ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Web安全入门:从Referer伪造到MD5绕过实战解析

2026/9/14 1:29:28 拓冰建站 浏览量
Web安全入门:从Referer伪造到MD5绕过实战解析 第一次在Bugku上刷到“你从哪里来MD5”这道Web题时我其实没太当回事。题目名字等于把考点写在脸上了“你从哪里来”指向的是Referer头“MD5”指向的是哈希比较。可真正上手之后我才发现从看懂名字到完整拿到flag之间还隔着不少细节——尤其是MD5比较这一步同一个考点在不同题目里能变出好几种“姿势”稍不留神就会钻进死胡同。这篇文章就围绕这道题把我自己的完整做题过程、中间卡壳的地方以及解题后沉淀下来的一套通用方法论都整理出来给正在刷Bugku Web入门题的朋友做个参考。1. 拿到题目后的第一轮信息收集1.1 题目页面的表面信息这类CTF题不像平时开发的Web项目打开页面通常不会直接给你文档和接口说明而是给一段看似无关紧要的话。我记得当时打开这道题的入口页面画风非常“Bugku风格”一个极简页面几个字提示没有任何多余按钮。这种时候最忌讳的就是盯着页面发呆。我的习惯是先按F12打开开发者工具分三步走看Elements检查页面里有没有隐藏的注释、隐藏表单、被CSS藏起来的div。看Network刷新一下页面观察所有资源的请求与响应重点看有没有非200的状态码、有没有奇怪的自定义响应头。看Sources确认页面有没有加载额外的JS文件。这套操作我称之为“入口三件套”不管题目多简单或多复杂先走一遍永远不亏。Bugku很多Web题属于代码审计类也就是“答案藏在源码里”所以第一步把源码翻个底朝天几乎总是有收获。以这道题为例页面本身的HTML代码非常干净但请求头里有一个Cookie响应里也没有明显异常。真正让思路豁然开朗的是页面正文里那句带暗示性的话——大意是“你不是从那个地址来的我不能给你flag”。这句话基本就把“来源校验”这个考点摆到台面上了。1.2 从HTTP交互细节里读门道信息收集阶段很多人只盯着页面内容忽略了一个关键事实题目叫“你从哪里来”这里的“从哪里来”在HTTP协议里是有标准字段的也就是Referer。Referer字段记录的是“上一个页面地址”也就是用户是从哪个URL跳转过来的。服务器拿到这个字段后可以据此判断请求是否来自某个可信来源。这道题的逻辑大概率是如果你从指定地址来就放行否则拒绝或者把你引到别的页面。这里还需要分清一个容易混淆的点Referer和Origin。Origin字段更多地用于CORS相关的跨域判断只携带协议、域名、端口Referer则包含完整路径。像这类CTF题出题人一般写的是检查Referer是否为某个固定值因为用PHP或者Python读取Referer都比读取Origin更常见。1.3 确认目标这道题到底想考什么走完信息收集后我给这道题起了个内部代号“双考点串联题”。前半段是Referer绕过后半段是MD5绕过。它的设计思路是你带着指定来源的请求访问页面页面在本地再做一个MD5值的比较通过比较才能看到最终flag。这种“一题两关”的设置在Bugku的Web题里不算少。好处是逼着你把多个知识点串起来用而不是背单个payload就完事。做题的时候要对每一步的结果保持敏感改了Referer后页面变化是什么传了某个参数后页面变化又是什么每一步反馈都是在告诉你下一步怎么做。2. “你从哪里来”暗指的是哪个字段2.1 Referer的设计初衷与默认行为聊到Referer得先说说它为什么存在理解了这个你才知道出题人为什么选它。浏览器在请求一个页面时如果这个页面是通过点击链接、表单提交、加载图片或脚本等方式触发的通常会在请求头里带上Referer字段告诉服务器“我是从哪个地方跳转过来的”。比如你在搜索引擎里点了一个链接跳转到目标网站目标网站的日志里就能看到Referer是搜索引擎的页面地址。这个设计最初是为了方便站点统计流量来源后来也被广泛用在防盗链、CSRF防御、来源鉴权等场景。但它有个天然弱点Referer是客户端发送的客户端完全可以伪造。很多“来源校验”之所以能被绕过本质就是这个字段可以被任意篡改。CTF题的常考路线就是让你用抓包工具把这个值改成出题人期望的地址。2.2 用Burp Suite改包最顺手的做题方式我第一次做这道题时用的工具是Burp Suite Community版免费的做题够用。关键配置是开启代理拦截让浏览器请求先经过Burp再由Burp转发到目标服务器。完整操作流程如下打开Burp Suite确认Proxy选项卡里的Intercept开关是打开的。浏览器配置代理为127.0.0.1:8080具体端口看你Burp的设置。刷新目标页面Burp会拦截到请求。在Raw请求头区域找到Referer字段把它改成出题人期望的那个地址。点击Forward转发请求观察页面的返回结果。这里有个细节很容易踩坑Burp默认只拦截浏览器请求如果你用的浏览器之前没装过配套的CA证书访问HTTPS站点会报证书错误。Bugku这类训练平台大多是HTTP协议问题不大但如果你以后做HTTPS的靶场记得先把Burp的CA证书导入浏览器信任列表。我第一次做的时候犯过一个很蠢的错误把Referer改对了但忘了URL编码或改掉了Host头结果请求被服务器识别为畸形请求返回400。排查了半天才发现是自己在Raw区域编辑时不小心删了一个冒号。这类低级失误在CTF做题初期很常见建议每次改完包后先扫一眼Raw数据是不是完整的HTTP语法。2.3 也可以不完全依赖Burp用curl快速验证Burp虽然功能强大但如果只为了改一个Referer用curl反而更轻快。尤其是你已经大致知道考点的情况下一条命令就能验证猜想。比如出题人要求从https://www.bugku.com这个地址跳转过来那么curl命令可以这样写curl -v \ -H Referer: https://www.bugku.com \ http://目标题目地址/加了-v参数后curl会打印完整的请求和响应头方便你确认自定义的Referer有没有被正确带上以及服务器返回了什么新内容。如果第一关过了页面往往会在响应正文里给出下一步的提示比如要求GET一个名为a的参数。用curl的好处是脚本化容易写个循环就能批量尝试不同的Referer值缺点是不能可视化地看到页面渲染效果。我个人习惯是前期用Burp做交互式探测确定思路后改用curl或Python脚本做最终验证效率更高。3. MD5比较绕过弱比较与强比较两条路3.1 代码逻辑分析是绕不开的坎过了Referer这一关后页面提示开始围绕“MD5”做文章。以我在Bugku上遇到的版本页面通常会让你提交一个参数比如?keyxxx服务端会拿这个参数的MD5值跟一个已知MD5值做比较。要绕过这类检查你必须先搞清楚服务端比较用的是弱比较还是强比较。这两种比较规则在PHP里差别极大也因此产生了两种完全不同的绕过思路。题目源码表面上是看不到的但你可以通过后端的“反馈”来判断。比如你随便传一个数字或字符串页面显示“md5校验失败”这时候可以依次尝试以下Payload?keyQNKCDZO ?key240610708 ?key[]1 ?key[]2如果某个Payload让页面进入了“成功”分支比如显示了flag或者提示进入下一层就说明踩中了正确的比较类型。3.2 弱比较0e开头的魔法字符串PHP的运算符在做比较时如果两个操作数都是字符串PHP会尝试把字符串转换成数值再比较。这导致一个非常经典的漏洞如果一个字符串是0e开头后面全是数字在转换成数值时会被当成0。如果另一个字符串也是0e开头同样会被当成0两者用比较结果就是true。比如if ($_GET[a] $_GET[b]) { echo 相等; }攻击者提交?as878926199abs155964671a经过MD5运算后这两个字符串的哈希值都以0e开头于是弱比较判定相等。实战中常用的一些“0epayload”包括但不仅限于下面这些输入字符串MD5值QNKCDZO0e830400451993494058024219903391s878926199a0e545993274517709034328855841020s155964671a0e342768416822977524524974671057s214587387a0e8482404488305379244658656119042406107080e462097431906509019562988736854这里要注意不同字符串的MD5值都需要逐个验证不能只背一个。题目如果要求两个参数都满足条件你就得准备两个不同的0e字符串否则a和b只是同一个字符串的不同写法服务端如果做了去重判断你依然过不去。这类弱比较的绕过前提是请求参数在服务端经过了MD5运算后字符串以0e开头并且PHP版本和配置不会改变这个运算结果。在常见的PHP 5.x和PHP 7.x版本中这个特性一直存在所以Bugku这类平台才会反复考它。3.3 强比较数组绕过能让也失守如果服务端用的是强比较要求类型和值都相等那0e字符串就失效了因为0e... 0e...虽然可能是true但题目往往要求你传入两个不同的值而且很多题目为了防弱比较会特意在代码里写md5($a) md5($b)甚至要求$a ! $b。这时候依然有绕过方法利用PHP对数组处理时的特性。当$_GET[a]传入一个数组时比如?a[]1PHP的md5()函数会尝试把数组转换成字符串但数组到字符串的转换在PHP里本身是失败的于是md5()会返回NULL。两个数组参数经过md5处理后都是NULL强比较NULL NULL成立。实战中的Payload是这样的?a[]1b[]2注意这里a和b的内容不需要相等只要保证二者都是数组即可因为两者经过md5()后都变成了NULL。即使服务端用了$a ! $b来防“传同一个参数”数组绕过依然有效因为数组是不同的。我在本地测试这个特性的时候写过这样一段PHP代码验证?php $a $_GET[a]; $b $_GET[b]; if (md5($a) md5($b)) { echo flag{fake_flag_for_demo}; } else { echo failed; }用浏览器访问http://127.0.0.1/test.php?a[]1b[]2输出就是“flag”。这个测试环境可以自己搭用XAMPP或php -S都行。3.4 实战中如何判断题目到底用哪种比较做题时你不会看到服务端代码但可以通过“输入输出差异”反推比较类型。我的判断方法是先试0e字符串。如果成功大概率是弱比较。如果0e字符串失败试数组。如果数组成功说明代码里要么是强比较要么是strcmp之类的函数被绕过了。如果数组也失败那问题可能不只是MD5比较还有类型约束比如is_string()检查这时候要回到题目源码思路看看是不是需要走别的入口。有的题目还会把和混着用先做个判断再做判断。这时候你要先满足第一层条件再构造能同时满足第二层的参数。这种情况比较少见但遇到就得多一点耐心逐层验证。4. 完整解题流程复现与踩坑记录4.1 从入口到flag的串联操作当你把Referer绕过和MD5绕过两个知识点都掌握后做这道题就是一个“按步骤拼接”的过程。以我当时的实际操作来完整复现一遍第一步正常访问题目页面观察提示确认需要伪造来源地址。第二步打开Burp的拦截功能刷新页面在请求头中修改Referer为出题人指定的地址。这里指定的地址在页面提示里通常会写明比如“你需要从http://127.0.0.1访问”。我遇到的情况是要求Referer等于http://www.bugku.com这也是题目名里“你从哪里来”最直观的应验。第三步转发请求观察返回内容。页面会提示“很好你的MD5不对”之类的信息这说明第一关已通过进入第二关。第四步拼接MD5参数。根据页面给出的参数名可能是a或key提交Payload。这一步需要你根据刚才3.4节的判断方法确定是弱比较还是强比较。第五步如果是弱比较?keyQNKCDZO如果是强比较?key[]1第六步携带Referer和MD5参数一起提交完整URL类似http://目标题目地址/?key[]1同时请求头带Referer。第七步拿到flag记录题型和思路顺手整理到自己的笔记里。4.2 我第一次做题时卡住的两个地方第一处卡住的是我以为需要把Referer改成题目页面的URL本身结果怎么试都不对。后来才反应过来题目的意思是你得“来自”另一个专门页面而不是当前页面。这个细节如果页面提示不够明确很容易白折腾。第二处卡住的是我一开始只想着改Referer把MD5参数当成了普通参数传了一个字符串就开始乱试忘了这题的核心考的是比较绕过而不是“找出原始字符串”。MD5是不可逆的在CTF题里极少让你“解密”绝大多数情况是让你“绕过比较”。如果你在刷题时把思路导向“找个字符串它的MD5等于给定值”赶紧停下来大概率走错方向了。4.3 本地复现环境搭建与调试建议我建议每个刷Bugku Web题的人都搭一个本地PHP环境因为很多Web题都是PHP代码审计本地写个小脚本测试比较逻辑非常方便。搭建方式很简单安装PHPWindows/Mac/Linux都可以直接用系统包管理器装。在某个目录下创建test.php文件。打开终端进入该目录运行php -S 127.0.0.1:8080。浏览器访问http://127.0.0.1:8080/test.php。这样你不需要完整安装Apache或Nginx瞬间就能起一个调试环境。测试完了直接关掉终端即可。我在本地这么一测才发现0e字符串其实很容易踩坑有些字符串虽然MD5以0e开头但后面可能不是纯数字PHP在比较时不会被识别为0。网上流传的很多“0e payload列表”里偶尔也有不靠谱的务必自己跑一遍验证。5. 这题背后的Web安全学习路线5.1 相似题型的“模板化”打法做完这道题并沉淀下来之后我会给这类题目归一个小类“请求头伪造 参数类型绕过”。以后只要遇到类似场景就可以直接套模板页面给了“从哪来”的提示优先看Referer或Origin。页面试图校验客户端提交的值优先思考PHP弱类型问题。出现md5、sha1这类哈希比较优先尝试0e绕过和数组绕过。出现unserialize、preg_replace这类函数优先考虑反序列化和正则回溯。模板化不是让你死记硬背而是帮你建立“看到某个特征就想到某类攻击”的条件反射。刷题量上来之后你会发现自己做题速度越来越快因为大量题目都是同一套底层逻辑换了个包装。5.2 代码审计能力才是Web题的核心“你从哪里来MD5”这道题表面考的是Referer和MD5本质上考的是代码审计和HTTP协议理解。你会用Burp改包、会传数组但如果不理解PHP的弱类型比较原理不理解服务器如何读取请求头那下次题目变个花样照样不会。所以我的建议是每道题做完后不要急着做下一道花20分钟把题目的核心原理写一遍再用自己本地环境复现一遍最后再尝试回答三个问题如果出题人加一层过滤我该怎么绕过如果从PHP换成Java或Python写法这道题还成立吗这个漏洞在真实业务中会造成什么影响想明白这三个问题你对一道题的理解就远超“拿到flag”本身了。5.3 从Bugku入门到更广阔的CTF世界Bugku的Web题难度梯度做得比较友好像“你从哪里来MD5”这种题非常适合入门。做完这类题你可以继续去刷别的平台的同级别Web题比如类似的CTF练习平台上的入门Web题你会发现很多知识点是相通的。后续可以按这个方向升级从“改Header”升级到“伪造Cookie、JWT”。从“MD5绕过”升级到“哈希长度扩展攻击”。从“GET参数注入”升级到“SQL注入、XSS、文件包含”。每一步都是在前一步基础上的递进。当你能把Request、Response、代码执行、数据存储这几个环节串起来思考时Web安全的大门才算是真正打开了。最后分享一个我个人的小习惯每次做完题我都会把关键Payload和页面反馈截图存到本地按平台、题型、知识点三个维度归档。等刷完几十道题再回头翻你会清晰地看到自己的成长轨迹也能很快定位到哪类知识点是自己的短板。“你从哪里来MD5”这道题就是我笔记里Referer绕过和MD5比较这两个专题的第一个案例。