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

DVWA靶场通关笔记-SQL Injection (Impossible级别)

目录

一、源码分析

1、index.php

2、impossible.php

二、SQL注入防范分析

1、Anti-CSRF 令牌

2、参数化查询

3、输入验证


本系列为通过《DVWA靶场通关笔记》的SQL Injection 关卡(low,medium,high,impossible共4关)渗透集合,通过对相应关卡源码的代码审计找到讲解渗透原理并进行渗透实践。本文为SQL Injection  impossible关卡的原理分析部分,讲解相对于low、medium和high级别,为何对其进行渗透测试是Impossible的。

一、源码分析

1、index.php

进入DVWA靶场SQL Injection源目录,找到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、impossible.php

进入DVWA靶场SQL Injection的source源码目录,找到impossible.php源码,分析其为何能让这一关卡名为不可能实现SQL注入渗透。

打开源码impossible.php,分析可知这段代码实现了用户信息查询功能,如下所示。

  • 验证用户登录状态:通过检查$_SESSION['id']判断用户是否已登录。
  • 查询用户信息:从数据库中查询当前登录用户的姓和名,并将结果以 HTML 形式展示。
  • 数据库操作流程:获取会话 ID 构建 SQL 查询 执行查询 解析结果 关闭连接。

详细注释后的impossible.php源码如下所示。

<?php// 检查是否通过GET方法提交了表单
if( isset( $_GET[ 'Submit' ] ) ) {// 验证CSRF令牌,防止跨站请求伪造攻击// 比较用户请求中的令牌与会话存储的令牌是否一致checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );// 从GET参数中获取用户ID$id = $_GET[ 'id' ];// 验证输入是否为数字(防止非数字类型的SQL注入)if(is_numeric( $id )) {// 准备SQL查询:从users表中查询指定ID的用户的名字和姓氏// 使用预处理语句防止SQL注入$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );// 将用户输入的ID绑定为整数类型参数// 这一步确保即使输入包含非数字字符也会被转换为整数$data->bindParam( ':id', $id, PDO::PARAM_INT );// 执行SQL查询$data->execute();// 获取查询结果的第一行$row = $data->fetch();// 确保查询只返回一行结果(防止越权访问)if( $data->rowCount() == 1 ) {// 提取查询结果中的名字和姓氏$first = $row[ 'first_name' ];$last  = $row[ 'last_name' ];// 输出用户信息(存在XSS风险,未对输出进行HTML转义)$html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";}}
}// 生成新的CSRF令牌并存储到会话中
generateSessionToken();?>

二、SQL注入防范分析

impossible.php 主要功能是处理用户提交的 ID 查询请求,通过验证 Anti-CSRF 令牌确保请求合法性,检查输入 ID 是否为数字,再使用 PDO 参数化查询从数据库中获取对应用户的姓名并反馈给用户,通过多重安全措施有效防范 SQL 注入等攻击。impossible.php 主要功能是处理用户提交的 ID 查询请求,通过验证 Anti-CSRF 令牌确保请求合法性,检查输入 ID 是否为数字,再使用 PDO 参数化查询从数据库中获取对应用户的姓名并反馈给用户,通过多重安全措施有效防范 SQL 注入等攻击。

  • 参数化查询(Prepared Statement):使用 PDO 预编译语句,分离 SQL 代码与用户输入数据。
  • 输入验证:限制输入为数字类型(is_numeric 检查)。
  • Anti-CSRF 令牌:防止跨站请求伪造,间接提升安全性。

1、Anti-CSRF 令牌

通过generateSessionToken生成随机令牌并存储在会话中,表单提交时包含该令牌字段,服务器端checkToken验证请求中的令牌与会话中存储的是否一致,不一致则拒绝请求。

// 验证令牌
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// 生成令牌
generateSessionToken();
// 表单中包含令牌字段
$page[ 'body' ] .= "			" . tokenField();

CSRF 攻击依赖盗用用户身份发起恶意请求,而 Anti-CSRF 令牌为每个请求附加随机且时效性的验证信息。攻击者攻击者难以获取合法令牌,即使构造恶意请求,因令牌不匹配也会被拦截,间接保障 SQL 查询的输入来源合法性,降低恶意注入请求的成功率。

2、参数化查询

通过 PDO 预编译语句将 SQL 结构与用户输入分离,先用:id作为占位符定义查询模板,再通过bindParam绑定参数并指定类型为整数,最后执行查询。即使输入包含恶意 SQL 片段,也只会被当作数据处理,无法改变查询逻辑

$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
$data->bindParam( ':id', $id, PDO::PARAM_INT );
$data->execute();

预编译阶段 SQL 语句结构已固定,数据库会将占位符视为数据而非可执行代码。绑定参数时强制类型为整数(PDO::PARAM_INT),进一步确保输入仅作为数值处理,从根本上避免用户输入被解析为 SQL 指令,彻底阻断断裂取数据库控制权的注入路径。

3、输入验证

获取用户输入的id后,通过is_numeric函数验证其是否为数字。只有当输入为数字时,才执行后续数据库操作;非数字输入会被直接拦截,不进入查询流程。

$id = $_GET[ 'id' ];
if(is_numeric( $id )) {// 执行数据库查询
}

SQL 注入常依赖字符串拼接注入恶意指令,而数字类型输入无法包含引号、关键字等注入要素。is_numeric从输入源头限制数据类型,过滤掉包含字母、符号的潜在恶意输入,减少注入攻击的可能性。即使参数化查询存在疏漏,该验证也能作为第二道防线拦截风险输入。

http://www.xdnf.cn/news/19538.html

相关文章:

  • [ Android Audio 篇 ] 高通平台 Android AudioRecord 多通道录音
  • LangChain中Prompt处理机制的技术架构与核心思想分析
  • STL库——stack/queue(类函数学习)
  • 切片语法[::-1]及其可用的类型
  • 基于STM32设计的智能家居控制系统(华为云IOT)_275
  • 2023年IEEE IOTJ SCI1区TOP,动态环境下无人机目标覆盖任务路径规划,深度解析+性能实测
  • KingbaseES JDBC 驱动详解:连接、配置与最佳实践
  • 介绍Ansible和实施Ansible PlayBook
  • pinia状态管理工具
  • Redis核心原理与Java应用实践
  • 洞悉边界:软件测试中边界值分析的艺术与科学
  • OpenJDK 17 解释器分发表与安全点表机制解析
  • 零基础入门AutoSar中的ARXML文件
  • 【Flask】测试平台开发,产品管理功能UI重构-第九篇
  • Kubernetes 服务发现与健康检查详解
  • 搭建卷积神经网络
  • 软考 系统架构设计师系列知识点之杂项集萃(139)
  • C++11语言(三)
  • Nginx实现P2P视频通话
  • codecombat(Ubuntu环境详细docker部署教程)
  • 项目-云备份
  • 面试 八股文 经典题目 - HTTPS部分(一)
  • Flink NettyBufferPool
  • 大模型时代:用Redis构建百亿级向量数据库方
  • EtherCAT主站IGH-- 41 -- IGH之sdo_request.h/c文件解析
  • Library cache lock常见案例分析(一)
  • Encoder编码器
  • 图像描述编辑器 (Image Caption Editor)
  • 极客时间AI 全栈开发实战营毕业总结(2025年8月31日)
  • 【Linux基础】深入理解计算机存储:GPT分区表详解