首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
CTF Web入门刷题实战:从SQL注入到PHP反序列化
📅 2026/10/17 10:04:31
✍️ 爱科研究院
👁 阅读 3,247
CTF的Web方向算是所有方向里最容易上手、也最容易让新人产生“我好像会了”错觉的领域。我最近在某个CTF练习平台上把Web方向的1~10题完整刷了一遍整理了一份writeup顺便把做题过程中踩过的坑、试错的路径和对题目设计的思考一起写出来。对于刚接触CTF的同学来说这几道题覆盖了Web方向最典型的入口前端审计、抓包改包、SQL注入、命令执行、文件上传、PHP弱类型和反序列化。刷完这一批基本上就能理解CTF题目里“入口找到、漏洞触发、数据提取”这条主线是怎么走的了。写writeup这件事表面上是在记录解题过程实际上是在逼自己把所有试错步骤重新过一遍。很多时候当时靠运气拿到flag回头写出来才发现自己的思路是断的——某些关键参数为什么这么写、为什么一定要先order by再union根本没想清楚。所以这篇不只是把答案贴出来我会把每一步的判断逻辑、报错信息对应的含义、以及我踩过的坑一并写出来。1. 整体思路这10道题到底在考什么1.1 题目分布与核心考点开始刷之前我先把题目列表扫了一遍。这批Web 1~10题没有按难度从“纯前端”到“服务端漏洞”线性排布但大致能分成三组前3题属于信息收集与基础协议中间4题是SQL注入和命令注入的组合后3题集中在文件上传、代码审计和反序列化。看起来杂乱其实是一个很典型的入门路径。信息收集题的价值在CTF里经常被低估。很多人上来就去试SQL注入结果第一题只是让你看一眼源码注释。我见过不少同学在简单题上耗费半小时就是因为没有养成“先看HTML、再看JS、再抓包、再考虑漏洞”的习惯。这一批题目里至少有两道都是纯粹靠观察页面细节就能解的根本不需要构造payload。中间四题里SQL注入占了两个命令执行占了一个还有一道是把SQL注入和弱类型比较混在一起。说实话第二道SQL注入题比第一道难一些因为它过滤了默认的关键字需要换思路。命令执行那一题则是对Linux命令拼接特性的入门考察管道符、通配符、$IFS这些知识点在真实渗透测试里也是基本功。后三题里文件上传考的是MIME和扩展名的双重绕过代码审计题考的是备份文件泄露最后一道是PHP反序列化。反序列化这题对新手是最难的因为它不是靠工具扫一眼就能出结果的必须看得懂类方法之间的调用关系手动构造数据包。不过题目本身给足了源码而且目标类方法写得很直白算是把门槛降到了最低。1.2 我自己做题时的顺序和工具准备刷题顺序我建议按题目编号来因为它是递进的但如果有哪一道卡了超过20分钟我会先跳过后面再回头看。卡住的时候死磕反而容易钻牛角尖换个题清醒一下思路可能就通了。工具方面我准备了这些一个带代理抓包功能的浏览器或独立抓包工具能力范围内都行、一个终端环境、一份常用Payload字典以及一个用于目录扫描的简单字典文件。SQL注入的自动化工具我这次没怎么用因为题目基础手工构造更能练出判断能力。抓包工具强烈建议提前配好代理很多新人卡在抓包上不是因为题目难而是手机或浏览器的代理没配对导致流量根本走不过去。另外我习惯在本地开一个“草稿环境”用来快速测试payload的引号闭合和编码格式尤其是在命令执行题里面稍微一个转义不对就全错了。很多writeup里直接贴正确答案不解释为什么在引号前面要加一个反斜杠我自己吃过亏所以下面写每一个关键payload都会把为什么这么拼拆开讲。2. 基础题源码审计与前端绕过2.1 第一题藏在注释和开发者工具里的flag第一题打开以后是个很普通的页面背景是一张图片上面一行字说“恭喜你找到入口”然后没有任何交互。我第一反应是查看源代码按F12打开开发者工具在Elements面板里能看到一个注释!-- flag_hint: ZmxhZ3tyZWFkX3NvdXJjZV9jb2RlfQ --这个字符串一眼就能看出是Base64编码因为结尾有而且长度是4的倍数。在浏览器控制台里用atob()解一下或者直接扔到终端的base64 -d里去解得到flag{read_source_code}。这一段就是第一题的完整flag。这道题其实想教的就是“信息收集”四个字。很多新手以为拿到题目就要开始注入其实CTF题目的第一步永远是看这个页面有没有返回我们没注意到的数据。除了注释响应头、Cookie、JS文件、图片的EXIF信息、甚至robots.txt都可能藏东西。这里有个小技巧如果右键菜单被禁用直接按F12或者CtrlShiftI照样能打开开发者工具也可以在地址栏输入view-source:完整URL来查看网页源码这种场景在后面的题里更常见。我自己的体会是解这种题不要急着复制注释里的内容去百度先自己看一眼有没有明显特征。Base64和十六进制编码是CTF里最常见的两种编码练到一眼识别出编码类型后面能省很多时间。2.2 第二题JS禁用也能看到答案第二题页面里有一个按钮点击后弹出一个对话框内容是“密码错误”没有任何其他提示。我照例看源码发现它引入了一个check.js文件直接在浏览器地址栏打开这个check.js看到如下代码function checkPassword() { var flag flag{javascript_is_fun}; var input document.getElementById(pass).value; if (input admin) { alert(flag); } else { alert(密码错误); } }这题实际上就是考直接查看外部JS文件。既然flag变量就在checkPassword函数里根本不需要输入正确的密码。我直接在控制台执行checkPassword()因为浏览器环境里所有全局函数都能在控制台访问。更粗暴的办法是直接在控制台执行alert(flag)或者干脆改写逻辑把if判断条件反着来。但最正规的解法是看到这个函数后直接在源码里搜关键词flag几秒钟就出来了。这里补充一个“禁用JS”的经典场景有些前端验证题在禁用JavaScript后整个页面会失去验证逻辑这时候可能绕过前端限制。但第二题并不是这个套路它的考点是“不要只看HTML还要看引用的资源”。很多初级开发会把敏感逻辑写在JS里这在真实环境里是安全隐患但在CTF里就是送分题。我在做这题时还试过用浏览器自带的查找工具CtrlF搜索“flag”快速定位关键词。如果你在一个大文件里找flag这个方法比逐行读代码高效得多。另外如果JS代码被压缩成了一行建议复制到本地用格式化工具打开可读性会好很多。2.3 第三题响应头与抓包改包第三题一打开页面显示“仅允许来自某内部来源的访问”。浏览器里直接访问返回403。这题明显要改Referer头。Referer是HTTP请求头里用来标识来源页面的字段很多站点会用它做防盗链或访问控制。但在CTF里这个字段纯粹是一个可以被伪造的信息。我先把请求发送到抓包工具在请求头里面加上一行Referer: http://internal.site/重新发送之后页面返回了一段提示“请求方式不对请使用POST”。好这又接上了一个HTTP方法的考点。于是我把请求方法从GET改成POST再次发送响应头里出现了一个X-Flag字段X-Flag: flag{http_basic_is_important}拿flag的过程很顺利但这里有两个极易踩坑的点。第一Referer的值在HTTP协议规范里应当是一个完整的URL有些新手写成了internal.site没有加协议头服务端可能会解析失败。第二如果只改POST而不改Content-Type某些后端框架会拒绝无内容的POST请求可以手动加一个Content-Type: application/x-www-form-urlencoded问题就解决了。更常见的变种是考X-Forwarded-For注入IP用来让服务端认为请求来自127.0.0.1。这个头本身是反向代理添加的但如果后端直接从请求头里取值做IP白名单就会存在伪造风险。解题时在原始请求里加一行X-Forwarded-For: 127.0.0.1往往就能达到“本地访问”的效果。各类“仅允许本地管理员”的题目十有八九都是这么设计的。抓包改包是Web方向的基础能力。很多人只在浏览器开发者工具里看Network那个只能看不能改真正要改请求必须用抓包工具。用不习惯的话其实浏览器开发者工具也自带了“编辑并重新发送”的功能在Network面板的某个请求上右键就能找到不需要额外工具也能完成大部分改包操作。3. 注入与命令类从SQL到命令执行3.1 第四题最简单的数字型SQL注入第四题是一个参数id页面会显示对应的内容。点了一下?id1正常返回改成?id2也正常返回。我先判断是字符型还是数字型直接在后面加and 11正常改成and 12无结果。这基本确定是数字型注入不需要闭合引号。接下来用order by判断列数。order by 1到3都正常order by 4报错说明查询结果有3列。这一步很重要因为联合查询的两个查询语句必须列数一致否则MySQL会直接报错没法回显。列数确定后我用联合查询查看回显位置?id1 and 12 union select 1,2,3页面上显示了2和3两个数字说明第二和第三列是在页面上回显的。接着把回显位置换成我们需要的数据。先查库名?id1 and 12 union select 1,database(),3得到库名ctf_db。继续查表名?id1 and 12 union select 1,group_concat(table_name),3 from information_schema.tables where table_schemadatabase()这里需要说明一下group_concat()的作用把多行查询结果合并成一行方便在单行回显里全部输出。查出来有两张表一张是users一张是flag_table。那目标很明显在后者。查列名?id1 and 12 union select 1,group_concat(column_name),3 from information_schema.columns where table_nameflag_table得到列名flag。最后直接把数据带出来?id1 and 12 union select 1,flag,3 from flag_table拿到flag。整个过程其实不复杂但对新手来说最大的障碍是不知道information_schema里面有什么。简单说这个库是MySQL自带的“元数据库”tables表存所有表名columns表存所有字段名。理解了这一点SQL注入的常规流程就串起来了猜列数、找回显位、查库名、查表名、查字段名、查数据。这里有一个很关键的避坑点联合查询时前面那个查询结果必须为空否则union后面的数据不会显示。所以我习惯在正常参数后面加上and 12这样前面返回空后面的union结果就成为唯一输出。如果你不加这个条件第一行数据会把我们的注入结果顶掉看起来就像没注入成功一样。3.2 第五题报错注入与information_schema第五题同样是一个SQL注入点但测试了一下发现union和select被过滤了直接使用会被替换成空。这种过滤很容易绕过比如大小写混写UnIoN SeLeCt但这题似乎把大小写也处理了。我尝试了一下/**/替代空格发现order by可以用但联合查询一直报错。于是换思路改用报错注入。MySQL的报错注入核心是利用某些函数在报错时会把参数内容带进错误信息。常用的是extractvalue和updatexml。原理是这两个函数在处理XPath表达式时如果格式错误会把错误信息包含在报错里。例如?id1 and extractvalue(1,concat(0x7e,(select database()),0x7e))0x7e就是~符号的十六进制写法用它包裹查询结果方便在报错信息里看清楚输出。执行后页面返回类似XPATH syntax error: ~ctf_db~库名就暴露了。如果按这个思路一步步查表、查字段、查数据和联合查询的流程是一样的只是载体不同。这里补充一下如果单双引号被过滤了可以用0x7e拼接而不是直接写引号或者用char()函数。如果database()被过滤可以临时换成schema()不过老版本MySQL可能不支持。报错注入在现实场景里也常见尤其是目标使用了某种WAF过滤掉union和select的情况下报错函数往往不在常规黑名单里。我在这题上卡了挺久原因是把一个关键字替换成了空格然后总是报语法错误。后来才意识到过滤逻辑是把它替换成空字符串而不是抛异常例如输入selselectect会被处理后变成select。在一些CTF题里这种“关键字递归替换”的过滤方式反而更容易绕过。但这题用的不是这种而是直接把整个注入行为截断所以必须另寻出路。做SQL注入题脑子里至少要准备三条路线联合查询、报错注入、布尔盲注。前面走不通就立刻换不要死磕一条。3.3 第六题命令执行的绕过技巧第六题是一个输入框提示输入一个IP地址来执行ping。我随便填了一个127.0.0.1页面显示了一下PING命令的输出这说明后端确实把它直接拼接到了系统命令里。此时试着在后面拼接其他命令127.0.0.1;ls如果ls的回显出现在页面里就说明分号没被过滤。但我测试后发现输出为空。我又试了 ls和| ls其中管道符|成功了这题过滤了分号但没有过滤管道符。接下来还需要找到一个文件。我用| cat flag.php测试结果显示为空可能是cat被过滤了也可能是flag.php文件名不对。先用ls看一下目录127.0.0.1|ls输出里有index.php和一个fl4g.txt原来文件名不是固定的。读取的时候发现空格被过滤了所以我用${IFS}代替空格127.0.0.1|cat${IFS}fl4g.txt成功拿到flag。这里解释一下${IFS}它是Linux系统环境变量中的“内部字段分隔符”默认包含空格、Tab、换行所以在命令里它等效于空格。常见的空格过滤绕过方式有${IFS}、$IFS$9和URL编码的%09其中%09是Tab字符。如果命令名本身也被过滤比如常见的cat、ls被过滤可以尝试在命令关键字中间插入反斜杠c\at用通配符代替/bin/c?t用变量拼接ac;bat;$a$b用其他等价命令more、less、head、tail、tac命令执行类的题目本质上就是考验对Linux命令解析规则的理解。过滤得再多只要有一个字符或一个操作符能用就能组合出完整命令。常见的操作符优先级也要清楚|只执行后面命令并取前面命令的输出||是前面失败才执行后面是前面成功才执行后面;则是无论前面如何都执行后面。题目过滤了某个操作符就去试其他操作符总有一个漏掉的。这题我还发现一个细节每次ping命令执行后会有超时等待这是因为有些命令执行类题目会等待ping完成。如果加上-n参数或者使用timeout命令可以缩短时间但不影响拿flag。4. 文件与代码审计上传、包含、弱类型4.1 第七题文件上传的MIME和扩展名绕过第七题是一个文件上传页面上传提示说“请上传图片”。我准备了一个PHP文件里面写的是访问时就输出环境信息的一行代码。直接上传提示“文件类型不正确”。抓包一看请求头里Content-Type: application/x-php后端显然校验了MIME类型。把这一行改成image/png重新上传提示“上传成功”。但是查看上传后的路径发现文件没有执行页面直接下载了这个文件。这说明后端还检查了扩展名而且不只检查后缀可能还检查了文件内容头。所以下一步构造一个“图片马”在PNG文件头后面拼上PHP代码。PNG文件头通常以\x89PNG\r\n\x1a\n开头我用编辑器在头部加了这些字节后面跟?php echo test; ?再把MIME改成image/png上传。上传之后访问该文件发现仍然没有解析。继续看响应头发现服务器把它当作了图片处理说明扩展名还是被拦截了。尝试把扩展名改为.php5或.phtml这次成功了服务器执行了里面的PHP代码。这个题考察的就是“服务端解析规则”和“上传文件类型校验”之间的偏差。很多服务器默认只解析.php但部分配置允许.phtml、.php3、.php5。如果黑名单只过滤.php那么这些变体就可能是突破口。还有一种常见绕过是文件名后缀双写比如上传shell.pphphp如果后端只是把.php替换成空字符串那么处理后就变成了shell.php。这种“一次替换”的过滤逻辑在CTF里很经典也可以配合大小写、点、空格等特殊字符来绕过Windows文件名解析规则但题目环境是Linux所以双写没有生效试了几种扩展名后定位到了.phtml。这里要特别提醒文件上传漏洞在真实环境中危害极大但在CTF里它只是模拟环境所有操作都是被允许的。建议只在本地或CTF平台上尝试不要拿真实网站练手。拿到shell之后我直接查看当前目录下的文件发现flag.txt就放在同目录直接读取即可。这题的考点其实集中在“如何让一个文件被成功上传且被当作脚本执行”执行后的操作反而很简单。4.2 第八题php弱类型比较的经典坑第八题给了一段PHP源码大概逻辑是这样$a $_GET[a]; $b $_GET[b]; if ($a ! $b md5($a) md5($b)) { echo $flag; }要求两个变量的值不同但是它们的MD5值弱比较相等。这个条件看起来不可能但PHP的弱类型比较存在一个著名的问题如果比较的两个字符串都形如0e开头且后面全是数字PHP会把他们当作科学计数法来解析也就是都等于0。比如md5(QNKCDZO)的结果是0e830400451993494058586219670391而md5(s155964671a)结果是0e342768416822451524974117254469两个字符串都等于0所以成立。访问时构造?aQNKCDZObs155964671a拿到flag。如果题目改成强比较这个办法就不行了。但许多入门题依然用就是为了考察这个知识点。除了0e开头的md5PHP中的strcmp()函数也有一个经典坑如果传入一个数组函数会返回NULL而NULL 0成立。所以如果题目里出现了strcmp($a, $flag) 0直接传a[]any就能绕过。这题给我的启发是看题目给的源码时第一件事不是去思考算法而是检查所有比较运算符。和在PHP里的行为差异极大很多设计者不经意用前者写“安全判断”就成了漏洞来源。在真实代码审计里看到比较哈希或密码时也要多留个心眼。如果不想依赖外部字典也可以用md5_file()或者数组绕过。比如构造a[]1b[]2因为md5(array)会返回NULLNULL NULL也成立。这种方式在某些过滤了流量的题里反而更好用。我第一次做的时候直接抄了0e字典但没有加上引号导致整段被当成数字解析越界后来才意识到这是PHP代码里的字符串比较payload需要放在URL参数里不需要额外引号。4.3 第九题备份文件泄漏与源代码审计第九题进入页面后只显示一个输入框“文件路径”。我尝试输入index.php页面返回了源码。这说明后台存在文件读取接口但没有过滤路径。不过直接读一个文件只能看到代码flag还没暴露。这时想到常见的信息泄露方式index.php.bak。在地址栏直接读取备份文件view-source:http://target/index.php.bak或者用文件读取口读取index.php.bak返回了一段带注释的源码。备份文件里通常保留着开发者的修改历史很可能有额外信息。源码里发现这样一段$file $_GET[file]; include($file);没有做任何过滤并且$file是用户可以控制的说明这里存在本地文件包含漏洞。最直接的利用方式是配合php://input伪协议让服务器执行我们POST上来的代码。但题目当前页面本身就是那个输入框所以我可以直接在file参数中写php://input然后用POST请求体发送PHP代码。不过这道题更简单因为文件读取接口可以直接读任意文件我尝试读/flag或/var/www/html/flag.txt等路径最终在/var/www/html/flag.txt里找到了目标文件直接读取即可。如果这条路不通还可以用php://filter/readconvert.base64-encode/resourceindex.php来获取经过Base64编码的源码从而绕过直接执行限制。我在练习时故意用这种方法验证了一下读取flag.php的Base64内容再解码出来也能拿到flag。备份文件是Web安全里非常常见的信息泄漏点。常见的备份文件后缀有.bak、.swp、.swo、~结尾的文件、.old等。如果题目没有给任何提示可以先用目录扫描工具扫一下字典里通常都会包含这些。不过这里没有用到扫描因为页面本身就暴露了接口直接读备份是更快的路径。这道题的核心价值在于把“信息收集”和“漏洞利用”连接起来有时候漏洞入口是隐藏的藏在一个备份文件里。很多代码审计题不会直接给你全套源码而是通过一个备份文件或一个git泄露让源码“意外”暴露。所以看到任何疑似有文件操作的题目先找备份文件总没错。4.4 第十题综合题PHP反序列化入门第十题是这批题里最难的主要考察PHP反序列化。页面提供了一段源码class User { public $username; public $role; function __destruct() { if ($this-role admin) { include(/flag.txt); } } } $data $_GET[data]; unserialize($data);代码很简单如果User对象的role属性等于字符串admin那么对象销毁时会读取flag。这里的攻击点是我们可控的data参数可以被反序列化成任意对象。正常逻辑下这个类本身没有赋值入口但如果我们自己构造一个序列化字符串就能造出一个roleadmin的User对象。PHP序列化字符串的格式有固定语法。一个属性为username和role的User对象序列化结果大致长这样O:4:User:2:{s:8:username;s:5:admin;s:4:role;s:5:admin;}逐段解释O表示对象4是类名长度User是类名2是属性个数然后大括号内依次是键名和值的序列化。其中s表示字符串8是名字长度admin是值依此类推。我直接把这个字符串放在data参数后访问后页面输出了flag。但当时我的第一次尝试没有成功原因是PHP反序列化过程中会自动执行__wakeup()方法而源码里虽然没有显式写但在实际环境中有可能设置了属性个数检查导致反序列化失败。如果遇到这种情况可以尝试把属性个数改大比如改成3很多版本里这会绕过__wakeup()的校验原因是属性个数不匹配会触发一个不同分支。不过这题没那么复杂一次就过了。反序列化题目的关键点在于找到可以被利用的魔法方法常见的__destruct、__wakeup、__toString、__call等。理清触发条件这个方法是何时被调用的需要哪些属性满足条件。构造序列化数据严格按照类定义中的属性名、属性类型来构造注意属性修饰符是public、protected还是private因为序列化字符串的格式不同。考虑可能的过滤和绕过比如限制关键字、限制长度、限制特殊字符等。这题本身是最基础的“反序列化触发危险功能”的模型。明白这个流程后后续遇到Pop链利用多个类之间的方法调用链也能拆解成一步步的对象构造。写writeup时我把序列化字符串手打了一遍加深记忆。手打的同时也注意到每个属性的名字不能写错比如把role写成roles反序列化后该属性不存在$this-role就是NULL条件就不成立了。很多新人拿不到flag不是思路不对而是字符串构造时少了一个引号或一个花括号。5. 常见问题与排查技巧实录5.1 我踩过的坑SQL注入时的引号闭合SQL注入的order by和union几乎人人都会写但真正做题时挂在“引号闭合”上的人特别多。字符型注入和数字型注入的payload完全不同。数字型直接拼数字字符型则需要在参数值后先闭合后端SQL语句里的单引号比如输入1 and 11这里的逻辑是让原语句变成where id1 and 11如果你在字符型注入里直接输入1 and 11整个值会被当成字符串注入不会生效。判断是哪种类型有一个很简单的方法在参数后加一个单引号如果页面报错或行为异常说明后端把它放进SQL语句时没有做类型转换就是字符型如果加了单引号仍然正常显示那么很可能被代码里强制转成了整数也就是数字型。另一个常见的坑是URL编码。#在URL中代表锚点传给后端时会被截断所以如果payload里有#需要先编码成%23。空格在某些WAF或过滤规则里会被处理可以换成/**/或。我在这批题里没有遇到特别严格的WAF但后续刷题时一定要养成先编码再发包的习惯。5.2 容易忽略的Headers和Set-CookieWeb题里响应头常常藏着关键信息但很多新手只关注页面主体。第三题中的flag直接放在自定义响应头里如果不看Network面板根本发现不了。抓包时也不要只看响应头里的常规字段像X-Flag、Flag、Hidden这类自定义字段都可能出现。如果响应头里有Set-Cookie也要解码看看有些题把flag拆成两半一半在Cookie中一半在Body里需要拼接。检查响应头最直接的方法是在开发者工具的Network面板中点开具体请求查看Headers标签。我一般会先看Response Headers再在命令行里用curl -I复看一遍防止浏览器缓存干扰。如果页面有重定向要跟踪所有跳转过程因为flag可能藏在某个中间跳转的响应里。5.3 快速判断题目类型的方法刷了这10道题后我总结了一个快速判断题型的套路。看到页面有参数输入但没有登录框优先试SQL注入看到输入框有“查询”“ping”等字样考虑命令注入看到上传点就考虑文件上传看到页面直接输出源码或可以从参数读取文件考虑文件包含和代码审计。这些判断不是绝对的但能帮你快速找到第一个突破口。还有一个判断技巧看题目页面返回的HTTP状态码和错误信息。如果是MySQL语法错误基本就是SQL注入点如果是“include”或“path”相关错误就是文件包含如果有系统命令的报错就是命令注入。实在没有头绪时按“前端源码 → 抓包 → 扫描 → 注入”的顺序去尝试覆盖率会高很多。5.4 命令执行过滤绕过速查结合第六题的实战把命令执行常见的绕过方式整理成一张速查表方便以后刷题时对照。过滤点绕过方法示例空格${IFS}、$IFS$9、%09、%20cat${IFS}/flag分号;使用管道符 、、关键字cat插入反斜杠、变量拼接、通配符c\at、cat、/?in/c?t命令名过滤使用等价命令more、less、tac字符过滤Base64二次编码echo Y2F0IGZsYWc域名/IP过滤十六进制或十进制表示127.0.0.1转为数字这个表不是标准答案但覆盖了CTF入门题常见的过滤颗粒度。实际做题时先试一两种最省事的不行再叠加组合。5.5 文件上传与代码审计的排查顺序文件上传题做完后我自己整理了一个排查顺序先确认上传成功时返回的路径然后判断文件是否被执行再检查扩展名限制再检查MIME再检查文件内容头。每一步都可以通过抓包改包来测试。如果上传的位置是固定的不要忘了在不同目录间尝试有些题只允许传到/upload目录但源代码里却可能会把上传路径拼接到一个可预测的位置。代码审计题则应当先看敏感函数再追踪参数。敏感函数包括include、require、eval、system、exec、shell_exec、file_get_contents、unserialize等。在看到这些函数出现的位置后往回追踪参数是否可控。这一批题里的第九题和第十题都是这个思路先看到include和unserialize再去找到参数变量$_GET然后直接构造输入。做多了以后这种题就像找钥匙一样自然。这10道题刷下来我个人最大的感受是CTF不是比谁手里的工具多而是比谁脑子里的“路径图”清晰。拿到题目后第一步永远是想“这个页面有哪些输入点”第二步是“这些输入点对应哪些常见漏洞”第三步才是“构造payload、试错、调整”。writeup的作用不是把答案丢给别人看而是把每一步排查的因果链条记录下来。下次遇到类似的题哪怕环境变了你的思路依然能复用。最后分享一个小技巧每做完一题不要急着开下一题花两分钟重新审视一次自己的请求记录把“我为什么在这个位置尝试这个payload”写下来。这个过程一开始有点耗时间但当你积累到一定量你会发现自己对题目的敏感度明显提高很多错误在试之前就能预判到。后面再遇到更复杂的Web题目这套基础流程会让你走得更稳。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/17 10:04:31
基于Motus2的机器人自主导航实战:从强化学习到真机部署
2026/10/17 10:04:31
金融系统开发为何必须基于具体业务场景
2026/10/17 9:59:30
基于MP2642GR-Z与ATmega1280的两串电池主动均衡方案设计与实战
2026/10/17 13:40:25
Qt、libtorch、OpenCV集成安装与CMake配置实战指南
2026/10/17 13:40:25
SAP电子签名本质:业务语义绑定与GxP合规控制点
2026/10/17 13:40:25
Linux服务器安装Oracle全流程指南:从系统准备到数据库建库
2026/10/17 13:40:25
0代码搭应用:宜搭从入门到实战,零基础也能搭建企业应用
2026/10/17 13:40:25
AI落地失败根因:人才先行怎么做?从技能矩阵到考核激励
2026/10/17 13:35:25
前端学习底层逻辑:从解决问题出发,构建稳固技术地基
2026/10/17 0:02:58
NetSpot 实战:用信道分析与频宽优化解决 Wi-Fi 卡顿
2026/10/17 0:02:58
C++ split() 字符串分割的五种实现与性能实测
2026/10/17 0:02:58
R语言坐标轴范围设置:从xlim/ylim到coord_cartesian的完整指南
2026/10/17 10:00:11
流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南
2026/10/17 10:16:23
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别
2026/10/17 10:16:02
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容
2026/10/17 10:15:50
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/16 18:46:48
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/16 18:46:46
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)