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

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.dtcms.com/a/359672.html

相关文章:

  • 【LeetCode - 每日1题】解数独
  • Tomcat 中部署 Web 应用
  • [灵动微电子 MM32BIN560CN MM32SPIN0280]读懂电机MCU 模拟输入运放放大
  • LangChain Prompt管理核心:PromptTemplate与ChatPromptTemplate全解析
  • 旦旦的农场打卡计划
  • 合约服务架构-OOP 方式
  • Linux系统比较两个​​已排序文件​​的实用工具之comm
  • R3:适用于 .NET 的新一代响应式扩展库,事件订阅流
  • HarmonyOS 应用开发:基于API 12及以上的新特性与实践
  • 视觉大模型与多模态理解
  • MySQL直接启动命令mysqld详解:从参数说明到故障排查
  • 容器seccomp配置文件在云服务器安全策略中的实施规范
  • 基于单片机老人防丢失防摔倒系统/老人健康状态检测系统
  • 神州数码VRRP 原理与配置篇
  • 【lua】二进制数据打包和解析
  • 使用 Python 自动化检查矢量面数据的拓扑错误(含导出/删除选项)
  • 【C++ 】STL详解(六)—手撸一个属于你的 list!
  • Lua基础知识精炼
  • vscode+EIDE+Clangd环境导入keil C51以及MDK工程
  • PortSwigger靶场之Stored XSS into HTML context with nothing encoded通关秘籍
  • AG32 Nano开发板的烧录与调试工具(二)
  • LabVIEW 瀑布图与游标操作
  • Python人工智能机器学习汇总
  • MySQL 常用语法
  • CTFshow系列——命令执行web69-72
  • 贝叶斯分类(Bayes Classify)
  • 【嵌入式DIY实例】-空中鼠标
  • Ubuntu安装NVIDIA显卡驱动
  • C#基础(③CMD进程)
  • 【C2000】C2000的国产替代现状与技术关键路径