FEATURED · 精选文章

CTF Web入门实战:F12抓包、JSON篡改与PHP弱类型漏洞利用

发布时间 / 2026/8/10 6:40:09
来源 / 创域科博编辑部
栏目 / 资讯中心
CTF Web入门实战:F12抓包、JSON篡改与PHP弱类型漏洞利用 1. 项目概述一次CTF新手的Web实战演练最近在带新人入门CTFCapture The Flag的Web安全方向发现很多朋友拿到一个题目尤其是那种看起来像是一个正常网页的题目往往不知道从哪里下手。他们知道要“渗透”但面对一个登录框或者一段看似无害的代码常常感到迷茫。这让我想起了当年自己参加SWPUCTF 2021新生赛时遇到的一道非常经典的入门题。这道题没有复杂的框架没有眼花缭乱的漏洞组合但它精准地串联起了Web安全入门必须掌握的三个核心技能点浏览器开发者工具F12的熟练使用、JSON数据格式的理解以及PHP弱类型比较的漏洞利用。可以说吃透这道题你就拿到了打开Web安全大门的钥匙。这道题的目标很明确作为一个CTF新手你需要通过分析网页前端、拦截并修改数据包、理解后端逻辑最终找到隐藏的“flag”通常是一串代表胜利的字符串。整个过程就像一次侦探游戏你需要观察现场网页、寻找线索源码、请求、推理动机后端代码逻辑最后破解谜题。今天我就以这道题为蓝本带你走一遍完整的实战流程不仅告诉你每一步怎么做更会深入解释“为什么要这么做”以及我在实战中踩过的坑和总结的技巧。无论你是完全零基础还是对Web安全有些模糊的概念这篇文章都能帮你建立起清晰的入门路径。2. 核心思路拆解逆向工程与逻辑漏洞挖掘面对任何CTF的Web题目尤其是新生赛难度第一步绝对不是盲目地尝试各种攻击工具。高手和新手最大的区别在于思路。新手的思路往往是“我有什么工具比如SQL注入、XSS”然后往题目上套而高手的思路是“题目给了我什么信息”然后顺着信息链去推理可能存在的脆弱点。这道SWPUCTF 2021新生赛的题目就是一个典型的“信息给予型”题目。2.1 题目环境与初步观察通常CTF题目会提供一个访问链接。我们拿到链接后第一件事就是用浏览器打开它进行最基础的“肉眼观察”。你看到的可能是一个极其简单的页面也许只有一段文字、一个输入框、一个按钮。这道题当时呈现的很可能就是一个要求你输入某些内容并进行提交的界面。这里的第一步操作毫无技术含量但却至关重要仔细阅读页面上每一个字。题目名称、提示文本、按钮文字、甚至页面标题浏览器标签页上的文字都可能隐藏着关键信息。比如题目名“jicao”可能暗示了某些特性虽然在这道题里它更像一个随机标识而任何关于“json”、“true/false”、“比较”的词汇都应该立刻在你脑海里亮起红灯。在初步观察后我们立刻要祭出Web安全分析的第一神器浏览器开发者工具也就是按F12打开的那个面板。很多新手知道F12但只用来“看个大概”。实际上F12是我们与网页进行深度对话的窗口。我们需要系统性地检查以下几个面板Elements元素查看HTML和CSS源码。这里要寻找隐藏的表单input typehidden、被注释掉的代码!-- --、以及JavaScript代码。有时flag或者关键逻辑就直接写在页面的注释里。Console控制台查看JavaScript错误和信息输出。有些题目会故意在前端代码里留下console.log()语句输出调试信息这可能是重要线索。Sources源代码查看页面加载的所有静态资源文件HTML, JS, CSS。这里可能存放着独立的JavaScript文件其中包含了核心的业务逻辑。Network网络这是重中之重。它记录了浏览器与服务器之间所有的网络请求。我们需要在这里观察当我们在页面上进行一次操作比如点击提交按钮时浏览器具体向服务器发送了什么请求Request以及服务器返回了什么响应Response。请求中包含了方法GET/POST、URL、请求头Headers和最重要的——请求体Payload。响应中则包含了状态码、响应头和服务器返回的数据。2.2 逻辑漏洞的切入点数据流分析通过F12的Network面板我们能够清晰地看到一次交互的数据流。对于这道题关键通常在于提交数据到服务器服务器进行某种判断然后返回结果。我们需要搞清楚提交了什么数据是以什么格式发送的是普通的表单application/x-www-form-urlencoded还是JSONapplication/json参数名是什么判断逻辑是什么服务器如何验证我提交的数据这里就需要我们根据返回的结果、页面的变化甚至结合前端JavaScript代码去猜测后端的处理逻辑。返回了什么服务器是直接返回了flag还是返回了一个提示如“错误”或者进行了页面跳转这道题的核心考点之一就是JSON。如果你在Network面板里看到请求头中的Content-Type是application/json或者请求体是一段像{key: value}这样的文本那么就可以确定后端在期待接收JSON格式的数据。JSON是一种轻量级的数据交换格式在Web开发中极其常用。作为攻击者我们需要能够熟练地手动构造和修改JSON数据。而另一个核心考点PHP弱类型则通常隐藏在后端的判断逻辑里。我们可能通过前端的线索或者通过简单的测试比如提交一个数字和一个字符串发现后端在比较数据时行为“怪异”。这种“怪异”往往就是PHP弱类型比较漏洞在起作用。所以整体的解题思路链条就清晰了F12观察发现JSON交互 - 修改请求构造特定JSON数据 - 触发后端弱类型比较逻辑 - 绕过验证获取Flag。接下来我们就深入到每一个环节的细节中去。3. 工具与技能深度解析F12、JSON与PHP弱类型在动手解题之前我们必须把这三件“兵器”摸透。知其然更要知其所以然这样以后遇到变种题目才能举一反三。3.1 F12开发者工具的实战技巧按F12打开开发者工具后不要被密密麻麻的选项吓到。对于CTF Web题我们主要与以下几个功能打交道Elements面板的搜索功能在Elements面板中按CtrlF可以打开搜索框。你可以搜索关键词如“flag”、“password”、“admin”、“sql”、“md5”等有时能直接定位到隐藏信息。Network面板的保留日志与节流Preserve log保留日志勾选这个选项。否则当页面发生跳转比如提交表单后跳转到新页面时之前的网络请求记录会被清空你将丢失关键的提交请求记录。这是新手最容易忽略的一点我当年就因此反复重做了好几次。Disable cache禁用缓存勾选此项确保每次都能从服务器加载最新资源避免浏览器缓存干扰你的分析。Filter过滤在Network面板顶部你可以过滤请求类型比如只显示XHR或Fetch请求这能快速筛选出由JavaScript发起的、与服务器进行数据交互的异步请求对于分析API接口非常有用。修改请求并重发Replay这是F12最强大的攻击功能之一。在Network面板中找到你想要修改的请求通常是提交数据的那个POST请求右键点击它选择“Copy - Copy as cURL”。然后你可以将这个cURL命令粘贴到命令行中或者使用一些工具如Postman、Burp Suite来重放和修改。但更直接的方法是右键请求选择“Edit and Resend”。这时你可以直接修改请求的URL、请求头、特别是请求体Payload修改后点击“Send”即可发送修改后的请求。我们后续对JSON数据的篡改主要就在这里进行。注意有些题目会设置前端JavaScript验证。你在页面上输入非法内容可能直接被前端的JS代码拦截请求根本不会发到服务器。这时你需要先在Elements面板里找到并分析这段验证JS或者更粗暴一点直接使用“Edit and Resend”功能绕过前端直接与后端对话。3.2 JSON数据格式与篡改方法JSON看起来简单但在CTF中玩弄它需要一些精确性。基本结构对象{} 数组[] 键值对key: value。字符串必须用双引号括起来数字和布尔值true/false不用。在CTF中的常见玩法键值对注入后端可能直接使用json_decode()将你提交的JSON字符串转为PHP数组然后使用类似$data[key]的方式取值。如果后端未做严格过滤你可能通过注入额外的键值对来影响程序逻辑。例如原始请求是{user: guest}你可以尝试改为{user: guest, admin: true}看看后端是否会对admin字段进行特权检查。类型混淆这是利用PHP弱类型的前奏。例如后端代码可能是if ($json-key admin)。如果你提交{key: admin}这是字符串比较。但如果你提交{key: true}或{key: 0}在弱类型比较下可能会产生意想不到的结果。数组与对象转换在PHP中json_decode()的第二个参数如果为true会将JSON对象解码为关联数组如果为false默认则解码为PHP的stdClass对象。有时程序对数组和对象的处理方式不同可能造成漏洞。如何修改在F12的“Edit and Resend”中找到请求体Request Payload直接修改其中的JSON文本即可。务必注意JSON格式的正确性一个多余的逗号或缺少一个引号都会导致解析失败服务器可能返回“无效请求”的错误。可以先用在线JSON格式化工具校验你的修改。3.3 PHP弱类型比较漏洞原理详解这是本题的核心考点也是PHP语言一个“声名远扬”的特性。什么是弱类型比较在PHP中操作符在比较两个变量时会先尝试进行类型转换使它们具有相同的类型然后再比较值。这种比较方式非常松散。与严格比较的区别操作符要求比较的两个变量不仅值相等类型也必须相同。它是严谨的。经典的“魔法”案例 让我们来看一些在CTF中高频出现的弱类型比较“魔法”admin 0结果为true。为什么字符串admin在参与数值比较时会被强制转换成整数。转换规则是从字符串开头读取数字直到遇到非数字字符为止。admin开头是字母因此被转换成整数0。所以0 0成立。123abc 123结果为true。字符串123abc转换成整数是123。1e9 1000000000你可能以为这是字符串比较但用时PHP发现它们像数字会转换成数字再比。1e9是科学计数法等于1000000000所以成立。true any non-empty string结果为true。布尔值true在比较时非空字符串通常会被视为true。null false结果为true。0e12345 0e67890结果为true这是一个超级经典的漏洞。字符串0e12345和0e67890在PHP看来都是科学计数法表示的00乘以10的N次方还是0。当它们被比较时会被转换成数字0于是0 0成立。但用比较因为它们是不同的字符串结果为false。这个特性常被用于绕过MD5哈希比较如果两个不同的字符串的MD5哈希值恰好都是0e开头的数字字符串。在题目中的应用 后端代码可能会这样写$data json_decode($_POST[input]); if ($data-password secret_password_123) { echo $flag; } else { echo Wrong Password!; }看起来你需要知道密码secret_password_123。但利用弱类型如果你提交{password: true}那么比较就变成了true secret_password_123。一个非空的字符串在弱类型比较中会被视为true所以条件成立你就能拿到flag 另一种常见情况是密码的MD5哈希值与某个值比较。例如if (md5($_POST[password]) 0e123456789012345678901234567890) { echo $flag; }你需要找到一个字符串其MD5哈希值也是0e开头后面全是数字。这样在比较下两个0e...的字符串都会被当作数字0从而相等。4. 实战解题过程复现与深度操作现在让我们把理论付诸实践。虽然我无法还原原题的确切界面但我们可以构建一个高度近似的模拟场景并一步步推演攻击过程。假设题目页面有一个输入框让我们提交一个“口令”旁边有一个提交按钮。4.1 第一步信息收集与侦察打开题目页面浏览器访问提供的URL。查看页面源码右键 - 查看页面源代码或者按F12打开Elements面板。快速浏览HTML寻找注释、隐藏输入框、内联JavaScript。假设我们找到一段注释!-- 后端期待接收JSON格式数据例如{pass: your_input} --关键信息获取后端需要JSON格式并且键名可能是pass。尝试交互并抓包在输入框里随意输入一些内容比如test123点击提交按钮。立刻切换到F12的Network面板。确保“Preserve log”已勾选。你应该能看到一个新的请求记录方法通常是POST名称可能和当前页面URL一样。点击这个请求查看“Headers”和“Payload”。分析请求Headers查看Content-Type确认是application/json。Payload看到请求体正是{pass: test123}。这验证了源码注释的提示。Response查看服务器返回了什么。假设返回了一个JSON数据{msg: Wrong! Try again.}。至此我们摸清了交互模式前端收集输入将其包装成{pass: 输入值}的JSONPOST给后端后端校验后返回一个JSON消息。4.2 第二步猜测与测试后端逻辑现在我们需要猜测pass这个值在后端经历了怎样的判断。返回“Wrong”说明我们没通过。常见的校验逻辑有哪些简单字符串匹配if ($data[pass] 某个固定字符串)MD5哈希匹配if (md5($data[pass]) 某个MD5哈希值)弱类型比较if ($data[pass] 某个值)或if (md5($data[pass]) 某个值)如何测试利用F12的“Edit and Resend”功能。测试1尝试弱类型true。在Network面板中右键点击刚才的POST请求选择“Edit and Resend”。在请求体Payload中将{pass: test123}修改为{pass: true}。注意true是布尔值没有引号。点击“Send”发送。观察响应如果响应变成了{msg: Congratulations! Your flag is: nctf{...}}那么恭喜你直接利用了true “某个非空字符串”的弱类型漏洞。如果还是“Wrong”继续测试。测试2尝试弱类型0或数字。再次“Edit and Resend”修改Payload为{pass: 0}。发送请求。如果后端逻辑是$data[pass] 某个非数字开头的字符串比如admin那么0 admin在弱类型下是true。如果通过则说明是这种模式。测试3测试MD5哈希的0e绕过。如果前两种都没成功很可能是在比较MD5哈希。我们需要构造一个输入使得md5(输入)的结果是0e开头的纯数字字符串。常见的这类字符串称为“魔法哈希”已经被人收集整理。例如md5(240610708) 0e462097431906509019562988736854md5(QNKCDZO) 0e830400451993494058024219903391“Edit and Resend”修改Payload为{pass: 240610708}或{pass: QNKCDZO}。发送请求。如果后端是md5($data[pass]) 0e...这种判断那么md5(240610708)的结果是0e462...它会与后端硬编码的0e...字符串进行比较。根据我们前面讲的原理两个0e开头的字符串在弱类型比较下都等于数字0所以条件成立。如果成功你将获得flag。4.3 第三步获取Flag与流程总结假设我们通过测试3使用QNKCDZO作为pass的值成功收到了包含flag的响应。整个攻击流程总结如下侦察使用F12查看源码和网络请求确定数据交互格式JSON和关键参数pass。分析通过修改请求、观察响应推测后端校验逻辑MD5哈希的弱类型比较。利用利用已知的PHP弱类型“魔法哈希”值如QNKCDZO构造特定的输入使md5(输入)满足0e[0-9]*的格式从而绕过比较。获取发送构造好的恶意请求从服务器响应中提取flag。这个过程完美体现了Web安全测试的基本方法论信息收集 - 逻辑分析 - 漏洞利用。它不依赖于复杂的自动化工具而是考验你对Web基础组件HTTP/JSON和语言特性PHP弱类型的深刻理解。5. 常见问题、拓展场景与防御思考在实际操作中你可能会遇到一些变种或问题。这里我总结几个常见的情况和应对策略。5.1 可能遇到的变种与应对请求不是JSON而是标准表单application/x-www-form-urlencoded怎么办方法完全一样。在“Edit and Resend”中你看到的Payload会是passtest123这种格式。你仍然可以修改pass的值为true或0或QNKCDZO。关键是理解后端如何解析$_POST[pass]这个变量。PHP的$_POST数组本身就会进行类型转换字符串true会被当成字符串但布尔值true无法直接通过表单提交。不过你可以尝试提交pass0。当后端用$_POST[pass] admin判断时字符串0与字符串admin进行弱类型比较0会被转为数字0admin转为数字0结果也为true。所以pass0也是一个常用的测试Payload。题目增加了前端JavaScript验证禁止输入非数字字母怎么办这是前端限制与后端无关。有两种方法绕过方法A禁用浏览器JS。在浏览器设置中临时禁用JavaScript然后提交页面。这样前端验证代码就不会执行。方法B直接抓包改包。这是更通用的方法。你可以在输入框里输入一个合法值如aaa让前端验证通过点击提交。在Network面板中抓到这次请求然后使用“Edit and Resend”功能将Payload中的aaa修改成你真正想提交的Payload如true或0。因为修改请求是直接发生在浏览器网络层完全绕过了前端JavaScript。找不到“魔法哈希”怎么办你可以自己编写一个简单的PHP脚本或Python脚本来暴力碰撞。思路是生成大量随机字符串计算其MD5检查是否以0e开头且后续字符全部为数字。虽然概率很低但对于简单的CTF题目有时跑几分钟就能找到可用的值。这也提醒我们依赖这种“巧合”的哈希值进行身份验证是极度危险的。5.2 从攻击者到防御者的思考作为学习者我们不仅要学会如何攻击更要理解如何防御。这道题暴露出的安全问题在真实开发中应如何避免永远使用严格比较这是铁律。在PHP中进行任何可能涉及用户输入的比较时无论是密码、哈希值还是状态标识都必须使用或!杜绝使用或!。这能从根本上消除弱类型比较带来的隐患。谨慎使用json_decode()使用json_last_error()函数检查解码是否成功避免解析恶意格式JSON导致程序异常。明确指定第二个参数。如果你期望的是数组使用json_decode($input, true)如果期望对象使用json_decode($input, false)。避免类型不确定性。对解码后的数据进行严格的类型检查和过滤。不要想当然地认为用户传来的pass字段一定是字符串。哈希比较的安全方法比较哈希值如密码哈希时应使用PHP内置的hash_equals()函数。这个函数专门用于进行时序攻击安全的字符串比较可以防止基于时间差的旁路攻击同时也避免了类型转换问题。// 正确的做法 $user_input_hash md5($_POST[password]); // 注意md5已不安全此处仅作示例 $stored_hash 0e123...; if (hash_equals($stored_hash, $user_input_hash)) { // 验证通过 }输入验证与过滤在处理用户输入无论是来自JSON、表单还是URL参数之前先定义清晰的数据规范例如pass字段必须是长度在6-20位的字符串然后进行验证。可以使用filter_var()函数或正则表达式。5.3 给CTF新手的进阶建议当你熟练掌握了F12、JSON和PHP弱类型这“三板斧”之后可以尝试挑战更复杂的题目并将这些基础技能组合运用结合文件包含题目可能让你通过JSON传递一个文件名后端用include()包含。你可以尝试利用php://input等伪协议或者进行目录遍历。结合反序列化如果后端对JSON数据使用了json_decode()后再进行某些不安全的操作可能引发对象注入漏洞。结合XSS如果后端将你JSON中的某个字段不加处理地输出到页面上可能造成反射型XSS。你可以尝试构造{name: scriptalert(1)/script}。学习使用专业工具当题目复杂时F12可能不够用。建议学习使用Burp Suite这款专业的安全测试工具。它的Proxy、Repeater、Intruder等功能比浏览器开发者工具更强大可以自动化地修改、重放、爆破请求是Web安全工程师的标配。这道SWPUCTF 2021新生赛的题目就像一本优秀的入门教材它没有用晦涩难懂的技术吓退你而是把最核心、最基础、最常用的知识点串联起来让你在解决一个具体问题的过程中建立起对Web安全测试的初步感觉。记住这个流程观察 - 抓包 - 分析 - 猜测 - 测试 - 验证。把这个流程变成你的肌肉记忆你就在CTF Web入门路上迈出了最坚实的一步。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻