upload-labs靶场实战:21种文件上传漏洞绕过技巧全解析
1. 靶场搭建与工具准备:你的第一个“黑客”实验室
如果你对网络安全感兴趣,想亲手试试那些听起来很酷的“文件上传漏洞”,但又不知道从何下手,那今天这篇文章就是为你准备的。咱们不搞那些虚头巴脑的理论,直接上手实战。我会带你从零开始,搭建一个完全属于你自己的、安全的漏洞实验环境,然后一步步攻克21种经典的防御姿势。
首先,你得有个“靶子”来练手。这里我们选择 upload-labs,一个在安全圈内非常经典的文件上传漏洞靶场。它用PHP编写,模拟了各种真实网站在上传功能上可能犯的错误。你不需要一台独立的服务器,在你自己电脑上就能跑起来。
第一步:准备“地基” 你需要一个能运行PHP的Web环境。最简单的方法就是安装一个集成软件包,比如 PHPStudy 或者 XAMPP。我习惯用PHPStudy,因为它对Windows用户特别友好,一键安装,自带Apache、MySQL和PHP。记得选择PHP 5.x的版本(比如5.4.45),因为有些古老的漏洞特性在新版本里已经被修复了,为了复现所有关卡,老版本环境更合适。
第二步:下载“靶场”
打开GitHub,搜索 c0ny1/upload-labs,把这个项目下载到本地。解压后,你会看到一个名为 upload-labs 的文件夹。把这个文件夹整个丢到你PHPStudy的 WWW 目录下。比如,我的路径是 D:\phpstudy_pro\WWW\upload-labs。
第三步:启动服务
打开PHPStudy,启动Apache和MySQL服务。然后在浏览器里访问 http://127.0.0.1/upload-labs。如果看到一个写着“文件上传漏洞练习平台”的页面,恭喜你,靶场搭建成功!
第四步:装备你的“武器库” 光有靶场不够,我们还需要趁手的工具来发起“攻击”(当然是针对我们自己搭建的靶场)。
- Burp Suite Community:这是我们的“拦截器”和“改装车间”。绝大部分的绕过操作都需要用它来拦截浏览器发送的HTTP请求,然后修改其中的数据。社区版免费,功能对于学习来说完全够用。记得配置好浏览器的代理(通常是127.0.0.1:8080),并安装Burp签发的CA证书,这样才能拦截HTTPS流量。
- 蚁剑(AntSword):这是我们的“后门连接器”。当我们成功上传了一个Webshell(一句话木马)文件后,就需要用蚁剑来连接它,从而在靶场上执行命令,模拟攻击者获取服务器权限的过程。它是一个图形化工具,比古老的“中国菜刀”更现代、更好用。
- 浏览器:推荐使用Firefox或Chrome,并安装好用于配合Burp Suite的代理插件,比如FoxyProxy,方便切换代理模式。
- 文本编辑器:用来编写我们的一句话木马文件。一句话木马本质上就是一个特殊的PHP文件,内容极其简单,比如:
<?php @eval($_POST['pass']);?>。这行代码的意思是,接收一个名为pass的POST参数,并将其中的内容当作PHP代码来执行。这就是我们获取Webshell的钥匙。
好了,实验室搭建完毕,工具也齐活了。别担心,这一切操作都在你自己的电脑上进行,绝对安全,也绝对合法。接下来,我们就正式进入闯关模式,看看那些看似牢固的文件上传检查,是如何被我们一一绕过的。
2. 前端到后端的初阶绕过:与检查机制“捉迷藏”
很多网站的上传功能会设置多层检查,我们从最外面一层开始。
2.1 绕过前端JavaScript验证(Pass-01)
这是最简单、也是最常见的一种防护。你选择了一个 shell.php 文件点击上传,页面立刻弹窗提示“只允许上传.jpg/.png/.gif格式!”。注意,这个弹窗出现时,你的文件其实根本没有离开你的浏览器,更没有发送到服务器。 这纯粹是前端JavaScript代码在“多管闲事”。
绕过方法简直像撕掉门口的告示一样直接:
- 先把你的
shell.php改名为shell.png。这下前端JS检查通过了,文件开始上传。 - 此时,立刻打开Burp Suite的代理拦截功能。你会看到一个HTTP请求正在被Burp捕获。
- 在这个请求里,找到
filename="shell.png"这一部分,把它改回filename="shell.php"。 - 点击“Forward”放行这个被修改过的请求。
原理与实战: 前端验证就像超市门口的保安,只凭你穿的衣服(文件名)判断能不能进。我们穿了件“png”马甲混过保安,进去之后再把马甲脱掉(Burp改包),恢复“php”的真身。服务器后端如果没有其他检查,就会乖乖收下这个PHP文件。上传成功后,用蚁剑连接 http://你的靶场地址/upload-labs/upload/shell.php,密码填你木马里设定的(比如上面例子里的 pass),就能成功获得Webshell。
2.2 伪造MIME类型(Pass-02)
过了第一关,第二关的页面可能没有弹窗了,但上传PHP文件还是会失败。查看页面源码或者用Burp观察响应,可能会提示“文件类型不正确”。这说明服务器端开始检查了,但它检查的是什么呢?是 Content-Type 这个HTTP头。
当你上传文件时,浏览器会告诉服务器:“我传的这个东西是什么类型”。对于图片,通常是 image/jpeg 或 image/png;对于PHP脚本,则是 application/octet-stream(二进制流)。第二关的服务器只认前面那几种图片类型。
绕过方法就是“说谎”:
- 正常上传你的
shell.php文件,并用Burp拦截请求。 - 在Burp的拦截视图里,找到
Content-Type: application/octet-stream这一行。 - 把它改成
Content-Type: image/jpeg。 - 放行请求。
原理与实战: 这关的检查者像个“形式主义者”,它不关心文件实际内容是什么,只认包装盒上的标签。我们给一个PHP文件贴上了“image/jpeg”的标签,它就以为这是个图片,爽快放行。同样,上传成功后用蚁剑连接即可。这种方法对付只做MIME类型检查的后端非常有效。
2.3 黑名单的漏网之鱼:特殊后缀(Pass-03)
从这一关开始,防御升级到了后端黑名单。服务器有一份“坏人名单”,上面写着 .php, .asp, .jsp 等危险后缀,上传这些文件直接拒绝。但这份名单可能不全。
绕过思路:寻找“别名”
Apache等Web服务器可以通过配置,将其他后缀的文件也当作PHP来解析。常见的“PHP别名”后缀有:.phtml, .php3, .php4, .php5, .pht, .phps 等。如果服务器配置了 AddType application/x-httpd-php .php .phtml .php3,那么 .phtml 文件就会被当作PHP执行。
实战操作:
- 将你的木马文件
shell.php重命名为shell.phtml。 - 直接上传。如果靶场环境配置了解析这些后缀,就会成功。
- 用蚁剑连接时,地址要相应改为
.../shell.phtml。
踩坑提醒: 这个能否成功,完全取决于服务器(靶场)的配置。upload-labs的Pass-03关卡模拟了这种配置环境,所以可以成功。但在真实渗透测试中,这需要你通过信息收集去猜测或验证目标服务器是否存在此类配置。
3. 黑名单绕过进阶:利用系统与协议特性
当黑名单看起来越来越全,我们就需要利用一些系统和协议层面的“特性”或“漏洞”来钻空子了。
3.1 掌控解析规则:.htaccess文件攻击(Pass-04)
这是Apache服务器特有的一种强大攻击方式。.htaccess 是一个分布式配置文件,它可以覆盖其所在目录及其子目录的Apache配置。如果我们能上传一个 .htaccess 文件,就能“命令”服务器:“把这个目录里所有.jpg文件都当成PHP来执行!”
实战步骤:
- 制作.htaccess文件:新建一个文本文件,改名为
.htaccess(注意前面有个点)。用记事本打开,写入一行代码:AddType application/x-httpd-php .jpg。这行代码的意思是,将.jpg后缀的文件解析为PHP。 - 上传.htaccess文件:在靶场页面,先上传这个
.htaccess文件。如果服务器没有禁止上传此类配置文件,通常会成功。 - 上传图片马:制作一个图片Webshell。用命令行
copy normal.jpg/b + shell.php/a shell_with_webshell.jpg(Windows)或者用文本编辑器在图片文件末尾追加PHP代码。这个文件实际内容是图片,但末尾藏了一句话木马。 - 触发执行:上传这个
shell_with_webshell.jpg文件。此时,由于.htaccess文件的作用,服务器会把这个“图片”当作PHP脚本来解析,执行隐藏在图片末尾的代码。访问这个图片的URL,就能看到代码执行效果。
原理深度: 这招相当于在敌人的军营里,偷偷修改了他们的武器使用手册,把“扫帚”的用途改成了“机枪”。只要手册(.htaccess)生效,你递过去一把看起来像扫帚的机枪(图片马),他们也会按机枪来用。防御这种攻击的方法就是在服务器端禁止上传 .htaccess 这类配置文件。
3.2 大小写、空格与点的游戏(Pass-05, 06, 07)
Windows系统有一个“特性”:它对文件名的大小写不敏感。shell.php, shell.PHP, shell.Php 在它看来是同一个文件。但很多用PHP写的检查逻辑,是大小写敏感的。
-
Pass-05 大小写绕过:如果黑名单里只有小写的
.php,那么上传shell.PHP就可能绕过检查。因为in_array(‘.PHP’, [‘.php‘])会返回false。在Burp里把filename改成shell.PHP即可。 -
Pass-06 空格绕过:有些检查函数在比较后缀名后,没有用
trim()函数去除文件名首尾的空格。你可以在Burp里将文件名改为shell.php(注意php后面有个空格)。当这个带空格的文件名被保存到Windows系统时,系统会自动去掉末尾的空格,最终存储为shell.php。 -
Pass-07 点号绕过:和空格类似,Windows系统也会自动去除文件名末尾的“.”。你可以上传
shell.php.。后端检查时,strrchr(‘shell.php.‘, ‘.’)取到的后缀是‘.‘,不在黑名单[‘.php‘]里,于是通过。保存到系统时,点被去除,文件变回shell.php。
核心思想: 这些方法都利用了 “检查逻辑” 和 “最终存储系统” 之间的差异。检查时是一个样子(如 .PHP, php , php.),存储时变成了另一个样子(.php)。这种差异就是安全漏洞。
3.3 Windows的“数据流”把戏:::$DATA绕过(Pass-08)
这是Windows NTFS文件系统的一个特性,叫“交替数据流”(Alternate Data Streams)。在文件名后加上 ::$DATA,Windows会将其视为文件的主数据流,但在保存时,::$DATA 及其之后的内容会被忽略。
操作很简单:
- 在Burp中,将上传的文件名改为
shell.php::$DATA。 - 服务器端的检查逻辑可能只匹配
.php,看到::$DATA觉得不是.php,就放行了。 - Windows系统在保存文件时,会忽略
::$DATA,最终在磁盘上创建的文件就是shell.php。
注意: 这个方法仅对Windows服务器有效。如果靶场运行在Linux上,这招就不灵了。
3.4 双写绕过(Pass-11)
这一关的过滤逻辑非常“耿直”:它发现文件名里有黑名单里的词(如php),就直接把它删掉,而且只删一次。
绕过方法: 既然你删一次,那我就给你两个,你删掉一个,还剩一个。
将文件名改为 shell.pphphp。过滤逻辑发现里面有 php,把它删掉,字符串变成了 shell.php,正好是我们想要的。
这种过滤方式在编写时显然考虑不周,但恰恰是这种“想当然”的逻辑,在早期的很多程序中真实存在。
4. 白名单与更精巧的绕过:截断、竞争与渲染
白名单机制(只允许.jpg, .png, .gif等)比黑名单严格得多。要绕过它,需要更精巧的技术。
4.1 截断攻击:让路径“戛然而止”(Pass-12, 13)
这是一种利用旧版本PHP字符串处理漏洞的攻击。核心是 空字符(%00,URL编码形式)。在C语言等中,空字符表示字符串结束。PHP在5.3.4之前的版本,在某些情况下也会把 %00 之后的字符截断。
场景:假设上传代码是这样处理路径的:$file_path = $_GET[‘save_path’] . ‘/’ . $file_name;。其中 save_path 我们从URL参数可控。
- 我们上传一个名为
shell.jpg的文件。 - 在Burp中,我们修改上传请求,或者构造一个GET参数,使得最终的保存路径变成:
upload/shell.php%00/20231011.jpg。 - 旧版本PHP在处理
shell.php%00/20231011.jpg时,遇到%00就认为字符串结束了,实际保存路径变成了upload/shell.php。后面白名单检查的.jpg被截断丢弃了。
实战要点:
- Pass-12 (GET型截断):参数在URL中,直接使用
%00。 - Pass-13 (POST型截断):参数在POST数据体中,
%00不会被自动解码。需要在Burp的Hex视图里,找到对应位置,将字符的16进制值改为00。 - 重要:这个漏洞在PHP >= 5.3.4 后已被修复。现在的靶场为了复现,通常需要特意配置低版本的PHP环境。
4.2 条件竞争:与时间赛跑(Pass-18)
这是一种非常经典的“竞态条件”漏洞。它的逻辑是:服务器先允许文件上传到临时目录,然后再去检查文件内容是否合法(比如是否是真正的图片),如果不合法就删除。
攻击窗口就出现在“上传完成”到“检查删除”之间这短短的几毫秒或几百毫秒里。
- 我们编写一个特殊的PHP木马,它一被访问,就会在服务器上生成一个永久的Webshell文件。例如:
<?php file_put_contents(‘shell.php‘, ‘<?php @eval($_POST[cmd]);?>‘); ?> - 我们利用Burp Suite的 Intruder 模块,以极快的速度(比如每秒数百次)重复发送上传这个木马文件的请求。
- 同时,我们用浏览器或脚本,以同样快的速度去访问那些可能已经上传成功的临时文件地址。
- 只要在某个瞬间,我们访问文件的速度快过了服务器删除它的速度,我们的木马就会被执行,从而在服务器上生成一个真正的
shell.php。
这个过程就像一场赌博,赌的就是“我访问到你”发生在“你删除我”之前。通过自动化工具发起海量请求,这个概率可以被大大提升。
4.3 图片马与二次渲染绕过(Pass-14, 15, 16, 17)
这是更高级的绕过,针对的是那些不仅检查后缀、MIME,还会检查文件内容的严格防御。
基础图片马:将PHP代码附加到一个正常图片文件的末尾。用 getimagesize() 或 exif_imagetype() 函数检查时,它能通过,因为文件头确实是合法的图片格式。但如果服务器只是简单地“包含”了这个图片文件(存在文件包含漏洞),附加的PHP代码就会被执行。
二次渲染绕过:这是最难的关卡之一。服务器不仅检查,还会对上传的图片进行“二次渲染”——即用GD库或ImageMagick等函数,将图片打开、再重新保存。这个过程会剥离所有非图片数据,普通的图片马会失效。
绕过二次渲染的思路:
- 研究渲染算法:你需要研究目标服务器使用的图片处理库(如GD库)对特定格式(GIF/PNG/JPG)的渲染细节。例如,GD库处理GIF时,可能会保留帧与帧之间的数据区。
- 制作特制图片马:找到一个图片,在二次渲染后,其某些数据块的位置和内容保持不变。将你的PHP代码精心编码后,插入到这些“不变”的数据区中。这需要对图片文件格式和库函数有很深的理解,通常需要借助专门的工具或脚本来生成。
- 上传验证:上传制作好的特制图片马,下载被服务器二次渲染后的图片,用16进制编辑器对比,确认你的代码是否幸存。
这个过程更像是在制作一个“数字寄生虫”,让它能寄生在图片的合法结构里,躲过系统的“清洗”流程。虽然难度高,但一旦成功,防御效果极佳的文件内容检查也会被穿透。
5. 防御之道:从攻击者视角构建安全
一口气看了这么多绕过技巧,是不是觉得文件上传功能处处是坑?没错,构建一个安全的文件上传功能,必须进行“纵深防御”。
- 使用白名单,而非黑名单:这是最重要的原则。只允许业务明确需要的后缀,如
.jpg,.png,.pdf。任何不在名单上的,一律拒绝。 - 文件内容检查:使用
getimagesize(),exif_imagetype()或更复杂的文件头检查,确保文件内容与其后缀匹配。但要注意,这可以被图片马绕过。 - 重命名文件:上传后,立即用随机字符串(如UUID)重命名文件,并保留原始后缀。这样即使攻击者上传了恶意文件,也无法直接访问或预测其路径。
$new_filename = md5(uniqid()) . ‘.‘ . $ext; - 设置正确的权限:上传目录应禁止脚本执行。在Apache中,可以在
.htaccess里设置php_flag engine off。将上传目录放到Web根目录之外,通过脚本代理访问,是更彻底的方法。 - 使用专用存储服务:对于大型应用,可以考虑使用OSS、COS等对象存储服务。它们通常提供了更完善的上传策略和安全检查。
- 扫描与监控:对上传的文件进行病毒/木马扫描。记录所有上传日志,监控异常访问模式(如一个图片文件被频繁以POST方式访问)。
upload-labs的21关,几乎涵盖了文件上传漏洞的所有经典场景。我建议你不要仅仅满足于“通关”,而是每过一关,都去仔细读一读靶场提供的源代码,理解它为什么会被绕过。然后思考,如果让你来修复这个漏洞,代码应该怎么写。只有这样,你才能从“知道怎么攻”真正进阶到“懂得怎么防”,成为一名合格的网络安全实践者。实战中遇到的情况可能更复杂,但万变不离其宗,理解这些核心原理和思维模式,就是你最有力的工具。
更多推荐


所有评论(0)