概述 (Overview)
许多网站提供文件上传功能,例如用户上传头像、上传附件、导入数据等。当用户上传文件时,后端服务器通常会对文件进行一系列检查(如文件类型、扩展名、大小),然后可能进行重命名并存储到指定目录。
如果后端对上传文件的安全检查缺失或不够严格,攻击者就可能上传恶意的可执行文件(如WebShell,通常是一句话木马),并在服务器上执行该文件,从而获得服务器的控制权(即GetShell)。
利用条件 (Conditions)
- 存在文件上传的功能点。
- 应用程序允许上传动态脚本文件(如
.php,.jsp,.asp,.aspx)或可以通过其他方式(如解析漏洞)使上传的文件被当作脚本执行。 - 上传文件的存储目录具有Web服务器的执行权限。
- 攻击者能够通过URL访问到上传的恶意脚本文件。
上传检测流程与绕过点 (Upload Detection Process & Bypass Points)
一个完整的文件上传流程可能涉及多个环节的检测:
- 前端提交 (Client-Side):
- 检测: JavaScript检测(检查文件扩展名、MIME类型)、Flash AS检测(旧)。
- 绕过点: 可以通过修改前端JS代码、禁用JS、或使用代理工具拦截修改HTTP请求绕过。
- 数据传输 (Data Transmission):
- 检测: WAF(Web应用防火墙)、IPS(入侵防御系统)可能拦截包含恶意特征(如已知WebShell代码、危险扩展名)的请求。
- 绕过点: 编码、混淆Payload、分块传输、利用协议特性等。
- 后端处理 (Server-Side):
- 检测:
- 扩展名检测 (Extension Check): 黑名单(禁止
.php等)、白名单(只允许.jpg,.png等)。 - MIME类型检测 (MIME Type Check): 检查HTTP请求头中的
Content-Type字段。 - 文件头检测 (File Header/Magic Number Check): 检查文件开头的几个字节是否符合特定文件类型的标识。
- 文件内容检测 (Content Inspection): 检查文件内容是否包含恶意代码特征(如
eval,system等函数)。 - 文件结构/图像校验 (Image Validation): 调用图像处理库(如PHP GD库)检查文件是否为有效图像。
- 扩展名检测 (Extension Check): 黑名单(禁止
- 绕过点: 最常见的绕过发生在此阶段,方法多样,见下文。
- 检测:
- 写入文件系统 (File System Write):
- 处理: 文件重命名(可能基于时间戳、随机数、用户ID等,使预测文件名困难)、存储到特定目录。
- 检测: 服务器上的杀毒软件可能查杀恶意文件。
- 绕过点: 如果重命名规则可预测或存在缺陷,仍可能找到文件。免杀技术绕过杀软。
- 访问文件 (File Access):
- 限制: 上传目录可能没有执行权限(Web服务器配置)、上传后的文件名未知、目录禁止Web访问。
- 绕过点: 利用解析漏洞、找到泄露文件名的途径、利用目录穿越将文件存到可执行目录。
绕过方法 (Bypass Techniques)
客户端检测绕过 (Bypassing Client-Side Checks)
- 原理: 客户端检测(主要是JavaScript)仅在用户浏览器中执行,容易被绕过。
- 方法:
- 禁用JavaScript: 在浏览器中临时禁用JavaScript。
- 修改前端代码: 使用浏览器开发者工具,找到并删除或修改执行文件检查的JavaScript代码(如
onchange,onsubmit事件中的校验函数)。 - 抓包改包 (通用方法):
- 先上传一个扩展名符合要求的文件(如
.jpg)。 - 使用代理工具(如 Burp Suite)拦截HTTP请求。
- 修改请求中的文件名(
filename="shell.php")和可能的Content-Type。 - 发送修改后的请求。
- 先上传一个扩展名符合要求的文件(如
APP端抓包 (Mobile App Traffic Interception)
- 设置代理:
- 在Burp Suite中设置代理监听
All interfaces。 - 在手机的Wi-Fi设置中,配置HTTP代理指向运行Burp的电脑IP和端口(如
192.168.1.100:8080)。 - 手机浏览器访问
http://<burp_ip>:<burp_port>(如http://192.168.1.100:8080) 下载并安装Burp的CA证书。 - Android: 可能需要将证书扩展名改为
.crt,然后在 设置 -> 安全 -> 加密与凭据 -> 从存储设备安装 (或类似路径) 安装证书。对于Android 7+,应用默认不信任用户安装的CA证书,可能需要Root设备并使用Magisk模块(如Move Certificates)或修改应用Manifest(如果能重新打包)。 - iOS: 安装描述文件后,需要在 设置 -> 通用 -> 关于本机 -> 证书信任设置 中手动信任该根证书。
- 在Burp Suite中设置代理监听
- 绕过证书固定 (Certificate Pinning):
- 如果APP使用了证书固定,直接设置代理会失败。
- 需要使用框架(如 Xposed + JustTrustMe, Frida)来Hook掉APP的证书校验逻辑。
- 模拟器配置 (Mumu为例):
- 可能需要使用
adb命令打开Wi-Fi设置界面:adb connect 127.0.0.1:7555 # 连接模拟器 (端口可能不同) adb shell am start -a android.settings.WIFI_SETTINGS # 打开WiFi设置
- 可能需要使用
服务器端检测绕过 (Bypassing Server-Side Checks)
-
MIME类型检测绕过:
- 原理: 服务器检查HTTP请求头中的
Content-Type字段。此字段由浏览器(或客户端)设置,可以被篡改。 - 方法: 抓包,将
Content-Type修改为服务器允许的类型(白名单),如image/jpeg,image/png。 - 常见白名单MIME类型:
image/jpeg,image/png,image/gif,text/plain,application/pdf,application/msword,application/zip。
- 原理: 服务器检查HTTP请求头中的
-
文件头检测绕过 (Magic Number Check):
- 原理: 服务器检查文件开头的几个字节(文件头/Magic Number)是否符合特定格式。
- 方法: 在WebShell代码前添加合法的文件头。
- 示例:
GIF89a<?php phpinfo(); ?>(保存为.php或配合解析漏洞)\xFF\xD8\xFF<?php phpinfo(); ?>(JPEG文件头,注意需要是原始字节)\x89PNG\r\n\x1a\n<?php phpinfo(); ?>(PNG文件头,注意需要是原始字节)
- 注意: 文件扩展名仍需能被解析为脚本,或结合解析漏洞。
-
文件结构/图像校验绕过:
- 原理: 服务器调用图像处理函数(如PHP的
getimagesize(),imagecreatefromgif())检查文件是否为有效的、完整的图像。简单添加文件头无法通过。 - 方法: 制作图片马 (Image Webshell)。将一个合法的图片文件与WebShell代码合并。
- Windows命令:
copy /b image.jpg + shell.php webshell.jpg - Linux命令:
cat image.jpg shell.php > webshell.jpg - 注意: 上传后的文件需要配合解析漏洞(如Apache
AddHandler配置错误)才能执行代码,或者用于包含漏洞(LFI)中。
- 原理: 服务器调用图像处理函数(如PHP的
-
恶意文件内容检测绕过 (Content Inspection):
- 原理: WAF或服务器端代码扫描文件内容,查找已知的WebShell特征码或危险函数(如
eval,system,assert,base64_decode,java.lang.Runtime)。 - 方法:
- 使用混淆/编码: 对WebShell代码进行编码(Base64, Hex, URL)、拆分、变形,绕过特征匹配。
- 使用免杀WebShell: 寻找或制作难以被检测到的WebShell。
- Weevely: 一个强大的隐蔽PHP Webshell生成工具 (Kali自带)。
- GitHub项目: 在GitHub搜索
webshell,但需自行判断安全性(可能包含后门)。
- 利用语言特性: 使用不常见的函数组合、回调函数、反序列化等方式执行命令。
- 原理: WAF或服务器端代码扫描文件内容,查找已知的WebShell特征码或危险函数(如
其他技巧 (Other Tricks)
- 多
filename属性绕过:- 场景: WAF可能只检查第一个
filename属性的扩展名。 - 方法: 抓包,在
Content-Disposition头中添加多个filename属性。
(具体效果依赖于服务器和WAF的解析方式)Content-Disposition: form-data; name="file"; filename="shell.jpg"; filename="shell.php"
- 场景: WAF可能只检查第一个
- 目录穿越 (Path Traversal):
- 场景: 上传目录可控(如通过参数指定子目录),且后端代码未正确处理
../。 - 方法: 抓包修改上传路径,尝试使用
../将文件上传到预期目录之外的可执行目录。 - 示例: 正常上传到
/uploads/avatar/,尝试修改路径为../../webshell/shell.php,可能将文件上传到/uploads/webshell/shell.php。
- 场景: 上传目录可控(如通过参数指定子目录),且后端代码未正确处理
- 可控扩展名检测类型:
- 场景: 允许上传的扩展名列表由配置或参数控制。
- 方法:
- 后台配置: 如果获得后台权限,直接修改允许上传的扩展名列表,添加
.php等。 - 前端参数: 如果允许的类型在前端(如隐藏字段)或请求参数中传递,修改该参数值。
- 后台配置: 如果获得后台权限,直接修改允许上传的扩展名列表,添加
常见解析漏洞 (Common Parsing Vulnerabilities)
利用Web服务器或语言解释器的解析缺陷,使非预期扩展名的文件被当作脚本执行。
-
IIS 5.x/6.0 解析漏洞:
- 分号文件名 (
.asp;.jpg): 服务器将;后面的内容视为路径参数,文件shell.asp;.jpg会被当作shell.asp执行。 - 目录名 (
/shell.asp/): 名为shell.asp的目录下的所有文件(无论扩展名)都会被当作ASP脚本执行。
- 分号文件名 (
-
Apache 解析漏洞 (配置错误):
- 多后缀解析: 从右向左解析,直到遇到认识的扩展名。如果
httpd.conf中有类似AddHandler application/x-httpd-php .php的配置,那么shell.php.jpg文件会被当作shell.php执行。 .htaccess文件: 如果允许上传.htaccess文件,可以在其中添加AddType application/x-httpd-php .jpg使所有.jpg文件被当作PHP执行,或使用<FilesMatch>指令。
- 多后缀解析: 从右向左解析,直到遇到认识的扩展名。如果
-
Nginx 解析漏洞:
- PHP CGI 路径修复 (
cgi.fix_pathinfo): 当PHP配置cgi.fix_pathinfo=1(默认值) 时,Nginx + PHP-FPM 环境下访问http://site.com/shell.jpg/xxx.php,如果/shell.jpg/xxx.php不存在,PHP会尝试将/shell.jpg作为PHP文件执行。需要Nginx配置将.php请求转发给PHP-FPM。 - 空字节 (
%00) 截断 (旧版本 Nginx < 0.8.41 + PHP < 5.3.4): 访问http://site.com/shell.jpg%00.php可能导致shell.jpg被当作PHP执行。 - Nginx 文件名逻辑漏洞 (CVE-2013-4547): 影响版本 Nginx 0.8.41 - 1.4.3 / 1.5.0 - 1.5.7。上传带空格的文件名
shell.jpg(注意末尾空格),访问时请求shell.jpg \0.php(空格+空字节+.php,需URL编码),可能导致shell.jpg文件被当作PHP执行。
- PHP CGI 路径修复 (
-
Apache 路径穿越与RCE (特定版本):
- CVE-2021-41773 (Apache 2.4.49): 路径穿越漏洞,可读取Web目录外文件。如果启用了CGI,可能导致远程代码执行。
- CVE-2021-42013 (Apache 2.4.50): 对上一个漏洞的不完整修复,仍然存在路径穿越。
- 利用: 构造类似
/.%2e/.%2e/.%2e/etc/passwd的URL进行目录穿越。
高级绕过技巧 (Advanced Bypass Techniques)
-
二次渲染/重绘图绕过:
- 场景: 应用程序上传图片后,会调用GD库等图像处理库进行缩放、裁剪或加水印等操作(二次渲染),这通常会破坏嵌入在图片数据中的简单WebShell。
- 方法:
- 上传一张正常图片,获取被服务器处理(渲染)后的图片。
- 比较处理前后的图片二进制数据,找到未被渲染过程改变的数据区域。
- 将WebShell代码精确地插入到这些“稳定”区域。
- 上传修改后的图片。由于WebShell在稳定区,二次渲染后代码可能仍然存活。
- 工具: 有一些脚本尝试自动化这个过程,如 Bypass-PHP-GD-Process-To-RCE。
-
phpinfo()与 LFI 联合利用 (PHP Multipart/form-data 临时文件):- 场景: 目标存在本地文件包含漏洞 (LFI),并且能访问
phpinfo()页面,但不知道上传文件的绝对路径或WebShell被查杀。 - 原理: PHP处理
multipart/form-data类型(文件上传)的请求时,会将上传的文件内容保存到一个临时文件中(如/tmp/phpXXXXXX)。这个临时文件名和路径会显示在phpinfo()页面的$_FILES变量信息中。脚本执行完毕后,临时文件会被删除。 - 方法 (条件竞争):
- 构造一个包含文件上传(上传一个简单的PHP代码文件)和触发
phpinfo()的请求。 - 通过发送大量数据(填充请求体)或并发请求等方式,尝试延长PHP脚本的执行时间,或使
phpinfo()输出变慢(流式输出)。 - 在发送请求的同时,快速、并发地发送LFI请求,尝试包含
phpinfo()中泄露的临时文件路径。 - 如果在临时文件被删除前成功包含了它,就能执行上传的PHP代码。
- 构造一个包含文件上传(上传一个简单的PHP代码文件)和触发
- 工具: 有现成的脚本可以帮助实现这种条件竞争攻击,如 LFI Suite 或特定 PoC 脚本。
- 场景: 目标存在本地文件包含漏洞 (LFI),并且能访问
-
在线解压缩功能漏洞利用:
- 场景: 网站允许上传
.zip,.rar等压缩包,并在服务器端自动解压。 - 方法:
- 直接打包WebShell: 将WebShell文件放入压缩包上传。
- 目录穿越: 在压缩包内创建包含
../的路径,尝试将文件解压到Web目录或其他敏感位置。 (需要解压工具支持或存在漏洞) - 软链接/符号链接: 在压缩包中包含指向服务器敏感文件(如
/etc/passwd)或目录(如/)的软链接。如果服务器解压时遵循链接(通常不安全配置),可能读取或覆盖文件。 - Zip Slip 漏洞: 一种特殊的目录穿越,利用解压库处理包含
../文件名的缺陷。 - 绕过内容检测: 如果服务器解压后会检查文件内容,可以尝试将WebShell放在深层目录结构中,或使用加密压缩包(如果支持并知道密码处理方式)。
- 场景: 网站允许上传
防御策略 (Defense Strategies)
- 使用白名单验证扩展名: 仅允许上传已知安全的文件类型(如
.jpg,.png,.pdf,.docx),拒绝其他所有类型。避免使用黑名单。 - 严格检查MIME类型: 检查
Content-Type,但不能单独依赖此项(可伪造)。应结合扩展名检查。 - 文件内容检测:
- 图像文件: 使用图像处理库(如PHP GD, ImageMagick)尝试打开并重新保存图片。无效图片或包含恶意代码的图片通常会导致处理失败或代码被破坏。
- 扫描恶意特征: 使用服务器端杀毒软件或专门的WebShell扫描工具检查文件内容。
- 安全重命名:
- 对上传的文件使用随机生成的、不可预测的文件名(如UUID)存储,并去掉原始扩展名或强制使用安全扩展名(如
.dat)。 - 在数据库中记录原始文件名与随机文件名、真实文件类型的映射关系。
- 对上传的文件使用随机生成的、不可预测的文件名(如UUID)存储,并去掉原始扩展名或强制使用安全扩展名(如
- 隔离存储:
- 将上传文件存储在Web根目录之外的、不可直接通过URL访问的独立目录。
- 如果需要Web访问,通过后端脚本读取文件内容并设置正确的
Content-Type输出,而不是直接链接到文件。
- 设置目录权限: 确保上传文件存储目录没有执行权限(移除Web服务器的脚本执行权限)。
- 限制文件大小: 对上传文件的大小进行合理限制。
- WAF/RASP: 使用Web应用防火墙或运行时应用自我保护(RASP)技术,帮助检测和阻止已知的上传攻击。
- 定期更新: 及时更新Web服务器、PHP/Java等语言环境、以及使用的第三方库,修复已知的解析漏洞和安全缺陷。
- 安全配置: 避免不安全的服务器配置(如Apache的
AddHandler滥用,Nginx的cgi.fix_pathinfo问题)。
1628

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



