Web安全CTF六日刷题复盘:SQL注入、文件上传与命令执行实战

发布时间:2026/10/16 18:15:12
Web安全CTF六日刷题复盘:SQL注入、文件上传与命令执行实战 1. 从零开始为什么我要系统刷一遍Web安全基础题那段时间我正处在一个挺尴尬的阶段——单个知识点拎出来都能说个大概但真给我一个综合场景脑子里的思路就串不起来。比如看到登录框我知道可能有SQL注入但具体是盲注还是联合查询、闭合方式是什么、WAF绕不绕全靠现场碰运气。这种“知道但不会用”的状态比完全不懂还难受。后来我给自己定了个规矩连续六天每天至少啃两道Web方向的CTF基础题不追求数量但每道题必须把原理、利用链、失败尝试全部记录下来。这个系列就是那六天的完整复盘从9月14日到9月19日覆盖了SQL注入、文件上传、命令执行、目录遍历、弱类型比较、反序列化入门这几个Web安全最核心的基础模块。这篇文章适合谁看如果你刚接触Web安全刷题时经常卡在“知道漏洞名字但不知道怎么打”的阶段那这篇记录应该能帮你省不少弯路。我不会只贴Payload和Flag而是把每道题的判断依据、尝试顺序、踩坑过程都摊开讲。有经验的朋友也可以当个思路对照看看别人的解题节奏跟你有什么不同。需要提前说明的是以下所有题目环境均为本地搭建的模拟靶场涉及的工具和命令仅用于安全学习与防御研究请勿用于任何未经授权的场景。2. 整体刷题节奏与选题逻辑2.1 六天时间怎么分配我给自己定的节奏是每天一个主方向不贪多。具体安排是这样的日期主攻方向核心训练目标9.14SQL注入基础判断注入点、闭合方式、联合查询9.15文件上传前端绕过、MIME绕过、内容检测绕过9.16命令执行管道符、空格绕过、关键字过滤9.17目录遍历与信息泄露路径穿越、备份文件、源码泄露9.18弱类型与代码审计入门PHP弱比较、变量覆盖9.19综合复盘把前五天的方法串成检查清单这个顺序不是随便排的。SQL注入和文件上传是Web方向出现频率最高的两类题先啃它们能快速建立信心。命令执行和目录遍历属于“辅助技能”很多综合题里会作为跳板出现。弱类型比较和代码审计则是为了补上PHP语言层面的坑不然遇到源码题只能干瞪眼。2.2 选题的三个原则我筛题的时候会刻意避开两类一是纯靠工具扫就能出的题二是需要大量前置知识但当前阶段用不上的题。具体原则是优先选有明确回显的题。比如联合查询注入你能直接看到数据库返回的内容这种反馈最直接适合建立“输入-输出”的直觉。优先选能手动完成的题。工具能跑出来当然好但手动构造Payload的过程才是真正长本事的地方。我前三天基本没用sqlmap全靠手注。优先选有源码或提示的题。黑盒题不是不能做但对新手来说有源码能让你把“现象”和“原因”对应起来学习效率高得多。这里有个小建议如果你刚开始刷题不要一上来就追求“一题多解”。先把一种最稳的解法练到肌肉记忆再去研究花式绕过。我见过太多人连联合查询的列数都数不明白就开始研究堆叠注入了结果两边都不扎实。3. SQL注入从判断闭合到联合查询的完整链路3.1 第一道题数字型注入的快速判断9月14日的第一道题是一个典型的数字型注入。页面很简单一个商品列表URL里带?id1。我当时的操作顺序是这样的第一步先测?id1页面报错。这说明单引号被带入了SQL语句但报错信息没有回显属于盲注的前兆。第二步测?id1 and 11和?id1 and 12前者正常返回后者返回空。到这里基本可以确定是数字型注入因为如果id被引号包裹and 11会被当成字符串的一部分不会影响查询结果。接下来是判断列数。我用的是order by法?id1 order by 3 -- ?id1 order by 4 --3的时候正常4的时候报错说明当前查询返回3列。然后就是联合查询?id-1 union select 1,2,3 --这里有个细节我把id设成了-1目的是让前面的查询返回空这样页面显示的就是union后面的内容。如果id1页面会优先显示第一条记录union的结果可能被挤掉。实操心得很多人卡在“为什么union查询没回显”这个问题上十有八九是没把前面的查询置空。记住一个口诀——联合查询要回显前面条件先失效。3.2 第二道题字符型注入与闭合方式第二道题跟第一道很像但?id1 and 11返回空?id1 and 11却正常。这说明id被单引号包裹了属于字符型注入。闭合方式就是单引号Payload要写成?id1 and 11 ?id1 and 12判断列数的时候也要注意闭合?id1 order by 3 --这里--的作用是注释掉后面的单引号在URL里代表空格。如果你直接写--有些环境会因为缺少空格而报错。字符型注入最容易踩的坑是闭合不完整。比如你写?id1 union select 1,2,3后面的单引号没注释掉SQL语句就变成了select * from table where id1 union select 1,2,3多出来的引号会导致语法错误。所以养成习惯只要用了单引号闭合后面一定跟注释符。3.3 第三道题布尔盲注的手工实现第三道题没有回显页面只返回“存在”或“不存在”。这就是典型的布尔盲注。手工盲注的核心思路是把问题拆成一个个是/否的判断通过页面的真假来推断数据。我当时的步骤是先判断数据库名长度?id1 and length(database())8 --页面返回“存在”说明数据库名长度是8。再逐字符猜数据库名?id1 and substr(database(),1,1)a --如果返回“存在”说明第一个字符是a。重复这个过程直到拼出完整的数据库名。这个过程非常枯燥但手工做一遍能让你彻底理解盲注的本质。我后来用Python写了个简单的脚本来自动化核心逻辑就是遍历字符集逐个位置判断。import requests url http://localhost/sqli.php?id1 and substr(database(),{pos},1){char} -- chars abcdefghijklmnopqrstuvwxyz0123456789_ result for pos in range(1, 9): for c in chars: r requests.get(url.format(pospos, charc)) if 存在 in r.text: result c break print(result)注意这个脚本只是演示盲注的自动化思路实际环境中请求频率过高可能触发防护机制。手工测试时建议加延时比如每请求一次sleep(0.5)。3.4 SQL注入部分的避坑清单问题现象可能原因解决方式加单引号不报错可能是数字型或双引号闭合测and 11和and 12union查询无回显前面查询未置空把id改成-1或0order by报错列数判断错误或注释符缺失从1开始逐列增加补上--盲注脚本跑不出结果字符集不全或大小写问题加入大写字母和特殊符号页面返回空白可能触发了WAF或语法错误检查Payload编码尝试大小写混合4. 文件上传从绕过前端到内容检测4.1 前端JS校验的绕过9月15日的第一道文件上传题页面只允许上传jpg和png。我第一反应是看前端源码果然有个checkFile()函数在拦截。这种前端校验是最容易绕的因为校验逻辑跑在浏览器里跟服务器没关系。绕过方式有三种禁用JS直接在浏览器设置里关掉JavaScript或者用开发者工具把onsubmit事件删掉。改后缀先把文件改成jpg上传时用Burp抓包把文件名改回php。构造请求直接用curl发POST请求跳过页面。我选的是第二种因为能顺便练一下抓包改包的手感。具体操作是把shell.php改名为shell.jpg选择上传Burp拦截后把filenameshell.jpg改成filenameshell.php放行。这里有个细节有些环境会检查Content-Type如果上传jpg但Content-Type是application/x-php也会被拦。所以改文件名的时候顺手把Content-Type改成image/jpeg。4.2 MIME类型检测的绕过第二道题比第一道严一点前端不拦了但服务器会检查Content-Type。如果传php文件Content-Type是application/x-php直接被拒。绕过方法很简单抓包把Content-Type: application/x-php改成Content-Type: image/png。服务器只看这个头不看文件内容所以能过。但这里有个坑改完Content-Type后文件内容还是PHP代码。如果服务器后续还会检查文件内容比如用getimagesize()那就过不了。所以这道题能过是因为它只检查了MIME类型。4.3 文件内容检测与图片马第三道题就狠了服务器用getimagesize()检查文件是不是真正的图片。这时候单纯的改后缀和Content-Type都没用因为getimagesize()会读取文件头判断是不是合法的图片格式。解决方案是图片马在一张正常的图片文件末尾追加PHP代码。这样文件头是图片格式getimagesize()能过但PHP代码也在里面。制作方法copy normal.jpg /b shell.php /a webshell.jpg这条命令的意思是把normal.jpg以二进制方式、shell.php以文本方式合并成webshell.jpg。合并后文件开头是JPEG的文件头末尾是PHP代码。但图片马有个问题直接访问图片PHP代码不会执行。需要配合文件包含漏洞比如?fileupload/webshell.jpg才能触发PHP解析。实操心得图片马的精髓在于“文件头合法内容夹带”。我试过用十六进制编辑器手动在图片末尾加代码效果一样但用命令行更快。另外有些环境会检查文件末尾所以最好在PHP代码前后加一些垃圾字符避免被特征匹配。4.4 文件上传的防御思路刷完这三道题我反过来想了一下防御方该怎么拦前端校验只能防君子不能防抓包所以服务端必须重新校验。MIME类型可以伪造所以不能只信Content-Type。getimagesize()能拦图片马但如果配合文件包含依然危险。最稳的做法是白名单重命名禁止执行只允许特定后缀上传后重命名为随机字符串并且上传目录不给执行权限。这个思路后来在我做代码审计的时候帮了大忙看到文件上传功能第一反应就是查这三条有没有做到。5. 命令执行管道符与空格绕过的实战5.1 基础命令执行与管道符9月16日的命令执行题页面有个输入框输入IP后返回ping的结果。这种题一看就是ping命令拼接试一下127.0.0.1; whoami果然返回了当前用户。命令执行常用的连接符有符号作用示例;顺序执行前一个失败也继续127.0.0.1; whoami|管道前一个的输出作为后一个的输入127.0.0.1 | whoami||前一个失败才执行后一个127.0.0.1 || whoami前一个成功才执行后一个127.0.0.1 whoami反引号命令替换127.0.0.1 whoami我一般先用;试因为它的容错性最好。如果;被过滤再试|或||。5.2 空格被过滤的绕过方式第二道题把空格过滤了127.0.0.1; whoami直接报错。这时候有几种绕过方式用$IFS代替空格127.0.0.1;cat$IFS/etc/passwd用Tab代替空格在Burp里把空格改成%09用{cat,flag}形式127.0.0.1;{cat,flag.txt}用重定向符127.0.0.1;catflag.txt我试了$IFS和{cat,flag}都能过。$IFS是Linux的内部字段分隔符默认就是空格和Tab所以能当空格用。5.3 关键字被过滤的绕过第三道题更狠cat、flag、空格全被过滤了。这时候需要组合绕过cat可以用tac、more、less、head、tail、nl、od等替代。flag可以用通配符f*、fla?、[f]lag等。空格用$IFS或%09。最终Payload127.0.0.1;tac$IFS/f*或者127.0.0.1;nl$IFS/fla?.txt避坑技巧通配符匹配的时候先用ls看一下目录下有什么文件确认匹配范围。我有一次用f*结果匹配到了flag.txt和flag_bak.txt两个文件命令直接报错。后来改成fla?.txt才精准命中。5.4 命令执行的常见过滤与绕过对照表被过滤内容绕过方式示例空格$IFS、%09、{cmd,arg}cat$IFS/flagcattac、nl、more、odtac /flagflag通配符cat /f*;|、||、、换行符127.0.0.1|whoami斜杠环境变量拼接cat ${PATH:0:1}flag关键字整体变量拼接、编码afl;bag;cat $a$b6. 目录遍历与信息泄露容易被忽视的入口6.1 路径穿越的基本原理9月17日的题是一个文件下载功能URL是?filedownload.php。这种题第一反应就是试?file../../../../etc/passwd。如果返回了passwd内容说明存在目录遍历。路径穿越的核心是../每多一层就往上跳一级目录。但实际环境中../经常被过滤绕过方式有URL编码%2e%2e%2f代表../双重编码%252e%252e%252f绝对路径直接写/etc/passwd截断在PHP老版本中%00可以截断后面的内容我试了直接../被过滤了。换成%2e%2e%2f成功读取到passwd。6.2 备份文件与源码泄露第二道题没有目录遍历但页面底部有个index.php.bak的提示。访问后下载到了源码里面有个include函数参数可控直接导致文件包含。常见的备份文件和泄露路径有文件类型常见命名源码备份index.php.bak、index.php~、index.php.swp版本控制.git/config、.svn/entries配置文件config.php.bak、web.config数据库文件backup.sql、data.sql实操心得拿到源码后重点看三个地方——文件包含、命令执行、SQL查询。这三个地方最容易出漏洞。我习惯用grep搜关键字grep -n include\|exec\|system\|query index.php能快速定位危险函数。6.3 信息泄露的排查清单刷完这两道题我整理了一个信息泄露的排查顺序先看URL参数有没有file、path、page这类可控参数。再看页面源码有没有注释、隐藏字段、备份文件提示。然后试常见备份文件后缀.bak、.swp、.old、.txt。最后试版本控制目录.git、.svn、.hg。这个顺序后来成了我拿到新站点的固定动作能快速排除低级的信息泄露问题。7. 弱类型比较与代码审计入门7.1 PHP弱类型比较的坑9月18日的题是一段PHP代码if ($_GET[a] $_GET[b] $_GET[a] ! $_GET[b]) { echo $flag; }要求两个变量相等但不相等。这听起来矛盾但在PHP弱类型比较下是成立的。比如a1e2和b100在比较时1e2被当成科学计数法值是100所以相等但字符串比较时1e2 ! 100所以满足条件。常见的弱类型绕过Payload变量a变量b比较结果1e2100为true!为true0e1230e456都是0为true[][]数组比较为true00字符串转数字为true7.2 变量覆盖与extract函数第二道题用了extract($_GET)直接把GET参数导入变量。如果代码里有个$flag变量我传?flag1就能覆盖它。变量覆盖的常见函数有extract()把数组键值对导入变量。parse_str()解析字符串为变量。$$var可变变量。防御方式也很简单不要用extract处理用户输入或者用extract($_GET, EXTR_SKIP)跳过已存在的变量。7.3 代码审计的入门思路这两道题让我意识到代码审计不是一上来就通读全文而是先找危险函数再回溯参数来源。我的习惯是用grep搜危险函数include、require、eval、system、exec、query。看这些函数的参数是否可控。如果可控再看有没有过滤过滤能不能绕。最后构造Payload验证。这个思路在后面的综合题里反复用到效率比盲目读代码高得多。8. 六天刷题的复盘与后续方向8.1 我踩过的三个典型坑第一个坑是盲目上工具。第一天我直接用sqlmap跑结果跑出来了但不知道原理第二天换手工注入反而卡了半天。后来我给自己定规矩先手工手工跑不通再用工具用工具也要看它发了什么包。第二个坑是忽略编码问题。命令执行的时候空格被过滤我试了%20不行后来才知道要用%09Tab。URL编码和HTML编码是两回事这个坑我踩了两次才记住。第三个坑是不看出错信息。文件上传的时候服务器返回“文件类型不允许”我以为是后缀问题其实是Content-Type没改。后来养成习惯每次报错都仔细读一遍错误信息里往往藏着过滤规则。8.2 后续可以深入的方向这六天只是把Web安全的基础模块过了一遍每个方向都还有很深的坑可以挖SQL注入可以继续研究堆叠注入、二次注入、宽字节注入。文件上传可以研究竞争条件、.htaccess绕过、二次渲染绕过。命令执行可以研究无回显外带、LD_PRELOAD劫持。代码审计可以研究反序列化链、框架漏洞。我个人的计划是接下来花两周时间专门啃反序列化因为这是现代Web应用里出现频率越来越高的一类漏洞而且利用链的构造非常考验代码理解能力。8.3 给同样在刷题的朋友几个建议如果你也在刷Web方向的题我有三个建议第一每道题写复盘。不用写得多正式但要把“为什么这么打”和“为什么打不通”记下来。我六天写了十几页笔记后来遇到类似题翻笔记比搜资料快得多。第二不要跳过基础题。数字型注入、前端校验绕过这些看起来简单但它们是所有复杂题的基础。我见过有人直接去刷反序列化结果连PHP的魔术方法都说不清楚。第三找个搭子一起刷。一个人刷题容易钻牛角尖两个人可以互相讲思路。我第三天卡在命令执行的空格绕过跟朋友聊了十分钟就找到了$IFS这个方案。最后分享一个我一直在用的小技巧把每道题的Payload整理成一个速查表按漏洞类型分类。下次遇到同类题先翻速查表能省不少时间。这个表我到现在还在更新已经攒了三十多条了。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询