
刷 BugKu 的 Web 篇是我带新人和自己重新梳理知识体系时都会干的一件事。这平台的好处在于题目梯度拉得比较开从送分题一路爬到需要静下心来做代码审计和逻辑绕过的题都有而且不需要你自己搭靶场环境浏览器打开就能开打。这篇 wp 我不打算按题目编号一篇篇复读答案那对新手没有任何营养。我更想把 Web 方向常见的题型、判断链路、卡壳点拆开讲清楚当你自己手头拿到别的靶场题目时也能套用同一套思路去解。标题虽然是“BugKu Web 篇通关”但我真正想交付的是一套能迁移到其他 CTF 比赛的 Web 解题方法论。如果你目前还处在“拿到题目不知道从哪下手”的状态这篇内容应该能帮你把解题顺序固定下来先看什么、怎么测、用什么工具、什么时候该换思路、哪些坑是踩过一次就该长记性的。如果你已经刷过一部分题那后面关于注入判断链路和上传绕过、代码审计的部分值得重点看。1. BugKu Web篇到底在考什么——先建立全局视角很多新人一上来就盯着“这一题怎么解”恨不得每道题都有人手把手喂答案。但通关整个 Web 篇之后再回头看题目之间是有脉络的。BugKu Web 篇的题目大致能分成这么几类我把它们梳理成一个表方便你有个全局概念。题型常见考点典型难度通关后你应该掌握的能力信息搜集类响应头、源码注释、robots.txt、备份文件、CMS 指纹低养成“拿到题目先看源码和响应头”的肌肉记忆HTTP 基础类User-Agent、Referer、Cookie、请求方法、X-Forwarded-For低会用 Burp Suite 改包重放理解请求与响应结构注入类SQL 注入联合、报错、布尔盲注、命令注入中能手工判断注入点闭合方式写出盲注脚本或熟练用 sqlmap文件上传类后缀校验、Content-Type 校验、内容头校验、解析漏洞中知道各类校验在服务端大致怎么实现怎么绕过代码审计类PHP 危险函数、变量覆盖、反序列化入口中高能定位输入点顺着输入点追踪到危险函数逻辑漏洞类越权、验证码绕过、弱口令、业务逻辑绕过中懂得修改请求参数、遍历 ID 或者绕过前端限制这个分类是通关后复盘出来的不是刷题之前就有的。我建议你也用这种方式管理自己的题单每做一道题就把它归类到某一个或多个题型下面顺便记一下自己当时卡在哪里。刷到后期你会发现很多题是复合型的比如上传题会结合代码审计SQL 注入题会结合绕过 WAF 的思路。难度梯度上BugKu Web 篇前三分之一基本属于“鼓励题”只要你愿意打开 F12 看源码、愿意装个 Burp Suite 改改包就能过。中段开始需要一点 SQL 注入基础后段则偏向代码审计和逻辑发散。整体设计对新手非常友好的一点是平台不限制你尝试次数也不搞什么环境隔离你可以在里面反复试错直到把原理弄明白。2. 从第一道题开始HTTP协议的“常识”才是Web题的根基Web 题的本质是你在跟服务器进行 HTTP 对话。很多人忽略这一点一上来就想着怎么搞注入、怎么传马结果最基础的送分题反而卡了半天。BugKu Web 篇开头的题目几乎都是围绕 HTTP 协议的基础字段做文章这其实是在帮你建立“一切攻击都基于合法请求被服务器误解”这个核心认知。2.1 改包前你得有个顺手的工具做题的第一步先把工具链装好。我的建议是三件套Burp Suite Community 版抓包、改包、重放请求的标配。社区版足够打完整套 Web 题不要一上来就去找 Pro 破解版没必要。浏览器开发者工具F12查看源码、看网络面板、改前端临时状态。做 Web 题不开 F12 等于闭着眼走路。curl有些时候你只需要快速发一个带特定 Header 的请求开 Burp 有点小题大做curl 一条命令搞定。拿 BugKu 的一道典型签到题举例页面打开只有一个输入框让你提交一个什么东西。很多新手会直接在输入框里乱试试不出来就卡住。正确顺序是先按 F12 看源码然后切到 Network 面板看页面加载了哪些请求响应里有没有什么提示字段。如果源码和响应头里都找不到线索再用 Burp 对提交动作抓一次包看看 POST 请求体长什么样、服务端返回了什么。2.2 服务端真正会检查的几个 HTTP 字段HTTP 基础题翻来覆去都是在考你对以下几个字段的理解我一个个说。User-AgentUA标识客户端身份的字段。服务端可以读取它来判断访问者是不是浏览器、是 Chrome 还是某些脚本工具。有些题要求你以指定 UA 访问比如改成浏览器版本字符串或者题目指定的 SpecialAgent。用 Burp 改一行就能过。Referer或新标准里的 Referrer表示“你是从哪个页面跳过来的”。有些服务端会校验这个字段要求访问某个页面时必须带有来自特定站点的 Referer 跳转来源——它本质上是一种很弱的防盗链和访问控制手段但也确实常被拿来做题。X-Forwarded-ForXFFHTTP 标准里用于透传客户端真实 IP 的扩展头服务端后面挂代理服务器时非常常见。CTF 题里最常见的考法是要求你必须用某个 IP 地址访问才能看到 flag比如本地 127.0.0.1。因为你自己改包就能伪造这个字段所以这类题本质上考的是“你知不知道改 XFF”。改成X-Forwarded-For: 127.0.0.1重放走人。Cookie 与 Session服务端用 Cookie 标识客户端身份状态。有些题把判断逻辑放在 Cookie 里比如admin0你改成admin1再刷新权限就变了。也有些题让你带着特定 Cookie 访问甚至直接让你从 Cookie 里找到 flag 字段值。请求方法GET、POST 是最常见的但服务端如果只实现了 GET 接口你发 POST 就会 405。反过来也一样。有些题要求你用 PUT、OPTIONS、TRACE 等冷门方法访问属于纯考 HTTP 方法认知的送分题。用 Burp 把请求方法改掉就行或者用 curl 的-X参数直接指定。2.3 响应头里的 Flag 和源码注释里的惊喜除了主动构造请求还要养成看响应的习惯。有些题的 flag 直接就藏在响应头里比如X-Flag: flag{...}这种专治不做题就着急提交的人。还有一些藏在 HTML 注释里注释里通常会写“flag is here”或者给你一个跳转提示。这类题在 BugKu 里属于“做完会觉得自己被温柔对待”的类型但说真的很多人就是在这里养成了不看源码的坏习惯导致后面中高难度的题寸步难行。我的建议是拿到任何一道 Web 题先不做任何攻击性测试就先把源码从头到尾读一遍把响应头看一遍把页面里所有可见的输入点列出来。这套动作做完至少有三成题目已经能出答案了。剩下的七成再进入下面要说的注入和绕过环节。3. SQL注入题的精髓闭合、报错与布尔盲注的完整判断链路SQL 注入在 BugKu Web 篇里的权重很高也是新手从“送分题”迈向“真正 Web 安全”遇到的第一道槛。很多人卡住的原因不是不知道 SQL 注入是什么而是拿到一个注入点之后不知道下一步该干什么、怎么判断注入了什么类型的库、怎么把数据提出来。问题出在他们没把 SQL 注入当成一条“判断链路”来走而是企图一步到位、直接一把梭哈掏出 flag。3.1 第一步永远不是丢 sqlmap而是手工找闭合方式注入的本质是程序把用户输入拼进了 SQL 语句而且没做参数化处理。你要做的第一件事是搞明白输入点拼在了什么位置、用什么符号闭合。假设后台代码长这样$sql SELECT * FROM users WHERE id $id;你在输入框里填1拼出来的 SQL 就是SELECT * FROM users WHERE id 1这时候你输入一个单引号拼出来的是SELECT * FROM users WHERE id 这个语句的语法已经错乱了因为闭合单引号后面多了个多余的引号服务端通常就会报数据库错误。如果它没有把错误信息藏起来而是直接回显给你那就说明注入点大概率存在。观察报错是第一步接下来要判断的就是“怎么闭合才能让这个 SQL 语句是合法的”。这是整个 SQL 注入里最考经验的一步常见情况我给你列出来后台拼接方式你输入的内容完整 SQL 效果$id直接拼1 OR 11WHERE id 1 OR 11$id单引号包裹1 OR 11WHERE id 1 OR 11$id双引号包裹1 OR 11WHERE id 1 OR 11($id)括号加单引号1) OR (11WHERE id (1) OR (11)你可以在输入框里输入这些测试语句观察页面显示是否恢复正常、回显的数据是否有变化。能正常显示说明闭合成功了。闭合一旦成功后面想查什么数据就有了一个合法的“语法上下文”。3.2 联合查询有回显时的最高效手段闭合找到之后最简单的数据提取方式就是联合查询。原理是UNION SELECT会把查询结果和后端查询结果拼在一起只要列数一致后面的查询结果就会原样显示在页面上。首先用ORDER BY探测列数。输入1 ORDER BY 3 -- -如果页面正常说明表至少有 3 列。再试ORDER BY 4如果报错说明列数就是 3。知道列数之后就能用联合查询了1 UNION SELECT 1,2,3 -- -页面通常会回显某个数字比如显示了 2 和 3说明这两个位置是回显位。把 2 换成database()3 换成version()就能拿到当前数据库名和版本信息。接下来通过information_schema.tables查表名、information_schema.columns查字段名一步步把目标表的数据捞出来。整条链路对新手来说其实非常固定多练几道就能形成肌肉记忆。3.3 没有回显也报错不出错那就走布尔盲注真实的题目往往不会让你那么痛快。你测试单引号的时候页面既不报错也没有任何回显变化只有“正常内容”和“空白/异常内容”两种状态。这就是典型的无回显场景需要用布尔盲注构造一个“真假条件”根据页面反应来判断条件是否成立。核心函数搭配是substr()和ascii()。比如要猜当前数据库名的第一个字符可以先猜它的 ASCII 码是不是 97对应字母 a1 AND ASCII(SUBSTR(database(),1,1)) 97 -- -页面正常说明第一位确实是 a接着猜第二位页面没反应就换成 98、99 挨个试。手工试几十次确实累但如果你是来学思路的我强烈建议先用笨办法跑通一次哪怕只是确认一下字符集前几位然后再考虑写脚本。我用 Python 写过一个最简单的布尔盲注脚本模板核心逻辑就三步构造条件、发请求、根据响应判断真假import requests url http://目标地址/index.php?id flag # 假设已知库名长度是 8 for i in range(1, 9): for ascii_code in range(32, 127): # 每个字符转成 ascii 为 victim payload f1 AND ASCII(SUBSTR(database(),{i},1)){ascii_code} -- - r requests.get(url payload) if 特征字符串 in r.text: # 页面正常时的特征内容 flag chr(ascii_code) print(flag) break脚本的思路是对每个位置依次尝试所有可打印字符的 ASCII 码一旦页面出现“条件为真”的特征就记录下这个字符继续下一位。实际做题时除了substr和ascii也可以用left()、mid()搭配ord()看后台用的什么数据库。MySQL 和 SQLite 的语法有细微差别报错信息里一般能看出来。3.4 报错注入和常见过滤绕过如果页面开启了大面积报错信息但又不支持 UNION那可以试试报错注入常见的是 MySQL 的updatexml或extractvalue。原理是让函数解析的 XPath 字符串非法触发报错而报错内容里会包含你传入的 SQL 查询结果。典型写法如下1 AND updatexml(1, concat(0x7e, (SELECT database())), 1) -- -报错信息里就会出现~数据库名。这种方式不需要回显位也不需要列数非常省事。关于绕过BugKu 的题大多不会上很恶心的 WAF但空格过滤、注释符过滤这类基础操作还是时有发生。空格被过滤时可以用/**/或%0a代替注释符-- -被过滤时用#或直接闭合后面的引号。这些技巧说穿了不值钱但确实能卡住没见过的人。4. 文件上传、命令执行与代码审计——三板斧打穿中阶题过了注入这一关BugKu Web 篇的体验会明显提升一个档次因为后面的题目不再是“一个输入点打到死”而是要求你综合运用文件上传、命令执行、代码审计等多项能力。这三块在实战中经常是连在一起的审计一段代码发现命令执行漏洞或者通过上传点拿下一句话木马。4.1 文件上传校验逻辑比文件内容更值得研究文件上传题的经典场景是页面提供一个上传入口让你传一个文件。目标通常是把一句话木马传上去然后通过 Web 访问它执行系统命令。服务端常见的校验逻辑有四种对应的绕过思路也完全不同我整理成表格校验位置校验逻辑常见绕过方式后缀名只允许.jpg/.png/.gif改成.php3/.phtml/.php5、大小写混合、末尾加空格或.Content-Type检查请求头里的 MIME 类型Burp 改包把Content-Type改成image/jpeg文件内容头检查文件开头的幻数如GIF89a在 PHP 代码前拼一段图片头字节目录/路径上传路径拼接不可控尝试路径穿越等方式少数题会考绕过的核心思路是服务端只校验了某一个维度而解析文件的逻辑又恰好容忍了你绕过的这个维度。比如它检查了文件后缀但没有检查文件内容那你就可以传一个内容为?php eval($_POST[x]); ?、后缀命名为shell.jpg的文件然后看看服务器会不会把它当作 PHP 解析。如果服务器配置了 Nginx 解析漏洞或者 Apache 多重后缀解析特性shell.jpg在某些路径下就能直接被当成 PHP 执行。BugKu 的题不一定会走到解析漏洞那么深的程度但“后缀校验不严”这种经典漏洞是必然会出现的。一句话木马的本体是?php eval($_POST[shell]); ?连上之后用工具或者手工 POST 参数shellsystem(ls);就能通过页面回显看到服务器上的文件列表。在 CTF 靶场上这一步是拿 flag 的关键。但这里我要多说一句这套能力只能在授权靶场里玩上传一句话木马到真实第三方站点那是违法的而且现在很多服务器都有防护也不会给你这么简单的机会。4.2 命令执行过滤了关键字不等于过滤了命令命令执行题一般长这样页面有个输入框传入一个 IP后台执行ping命令然后把结果回显出来。后台代码大致是$ip $_GET[ip]; system(ping -c 1 . $ip);如果服务端没有做任何过滤那直接输入127.0.0.1; ls就能看到目录列表。分号;、管道符|、换行符%0a、、||都是常见的命令拼接符号具体用哪个取决于后台用的是system()、exec()、passthru()还是shell_exec()以及它有没有做简单的过滤。如果它过滤了空格、ls、cat这些关键词也不要慌。空格可以用${IFS}替代cat可以用tac、more、less、head、tail替代ls可以用dir或者用通配符l*来绕过。我之前在一道题里遇到过过滤了cat和空格的环境最终用这段拿到了命令执行结果127.0.0.1;tac${IFS}/flag*tac是cat的反向输出${IFS}替代空格/flag*用通配符匹配 flag 文件名过滤规则直接失效。这类题的核心不是让你背命令而是让你理解过滤总是基于字符串匹配的而命令行的解析逻辑比字符串匹配复杂得多只要有一丝缝隙命令才能被拼起来。4.3 简单代码审计从输入点出发追到危险函数BugKu Web 篇后段的题目很多会直接给你 PHP 源码。新手看到一坨代码就发怵其实关键就两步找输入点。看有哪些变量来自$_GET、$_POST、$_REQUEST、$_COOKIE、$_FILES这些是你能控制的。顺藤摸瓜看输入点最终有没有流入危险函数。高危函数列表不多背下来就行eval()、system()、exec()、shell_exec()、assert()、include()、file_get_contents()、unserialize()。举一个最简单的例子?php $action $_GET[action]; include $action . .php; ?这个代码里$action是输入点include是危险函数。虽然它强制拼接了.php后缀但如果你传php://filter/convert.base64-encode/resourceindex就能用 PHP 流包装器把源码读出来后缀拼接在resourceindex.php上完全正常。这就是利用 PHP 内置协议的思路。做代码审计题一定要有个好习惯不要一行行从头读要先找输入点和危险函数然后把两者之间的路径打通。绝大多数 CTF 题的代码都不长可控点也就一两个用这个思路几分钟就能定位到可利用的位置。5. 卡关时最值得留意的几个“隐藏考点”做题最气人的不是题难而是题里塞了一些“小彩蛋”你没注意到就永远卡在同一关。BugKu Web 篇的题目很喜欢在常规考点之外埋一些隐藏信息按照我的经验下面这几个位置值得形成条件反射式的关注。5.1 响应头、JS 混淆和编码跳转有些题目在页面上只显示一张图或者一句话看起来毫无线索。这时候去翻响应头往往有意外收获。不只是X-Flag这种直白的字段有些题会把提示藏在Set-Cookie里或者藏在某个 JS 文件的注释里甚至在页面引用的某个.js文件末尾加了一段 base64 编码字符串。处理这类问题我习惯把所有返回内容复制下来如果里面有可疑字符串就丢到 CyberChef 里面试试 base64 解码、URL 解码、十六进制转 ASCII基本上一两轮就能解开。还有一种“跳转型”题目JS 里面加密混淆了一串字符或者页面通过 JS 不断跳转到别的路径。这类题不适合用肉眼盯代码直接把源码里看起来像编码结果的长字符串复制出来按 base64 或者十六进制解一遍大多数能发现 flag 或跳转地址。5.2 备份文件、robots.txt 和隐藏目录信息收集不仅仅是“看看页面”还要考虑站点上有哪些隐藏资源。做题时我用dirsearch或手写一个简短的目录字典去扫靶机上的路径发现过.git目录泄露、index.php.bak、www.zip、robots.txt这类东西。robots.txt是搜索引擎爬虫规则文件它经常会被网站管理员用来“屏蔽”不想被收录的路径结果反而是把敏感路径直接告诉了你。遇到 403 或者 404 的路径列表如果出现在robots.txt里值得换个请求方法或者补充路径再访问一遍。.git泄露则是另一个经典考点。如果扫描到/.git/目录存在说明站点把整个 Git 版本库暴露到了 Web 目录工具可以直接把源码拖下来里面往往有修改历史而 flag 可能藏在某次提交里被删掉了但历史版本里还有。不过这类题在 BugKu 里不是主流属于中后期才会遇到的花活。5.3 逻辑层漏洞越权和弱口令不要以为 CTF 题都是高大上的技术漏洞越权和弱口令也是常客。越权的典型场景是用户登录后访问一个profile.php?id100把自己的 ID 改成 101页面如果显示了别人敏感信息甚至变成管理员权限就是水平越权。有些题甚至懒得上登录流程直接给你一个可遍历的 ID 参数你就能依次读取其他用户的数据。弱口令更是老生常谈。遇到登录框先试试admin/admin、admin/123456、test/test这种经典组合。BugKu 有些题的登录提示其实写在页面标题或者源码注释里就是变着法提醒你别死磕技术漏洞先试试弱口令。如果登录成功并且出现了文件上传功能那就回到上一节的上传思路继续往后打。6. 我这轮刷题踩过的坑和我的排除顺序最后这部分我想说说我自己从头到尾刷 BugKu Web 篇时踩过的坑。这些坑不是知识点层面的而是做题习惯和心态层面的但说实话它们比知识点更能决定你能不能通关。6.1 我踩过的几个具体坑第一个坑不抓包只在浏览器里折腾。我前期有段时间遇到输入框就在页面上乱输完全忽略了 Burp Suite。直到遇到一道题页面上怎么输入都不对但抓包一看原来提交的请求里有一个隐藏参数前端页面根本没显示出来。从那以后我养成了“任何提交动作都必须抓包看一遍”的习惯。第二个坑拿到源码之后没有主次浪费大量时间一行行读。后来我发现只要先把$_GET、$_POST、$_REQUEST、$_COOKIE这些输入搜出来再把eval、system、include、unserialize这些高危函数搜出来中间一连接漏洞点基本就水落石出了。第三个坑过分依赖 sqlmap。工具确实快但我曾经在一道题里直接跑 sqlmap跑了二十分钟什么都跑不出来后来手工注入发现后台是 SQLitesqlmap 默认的 MySQL 指纹压根不匹配。快到的东西不一定可靠手工理解判定链路才是根治方案。第四个坑不看提示死磕一个点。BugKu 的题目描述里经常带着很明显的提示比如“请用 admin 身份访问”“某文件泄露了敏感信息”。我有一道题卡了两个小时最后发现题目描述第二行就写着“试试看备份文件”思路直接崩了。现在做题我第一件事就是反复读题面一个字都不会漏。6.2 我固定的解题顺序直接抄即可把上面所有经验浓缩成一条可执行的流程我现在做题的固定顺序是这样的读题面至少两遍画出所有线索关键词。F12 看源码看 HTML 注释看引用的 JS 文件。Network 面板看请求和响应头尤其注意有没有开给爬虫或者调试用的字段。对页面上所有输入点、按钮做一次正常请求抓包记录正常响应。根据前面信息判断题型注入 / 上传 / 命令执行 / 逻辑漏洞 / 代码审计 / 信息搜集。按题型进入对应链路每一步基于上一个响应结果决定下一步。卡住超过 30 分钟就放弃当前思路回去复查题面和响应头看看是不是漏了隐藏信息。解出 flag 后把 payload 和思路记录到自己的笔记里标注“当时卡在哪一步”。这个顺序看起来朴素但真的能救命。尤其在比赛现场或者限时环境下思路一旦乱了最有效的动作就是退回去从头看请求和响应而不是在一个错误的方向上继续消耗情绪。6.3 几件值得长期坚持的事情养一个“漏洞知识笔记”仓库按题型分类记录每次做题用的 payload 和绕坑过程。刷题时不追求题目数量而是追求“我能从头到尾讲清楚为什么这样闭合、为什么能绕过”。常用工具提前配好Burp Suite、dirsearch、CyberChef、一个顺手的 Python 环境别到了用的时候才想起来装。学会写简单的 Python 请求脚本因为盲注、遍历、爆破这类重复劳动写脚本的速度比手点快得多而且不容易出错。我第一次完整刷完 BugKu Web 篇的时候其实没有立刻感觉“我变强了”更多是松了一口气原来 Web 题就这些东西翻来覆去都是那几个考点。但后来再去打别的平台的题目我发现那些题目表面上换了皮内核却完全一致——闭合、绕过、信息收集、逻辑设计全都是 BugKu 这边练过的底子。这也是为什么我愿意花篇幅把这套思路完整写下来而不是给一份简单的答案列表。答案会过期但解题链路和排查习惯能陪你在 CTF 这条路上走很久。