首页 / 资讯中心 / 文章详情

文件上传绕过实战:从日志包含到RCE的完整攻击链分析

文件上传绕过实战:从日志包含到RCE的完整攻击链分析 ★ FEATURED ARTICLE
1. 从能上传到能利用这道题真正考的是什么先说结论这道CTF题作业2最坑人的地方恰恰在于它看起来太简单了。很多人一看到文件上传脑子里立刻蹦出三个字——马呢然后就开始往表单里塞一句话木马、改Content-Type、试后缀名折腾半天却拿不到flag。我最初接手这道题时也犯了同样的毛病。花了一晚上把常见的绕过手法轮了一遍大小写、双写后缀、加空格、加点、%00截断、图片马……结果全部吃瘪。后来冷静下来重新读题才发现自己完全走偏了——题目描述里根本没说上传一句话木马而是给了几个看起来八竿子打不着的线索词比如日志session临时目录。这几个词一出来整道题的思路就该立刻切换。这道题的核心考点其实是一个在网络攻防里经常被忽略、但真实业务里非常致命的问题当上传点本身百毒不侵时能不能换一个角度通过文件上传去污染服务端其他组件从而间接达成RCE远程代码执行换句话说上传点只是入口真正的战场在服务端如何处理我们传上去的内容、如何存储、如何回显、以及哪些本来不该被当成代码的东西被当成了代码。这篇文章我会把这道CTF 文件上传与其它作业2从读题、探测、绕过、利用到复盘完整拆给你看。不仅还原每一步操作还会把每步背后的判断逻辑讲清楚。文章面向的是有一定Web安全基础、想从会套模板进阶到会分析的读者如果你是纯新手前两章的思路部分请多看几遍比直接抄exp有价值得多。2. 第一轮探测先别急着上传把敌人的长相摸清楚2.1 从题目描述和附件里提取线索大多数CTF文件上传题题目描述都会光明正大地漏点东西。这道题也不例外只是因为夹杂了和 其他 作业2这种字样一开始让人摸不着头脑。我建议把所有线索词列出来不要放过任何一个关键字文件上传说明入口是上传功能大概率存在一个网页表单。其他作业2这个看起来很乱的词实际暗示题目不止一个考点可能存在需要结合的其他模块比如任意文件读取、日志包含、目录穿越等。关键词日志、session、临时目录这些属于典型的服务端隐藏组件线索。在真实渗透里攻击面往往不在主业务逻辑上而在这类辅助组件上。如果你拿到的题目环境还附带了源码文件很多这类作业会附带一个zip那更要优先看源码而不是急着开Burp。源码能告诉你上传目录在哪、过滤规则是什么、文件重命名规则、是否存在白名单、有没有include函数、日志路径是否可控。没有源码的话就用第二步的纯黑盒探测。2.2 黑盒信息收集确认Web容器、语言与上传逻辑在没有源码的情况下我的探测顺序是这样打开上传页面F12看表单结构记录name、action、enctype。上传一个无害的txt文件观察返回信息是否提示后缀不允许、大小超限、还是上传成功。访问上传后的文件路径看能否直接解析。故意构造一些畸形请求观察响应头的Server字段、X-Powered-By字段。这一步我拿到了关键信息环境是PHP Nginx上传的txt能访问但无法通过直接访问的方式触发代码执行。再加上题目线索里出现日志和session我基本可以锁定攻击链路是上传文件 - 文件内容被写入某个服务端可读取的文本文件日志/session/临时文件- 通过文件包含或条件竞争让该文本被PHP解析 - RCE。这里有个新手容易忽略的原则上传点只是投递通道能不能执行取决于服务端最终怎么用这个文件。判断一个上传点是否存在可利用价值不要只盯着我能不能传php而是要看我能不能把恶意内容送到服务端某个会被include或eval的位置。2.3 判断过滤规则黑白名单与内容校验的分水岭上传题说到底是过滤规则与绕过技巧的博弈。过滤规则通常分三类后缀名黑名单拦截php、php3、phtml等但可能漏掉pht、php5、Php、phP。后缀名白名单只允许jpg、png、gif这种一般得走文件包含或解析漏洞。内容校验检查文件头如GIF89a、MIME类型、甚至调用getimagesize。我测试的结果是后端采用白名单只允许jpg、png、gif同时文件头也校验了。这意味着常规上传可执行文件这条路彻底堵死。但注意它没有ban掉#、?、空格这些在URL解析里可能产生歧义的字符——这就是后文要利用的缝隙。提示判断出白名单后不要沮丧这是好事。白名单往往意味着过滤逻辑简单攻击面可以转向服务端如何处理白名单文件比如图片马结合文件包含、上传目录解析规则、POST包里的额外字段。3. 上传绕过实验把白名单逼到极限3.1 常规后缀绕过逐一测试与其失效原因很多教程喜欢列一串后缀绕过路径php、php2、php3、php4、php5、php7、pht、phtml、phar、phps……但我在本题实测全部被拦截。原因很简单服务端的拦截方式是后缀名白名单不在名单内的一律拒绝黑名单那套绕过手法自然无效。另外我还试了双写扩展名pphphp、.php.jpg、加空格、加点、加::data流、%00截断PHP 5.x的老玩法也都无效。原因分两类加空格/加点/双写在白名单判断下会被一刀切最终的后缀解析不是jpg/png/gif就拒绝。%00截断需要Web容器和PHP版本都够老现代环境默认安全模式开启废弃了这种玩法。这一轮虽然全失败但收获很大我确认了过滤是基于最后的后缀名是否在白名单内的严格判断。从攻防角度看这就意味着上传环节本身没有解析漏洞可钻必须寻找上传之外的辅助点。3.2 图片马与文件头校验的对抗既然后缀绕不过那就传jpg内容写PHP代码走文件包含路线。这类图片马的核心是文件的扩展名和MIME校验能通过但内容被人为塞了PHP代码。 因为服务端只是用getimagesize或文件头检查并不会真正去验证像素数据所以代码可以藏在图片末尾。我构造了最经典的方式先写一个1x1像素的PNG文件头再把?php eval($_POST[x]);?追加到文件末尾。上传后程序提示成功访问这个jpg文件浏览器直接当图片渲染没有任何异常。到现在为止一切都很平静。真正的转折发生在下一步——我尝试去触发服务端对这个jpg的内容解析。3.3 换个思路上传不是终点而是污染源普通的文件包含题会直接给你一个?pagexx之类的参数让你包含上传的jpg。但本题没有这种明显的include入口。于是我开始围绕题目里的日志、session线索做文章。这里分享一个实战判断法把目标想象成一个真实业务系统。系统每天会产生大量日志、session文件、缓存文件这些文件本质上是服务端写入的文本文件。如果我能把攻击代码注入到这些文本文件中再想办法让PHP去包含它们不就和包含图片马一样吗所以核心问题变成两个如何让我的恶意PHP代码进入某个服务端可写的文件如何触发包含针对问题1通常有三个入口User-Agent等请求头写入日志、Session内容写入session文件、上传文件名写入日志/临时目录。我用Burp重放了上传请求修改User-Agent字段为?php phpinfo();?然后去访问日志文件路径。如果日志开启且可读可包含这发就能直接看到phpinfo输出。日志路径通常需要猜常见位置有/var/log/nginx/access.log、/var/log/apache2/access.log、/tmp/access.log。本题环境在尝试/var/log/nginx/access.log时成功读到了页面说明日志文件可通过URL访问并被PHP解析。到这一步整道题的攻击链已经闭环。提示日志包含这种方式在生产环境里也非常常见。日志文件在真实攻击中是最容易利用的免费写文件点而且大部分时候日志功能是默认开启的。4. 核心利用链从日志污染到拿到flag4.1 为什么日志和session文件会变成代码执行点先解释原理这是理解本题的关键。Nginx的access.log会把每个请求的Method、URI、User-Agent、Referer等原样记录下来。这些字段由客户端也就是我完全控制。如果我在User-Agent里塞一段?php ... ?服务端不会对日志内容做任何转义或过滤直接落盘。 之后如果存在一个include函数能读到这个日志文件那么日志内容就会被当成PHP代码来执行。所以利用条件有三个日志文件可被Web服务读取。存在文件包含逻辑可能是file_get_contentseval也可能是include。日志写入和包含访问路径都可控。Session同理PHP默认把session序列化后存到/tmp/sess_sessionid。如果我能控制session中的某个字段比如用户名、昵称、数据内容写入?php ... ?再通过包含session文件来触发执行。这比日志包含更隐蔽但需要能控制session内容而且session文件的路径通常需要猜测。4.2 实操注入User-Agent并触发日志包含我按顺序做了以下操作先访问一个不存在的路径确认日志确实在记录然后找到日志文件路径/var/log/nginx/access.log。用Burp发送一个GET请求把User-Agent改为?php echo md5(test);?。再请求/var/log/nginx/access.log如果页面回显了MD5字符串说明日志被成功解析。我这里上手直接写了一个完整一句话马?php eval($_POST[cmd]);?然后访问日志文件确认无报错后用蚁剑/菜刀连接/var/log/nginx/access.log密码为cmd。不过这里有个非常容易被坑的点日志文件里含有大量原本的请求记录一行一行拼接起来可能造成PHP语法错误。比如某一行日志里有未闭合的括号或引号就会让整段PHP解析失败。解决办法是用日志中包含的某一行作为闭合边界——比如先注入?php eval($_POST[cmd]);?然后确保同一行里没有特殊字符干扰或者给一句话马加上??php前缀来强行闭合前面可能的php标签更稳妥的做法是先构造一个确定无干扰的请求例如专门用一个只有User-Agent的GET请求日志那条记录里只有固定格式不会带入非法符号。我最终的做法先发送一个GET /rce.php HTTP/1.1User-Agent为?php eval($_POST[cmd]);?然后再访问日志路径用蚁剑连接成功拿到RCE。4.3 利用获取的Webshell寻找flag遍历目录与文件读取技巧拿到RCE后找flag是最后一步。这一步常用命令包括find / -name *flag* 2/dev/null find / -name *.txt -exec grep -l flag {} \; 2/dev/null cat /flag cat /tmp/flag cat /var/www/html/flag.txt我当前环境里用find / -name *flag*直接定位到/var/www/html/flag.txtcat出来就是flag。如果flag被藏得更深比如根目录、docker环境变量、甚至隐藏在图片文件末尾需要用env、grep -r flag /、strings等手段逐步排查。这类找flag的收尾工作本身也值得练因为比赛就是这么设计的——run起来容易找到藏点才是真正区分度。4.4 另一个分支通过session文件路径执行日志这条路一旦走通session就只是换汤不换药。如果题目没有日志但给了可控session字段可以尝试找到session文件存储位置。常见路径/var/lib/php/sessions/sess_sessionid/tmp/sess_sessionid操作方式登录或构造一个请求让服务端把?php ... ?写进session某个字段然后包含对应sess文件。与日志相比session文件内容更干净触发成功率更高但前提是你得能预测session文件名。如果你已经通过其他漏洞读到了PHPSESSID或者能控制session_id这条路就很稳。注意当包含session文件时由于session文件内容里常有username|s:10:...这种序列化格式直接包含容易报语法错误。建议写入字段时不要把代码放在序列化数据的值里而是尝试覆盖整个session文件内容或者用不易破坏结构的注入方式。5. 把这道题放进更大的攻击面实际项目里文件上传还能怎么玩5.1 真实场景里文件上传漏洞的常见变体CTF里学会这一套放到真实渗透或实战中也不能只盯着日志和session。我梳理一下文件上传漏洞在真实系统里的常见衍生利用方式存储型XSS上传SVG文件内部嵌套JavaScript。现在很多头像、附件上传点允许SVGSVG一旦被浏览器加载就能执行脚本危害面很可能超出预期。存储型HTML注入上传HTML文件到同域路径诱导用户点击后可钓鱼、可盗Cookie、可利用同源策略操作其他页面。CSV注入上传包含Excel公式的CSV服务端展示或下载时如果用户用Excel打开就可能触发公式执行常用于钓鱼。恶意文档docx/xlsxOffice文档本质是zip可以在其内部XML里嵌入宏或外部实体如果上传点允许Office文件且后端有解析逻辑可能引发XXE。WebShell变种上传.phar、.htaccess、.user.ini等利用Apache/Nginx/PHP的配置特性间接执行代码。这类思路也很重要——特别是.htaccess可以给当前目录增加AddType配置直接把jpg当php解析。5.2 从上传点反推后端架构看见隐藏组件的能力这道题最有价值的训练点我认为不是某一条利用链而是从入口反推整体架构的能力。你会不会在看到上传功能时自动联想到文件存哪里Web可访问吗存储路径会不会拼接用户输入有没有路径穿越文件名如何处理是否可控制是否可包含路径分隔符文件内容是否会被二次读取/解析/展示有没有异步处理、解压、缩略图生成、AI审核等后处理流程日志/session/缓存/临时目录这些隐形文件是否可能成为投毒点如果每次测试上传点都能在脑子里过一遍这张检查清单你会比只会套用上传php改后缀绕过脚本的人高一个段位。这也是这道文件上传 与 其它 作业2真正想培养的能力——名字里的其他就是在提醒你别被困在单一漏洞类型里。6. 复现练习与避坑清单照着这个流程你可以少走一整晚弯路6.1 本地环境快速搭建建议如果你想自己复现、加深印象我用的是Docker搭的漏洞环境。大致步骤拉一个含Nginx PHP的镜像。写一个upload.php只允许jpg/png/gif上传校验文件头移动到uploads/目录。写一个包含入口比如page.php?file直接用include读文件仅限本地测试。确认日志路径/var/log/nginx/access.log可通过Web访问模拟低权限配置错误或题目故意敞开的路径。按上文流程先传jpg马再尝试日志包含最后用session包含做额外验证。这种环境搭建半小时内就能完成但跑通后的理解深度比看十篇writeup都值。6.2 常见踩坑点与调试技巧我在复现和实战中踩过不少坑列几个高频的日志解析失败日志行内含引号、括号、分号等符号破坏了PHP语法。解决先注入简单payload如phpinfo();看到回显再往一句话马方向构造构造时尽量在Payload前后增加空格和?闭合符。蚁剑连不上日志Webshell检查请求地址是否真的返回了正常HTTP 200且响应中无PHP警告输出如果日志文件过大可能导致连接超时建议清空日志或仅包含特定路径的请求。包含路径失效include参数可能限制了目录或文件后缀尝试php://filter/convert.base64-encode/resource...等伪协议绕过前提是PHP配置允许。session文件路径猜不到尝试用find / -name sess_*这类命令在获取RCE后反查比赛时也可以通过报错回显泄露路径。上传点根本没落地有些题目上传后端只是把文件内容写入数据库或消息队列这时攻击面又变了——可能需要往数据库内容里投毒再找一处把数据库内容渲染出来的功能。6.3 这道题给你留下的能力清单最后我想把这道题背后值得沉淀的能力点明确化方便你之后迁移到新题目信息收集不只看页面还要看响应头、报错、附件源码。过滤规则要分类判断而不是盲目套绕过字典。攻击面不止上传点要顺着文件流转路径找服务端二次读取/包含/渲染的地方。日志、session、临时文件、缓存是几个随手可用的免费写文件入口。拿到RCE后找flag要有自己的命令套路避免手忙脚乱。我个人在实际练习里有个习惯每做一道上传题就会写一份入口-流转-触发点三段式笔记把上传文件之后的每条可能路径都画出来——上传文件被存到哪、哪里在用它、用什么方式用它。这个笔记积累多了以后再遇到陌生题第一反应就不是上传一个马试试而是先画数据流再定点打击。这道题做完之后我最大的体会是文件上传漏洞从来不是一个孤立的技术点它更像一把钥匙能不能打开门取决于你有没有找到门后面的锁芯。多从服务端会怎么处理这个文件的角度去想问题很多看似无解的上传题都会变得豁然开朗。
阅读完成 · 觉得有帮助?
咨询建站