资讯动态

ACTF2020新生赛Upload题:文件上传绕过与蚁剑连接实战

发布时间:2026/9/10 8:49:49 来源:尧图企业网站定制
先说下这道题的背景。ACTF2020新生赛是给刚接触CTF不久的选手准备的一场入门级比赛Upload题是Web方向最经典的文件上传类型。对于刚入坑Web安全的人来说这道题的价值不在于知识点多深而在于它把文件上传漏洞从看文章理解原理变成了亲手打一遍的完整闭环。我第一次做这道题的时候卡了很久甚至一度卡在后端到底过滤了什么这个问题上。后来把上传文件名、Content-Type、文件头全部试了一遍才意识到这类题的套路其实是固定的先分析过滤规则再构造对应绕过方式最后用工具完成连接。这篇文章会以我实际做题的过程为主线把一句话木马构造、上传绕过思路、蚁剑连接的整套流程都过一遍同时把我在这个过程中踩过的坑和排查方法整理出来。文章更适合刚接触Web安全、准备入门CTF的读者。如果你还不会写一句话木马也不用担心看完第一部分你就能自己写出来并理解它为什么能工作。1. 题目认知从一道新生赛Upload题说起1.1 这道题到底考什么文件上传漏洞的考点看起来很集中应用允许用户上传文件但对上传内容没有做严格校验导致攻击者上传了可被服务器解析的脚本文件。一旦这类脚本在服务器上运行攻击者就能拿到一定权限后续无论是读文件、执行命令还是横向移动都建立在上传成功并解析成功这个前提上。不过在真实做题中你会发现这个前提没那么容易达成。出题人会在上传点后面加各种限制前端JavaScript校验、后端Content-Type检查、文件头检查、扩展名黑名单/白名单甚至还会对文件内容做关键字过滤。ACTF2020新生赛的这道Upload题虽然难度不高但它把最常见的过滤方式都集中在了这一道题里。练好它上传类的入门题目基本就掌握了大半。这道题没有考特别激进的利用方式不需要你研究CVE、不需要分析框架漏洞核心就是上传一个Webshell并用工具连接。上传一句话木马、用蚁剑连接是CTF里最标准的Webshell利用流程也是很多老手口中最简单的Web题的典型代表。我记得一道类似题目的环境通常是一个普通的上传页面可能还会带一个文件预览功能。从用户体验来看它就是一个允许上传图片或个人文件的小应用。但作为攻击者我们首先想到的不是我想传什么合规文件而是这个上传点能不能让我传一个能被解析的PHP文件。这个思维切换是很多新手从普通用户视角转向安全视角的第一步。1.2 一句话木马和蚁剑在题目里的定位先解释一个概念。一句话木马One-Line Web Shell指的就是代码量极小、功能却完整的后门脚本。以PHP为例最常见的写法是?php eval($_POST[a]);?这行代码表面上很简短但它完成的事情不小接收外部POST请求中名为a的参数然后把参数值交给eval函数执行。发送aphpinfo();服务器就会执行phpinfo()发送asystem(ls);服务器就会执行系统命令ls。从能执行任意PHP代码这个角度讲它已经是一个完整的Webshell了。但问题来了如果每次执行命令都要手动构造POST请求效率太低了。尤其是一个命令输出几百行结果时用浏览器或命令行工具肉眼去看体验很差。这时候蚁剑就派上用场了。蚁剑AntSword是目前CTF和渗透测试里最常用的Webshell管理工具之一。它做的事情可以理解成一个专门为Webshell打造的图形化终端你把Webshell的URL和连接密码填进去它就能帮你管理这个后门包括文件管理、虚拟终端、数据库管理等功能。用了蚁剑之后上传一句话木马相当于在服务器上装了一个远程控制台你可以像操作自己电脑一样查看文件、执行命令。所以这道题的完整链路是上传一句话木马 - 找到木马文件的URL - 在蚁剑里配置URL和密码 - 连接成功 - 在虚拟终端中查找flag文件。这五个步骤里难点在第二步绕过上传限制其他步骤只要熟练掌握基本不会出错。2. 核心原理解析文件上传漏洞为什么会出现2.1 上传功能的信任边界很多人第一次接触文件上传漏洞时会有一个疑惑为什么上传一个图片会变成执行代码问题就出在应用信任了不该信任的东西。正常情况下的上传流程是用户选择一个文件浏览器把文件内容发送到服务器服务器保存到一个指定的目录。如果服务器只关心文件能不能被保存下来而对这个文件被保存成什么类型、将来会不会被执行没有约束那就出了大问题。比如一个站点接受用户上传头像但它把文件直接保存在web目录下文件名和扩展名都沿用用户提交的。如果攻击者上传的是一个包含PHP代码的文件扩展名是.php服务器就会把它放在web目录中。当其他人访问这个文件的URL时服务器会把其中的PHP代码当作应用程序执行而不是当作静态资源返回。这样一来上传操作就从保存文件变成了在服务器上部署了一段可执行代码。我用一个生活类比来解释一下这个过程相当于房东允许租客往自己家搬箱子但不检查箱子里装的是什么。租客搬进来的箱子里藏了一个能自动运行的程序房东又把这个箱子放在了厨房可执行目录里。程序一运行可能就把整个房子翻了个底朝天。在做题时这个信任边界体现在哪几个位置呢大致有三个浏览器端前端JavaScript校验服务端接收文件时的类型检查Content-Type、文件头等服务端保存文件时的扩展名/目录策略这三个位置对应三种不同的绕过思路后面我会分别展开。2.2 一句话木马为什么能生效一句话木马能生效核心前提是服务器把上传的文件当作PHP代码来解析。这取决于两个条件第一文件上传到web目录下且能被外部通过URL访问到。如果上传的路径是用户不可预览的那攻击者就找不到触发点木马等于白传。这就是为什么上传后页面会回显文件路径或文件名这个信息在利用时要格外留意。第二文件中包含的PHP代码必须完整保留。有的应用会对文件内容做处理比如转义引号、过滤关键字、删除某些字符串。如果一句话木马里的eval或$_POST被过滤掉了代码就无法执行。一个经验总结一句话木马的写法不止一种不是因为写法花哨而是每种写法应对的过滤规则不同。比如有的环境把eval列入了黑名单你可以用assert有的环境禁止字母开头的函数你可以用可变函数有的环境对单引号敏感你可以换双引号。所以做题时如果发现传上去但连不上除了检查路径还要想想是不是代码本身被过滤了。PHP里常见的一句话木马变种有?php eval($_POST[a]);? ?php assert($_POST[a]);? ?php system($_POST[a]);? ?php $_POST[a]($_POST[b]);?其中第一种最常见第二个和第四个用于绕过部分函数黑名单。第三个严格说不是执行任意代码而是执行系统命令但在蚁剑里可以通过选择相应的连接方式来使用。2.3 蚁剑在解题中解决什么问题如果没有蚁剑利用一个Webshell的过程是这样的手工构造POST请求携带要执行的命令再从响应中提取结果。命令一多、结果一长你就会发现这个流程痛苦到不行。蚁剑在解题中的角色可以理解为把Webshell连接过程可视化、自动化。它内置了多种通讯协议和数据编码方式可以适配不同木马写法。在CTF题里我最常用的功能有三个。第一个是文件管理。连接成功后左边是目录树右边是文件列表你可以像用FTP客户端一样浏览服务器上的文件。做CTF时flag往往就是一个普通文件可能在根目录、可能在/flag、可能在某个隐藏目录里用文件管理器翻一遍就能找到。第二个是虚拟终端。它通过Webshell执行系统命令并在界面里模拟出一个终端的样子。你可以输入ls、cat /flag这类命令。如果Webshell执行命令受限虚拟终端就会报错或没有输出这时要回到木马本身去排查。第三个是插件系统。蚁剑有很多插件比如端口扫描、绕过disable_functions等。不过在新手赛的这道题里用不到太复杂的插件能连上、能列目录、能执行命令就够了。这里我想强调一点蚁剑不是黑客专用工具它是开源的安全测试工具在CTF、靶场练习、授权渗透测试中很常见。用它的前提是这是题目环境或者你有授权这一点在后续实战中一定要明确。好原理部分讲清楚后接下来进入实操环节。3. 实操过程从上传到拿flag的完整链路3.1 环境准备与信息收集先说一下我通常的做法。拿到一个CTF的Web题目第一步不是立刻上传木马而是先做信息收集。信息收集决定后面往哪个方向走尤其在上传题里至少要搞清楚三个问题。第一个问题上传点接受什么类型的文件页面有没有提示页面源代码里有没有线索有些题目会在前端代码里直接写出允许的扩展名列表这个信息非常有用。第二个问题上传成功后的文件存在哪个路径页面是否有回显如果没有回显看看是否有文件预览功能预览功能往往会暴露真实的存储路径。第三个问题后端到底是PHP、JSP还是其他语言这个可以通过响应头、页面后缀、报错信息来判断。以ACTF2020新生赛这道题为例打开靶场一般就是一个上传页面可能会有一个选择文件的按钮和一个上传按钮。我通常先上传一个正常的文本文件或者图片比如一个hello.txt看它返回什么。这一步是为了摸清规则不是为了拿flag。如果页面回显了上传成功并且给出了访问路径比如/uploads/xxx.png那你就可以分析路径结构了。如果上传失败观察错误信息是前端弹窗还是后端返回。这里有第一个实操技巧看到页面之后先按F12看源代码。有些题目的前端JavaScript直接限制了上传后缀这种限制只存在于浏览器端改包就能绕过。更简单的做法是直接把JS禁掉重试不过在后端也有校验的赛题中改包才是通用解。我平时做信息收集时会抓包看一眼POST请求的内容重点看Content-Type。这一项非常关键。有些后端校验只看上传请求包的Content-Type如果请求头里写的是application/octet-stream或者image/png它可能就直接放行或直接拦截。这比解析文件内容快得多也更容易被绕。3.2 构造一句话木马搞定信息收集后开始准备弹药——一句话木马。这道题是PHP环境所以我的首选是?php eval($_POST[cmd]);?这里的cmd是我自己起的参数名蚁剑连接时密码一栏就填cmd。参数名可以随便起但要注意参数名要在蚁剑配置里保持一致否则连接时会提示连接失败或返回空白。我的习惯是故意把一个明显的命令参数暴露出来便于蚁剑识别。有些木马会在代码里加上判断只有在收到预期参数时才会执行比如?php eval($_POST[pass]);?这种写法简洁明了。如果你担心太短被WAF规则匹配可以在前后补充一些干扰内容但在新生赛里一般不需要这么做。另外如果你想练得更细一点可以先构造一个phpinfo探针木马验证上传是否生效?php phpinfo();?先传这个文件如果访问URL能看到PHP信息页说明这个目录可以被外部访问、PHP解析正常接下来再把真正的Webshell传上去。这个先探路再上马的思路在新手期特别值得养成可以省下很多排查时间。3.3 绕过上传限制的三种情况上传限制到底限在哪一层直接决定了你要用什么方式绕。下面我按三种情况展开每一条都是实际做题中容易遇到的。情况一前端JavaScript校验如果你选择了一个.php文件页面上立刻弹出只允许上传图片之类的提示而且根本没有把请求发出去说明是前端JS在做限制。这时候有两种绕过方式。第一种是修改上传请求。用Burp Suite抓包把文件名改成1.php再观察请求是否正常发送。前端校验只拦你的点击操作不拦构造好的HTTP请求所以直接改包就能绕过。第二种是干脆绕开前端控制。在浏览器里禁用JavaScript或者用开发者工具删除负责校验的脚本标签刷新页面后再上传。这种方法在某些题目里也能成功但我更推荐学改包因为后端校验是更常见的场景改包是通吃的基础技能。情况二后端Content-Type校验把请求发给后端之后如果返回文件类型不正确之类的提示就要看Content-Type了。很多后端会检查POST请求中文件部分的Content-Type要求必须是image/jpeg、image/png或image/gif之一。比如说你用Burp抓包看到请求中的文件部分写着Content-Type: application/octet-stream把它改成Content-Type: image/png然后重新发送。注意这里要改的是multipart/form-data里具体文件的那个Content-Type字段不是整个请求头里的Content-Type。改完以后很多只检查Content-Type的后端就会放行。这也是新生赛里最常见的一种绕过方式。我当时做这道题第一次就是因为只改了请求头没改文件部分的Content-Type结果连绕三次都没成功。后来仔细一看才发现后端校验的就是文件块内部的类型字段。这个细节如果不注意很容易让你怀疑自己思路错了。情况三后端扩展名/内容校验如果Content-Type也改了还是在拦截那后端可能在检查扩展名或文件内容。扩展名检查一般有两种策略黑名单禁止上传.php、.asp、.jsp等危险后缀白名单只允许上传.jpg、.png、.gif等安全后缀黑名单的绕过方式比较多常见的有大小写绕过将.php改成.Php、.PHP适用于Windows服务器双重扩展名shell.php.jpg如果后端只检查最后一个后缀就会放行中间加特殊字符shell.php.、shell.php空格、shell.php%00可解析的其他后缀.phtml、.php3、.php5等白名单通常比较难绕但如果在代码里存在逻辑漏洞比如允许上传jpg但保存时拼接了文件名后缀之类的场景还是有机会的。不过新生赛一般不会白名单卡死多数是黑名单Content-Type的组合。内容校验主要看文件头。很多应用会检查文件的前几个字节是不是GIF89a、PNG、JPEG等图片头。这种情况下可以做一个图片马在图片文件末尾拼接PHP代码。执行的时候解析器会跳过图片内容执行后面的PHP代码。一个简单的构造方式是准备一个正常的1x1像素的GIF文件用十六进制编辑器或脚本在文件末尾追加一句话木马内容上传这个文件把后缀改成.php如果后端不检查扩展名或者保持图片后缀如果配合文件包含不过我后来做这道题时发现题目环境其实没有要求必须做图片马直接把一句话木马改一下扩展名就过了。这说明做题时先试最简单的路径每一步都做好记录不要上来就整复杂方案。很多新手容易犯的毛病就是一上来做图片马明明普通绕过就够了。3.4 用蚁剑建立会话上传成功后页面上通常会给出一个文件路径。如果题目没有回显路径可以尝试从常见路径去猜比如uploads目录、upload目录、files目录或者结合题目源码去分析。这道题我做完后上传的文件一般在/uploads/目录下URL类似http://靶场地址/uploads/shell.php接下来打开蚁剑。第一次使用蚁剑的人可能会被它的启动方式搞晕因为蚁剑本身是Electron应用加载器AntSword Loader负责加载源码目录。装好依赖后打开加载器选择源码目录就能启动。启动后界面比较简洁就是一个常规的图形化界面。连接Webshell的操作流程是右键点击数据管理区域选择添加数据在URL一栏填木马的完整地址http://目标地址/uploads/shell.php在密码一栏填一句话木马里的参数名比如cmd编码器先选择默认的base64类型选择PHP点击测试连接如果成功会有提示连接成功后双击这个会话就能进入管理界面。到这里你已经在服务器上拥有了一个可以执行PHP代码的入口。进入管理界面后我一般会先看文件管理功能。左边是目录树右边是文件列表。找flag的套路通常是先看根目录点击左侧的/浏览根目录下的文件寻找名称里带flag的文件比如flag、flag.txt、flag.php等。如果根目录没有再看常见敏感目录比如/tmp、/var/www/html。如果文件管理器找不到就切换到虚拟终端用命令搜索。比如Linux环境下可以执行find / -name flag* 2/dev/null这个命令会在整个文件系统里查找名字中带flag的文件把错误输出丢弃只显示可读的结果。找到后再执行cat命令读取内容cat /flag读完flag后把它提交到题目环境这道题就算完成了。整个过程看下来最核心的技术点其实就两个一个是上传绕过另一个是用工具管理Webshell。蚁剑只是让第二步变得高效真正决定你做不做得出来的是第一步。4. 常见问题与排查技巧实录4.1 文件传不上去怎么办这个问题出现频率最高。根据我踩过的坑把排查顺序列成一个速查表你按照顺序查一遍基本能定位到问题。现象可能原因排查/解决方向上传时页面直接弹窗提示前端JS校验抓包改请求或禁用JS后再试返回文件类型不正确Content-Type校验修改multipart中文件块的Content-Type为image/png返回文件格式不支持扩展名校验尝试大小写、双重后缀、可解析后缀上传成功但访问是下载而不是解析PHP解析未生效检查文件路径、确认扩展名在可解析列表上传成功但蚁剑连接失败代码被处理/函数被禁用换一句话木马写法检查phpinfo路径可用性这里我想特别强调一个容易犯的错改Content-Type时有的新手把整个请求头里的Content-Type改了但multipart里的文件块还是原来的类型。后端读取的是文件块内部的Content-Type所以改错位置等于没改。另外如果后端对扩展名做了黑名单过滤不要只试一次就放弃。这里有一个经验黑名单过滤往往会漏掉一些少见但可解析的后缀比如.phtml、.php3、.php5。在PHP运行环境里只要服务器配置了把对应后缀当作PHP来解析就可以用。建议多试几个后缀不要只死磕.php。4.2 蚁剑连接失败怎么排查连接失败是第二高频问题。我通常按照下面几个步骤排查。第一步确认木马文件真的存在。用浏览器直接访问上传后的URL如果返回的是404说明文件没在这个路径或者上传时文件被改名了。此时回到上传页面看回显的文件路径到底是什么。第二步确认PHP代码能被解析。访问木马URL时如果页面返回的是源码比如显示出了?php eval...说明服务器没有解析PHP代码而是把它当作文本返回了。这种情况通常是扩展名不在解析列表里建议换一种扩展名重新上传。第三步确认参数密码正确。蚁剑连接的密码填的是一句话木马里的参数名不是登录口令。如果你上传的是?php eval($_POST[cmd]);?密码就是cmd。如果参数不匹配蚁剑会提示连接失败或者返回空数据。第四步检查是不是函数被禁用。有些环境会禁用eval、assert等危险函数。如果eval被禁用你可以临时换一个不依赖eval的木马比如?php system($_POST[cmd]);?这种方式直接执行系统命令蚁剑连接时在连接类型里选择命令执行模式即可。不过要注意不同环境对函数的禁用情况不同多备几套木马写法总没坏处。还有一个容易被忽略的点上传到服务器后文件内容里可能会有一些隐藏字符或编码问题。如果你在自己电脑上编辑木马时用了带BOM的UTF-8编码PHP解析时会在文件开头多出几个不可见字符可能导致执行失败。解决方法是保存文件时选择无BOM的UTF-8编码或者用ASCII编码保存一句话木马。4.3 拿到shell之后flag在哪里这个问题看似简单但很多新手会在拿到shell后卡壳。因为不同题目放置flag的位置不一样有的在web目录下有的在根目录有的在环境变量里有的在数据库里。ACTF2020新生赛的这道题规格比较标准flag一般是文件形式放在服务器上。我的查找顺序是这样的。首先看文件管理器的根目录。点根目录后不要只看一层注意目录权限。如果某个目录无法访问说明当前Webshell的权限不够那就需要再用命令尝试提权或换个路径绕过。不过新生赛里权限通常给得比较足直接能读到。其次用命令查找。在虚拟终端里执行ls -la / find / -name *flag* 2/dev/null如果find命令不可用可以改用grep -r flag{ / 2/dev/null不过grep整个根目录会比较耗时可以先在常见的web目录里查比如/var/www/html、/tmp、/opt等。最后如果flag是base64编码或者其他编码读出来之后还需要解码提交但这类题目一般不会太复杂。读到内容后直接复制到题目提交框中注意不要多复制空行或隐藏字符。提交前可以用cat -A命令查看文件里是否有多余内容。就这道题而言我记得flag是放在根目录的flag文件里的算是最标准的放法。不过我不建议直接背flag放哪因为每个比赛都不一样关键是掌握用find搜索、用cat读取这个能力。5. 从这道题延伸出去的经验做完这道题之后我意识到一个问题很多新手打CTF容易陷入一个题一个套路的思维学会上传就只会上传碰到别的题就不会变通。其实文件上传漏洞的利用思路有很多可迁移的地方。首先是控制输入点的思路。任何允许用户输入内容、并能被保存在服务器上的功能都可能成为漏洞点。不只是上传文件还包括写日志、写配置、写入缓存等。当你拿到一个Web应用先梳理所有输入能落盘的位置再思考这些位置是否会影响后续解析这个思维比背绕过技巧重要得多。其次是工具只是效率放大器的认知。蚁剑再强大如果Webshell本身没上传成功它就只是个空壳。反过来如果你能手工用Burp或curl发送构造好的POST请求来验证Webshell那你理解工具的原理就会更深。我建议新手在能用蚁剑之前先用curl手动连一次Webshell确认流程再用工具。还有一个经验是做题要留记录。我每次打一道题都会在一个本地笔记里记下目标环境是什么、上传过滤了什么、试了哪些后缀、哪个后缀成功了、蚁剑的URL和密码是什么。这个过程看似繁琐但当你连续打多个比赛、面对多个环境时这些记录就是你最快的查找手册。尤其是碰到相似题目时翻到之前的记录直接复用思路能节省大量时间。我在实际解题过程中最深的感受是一道上传题做完不应该只记住我拿到了flag而应该沉淀出这个漏洞的判定点在哪、绕过方式为什么有效、工具连接的原理是什么。把这三件事想明白再做新的上传题你会发现它们之间只是换了层外壳内里的逻辑是通的。这种迁移能力比多刷一道题要值钱得多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价