【juice-shop】★★★ API-only XSS:绕过前端直接调用 API 实施存储型 XSS
目录
【juice-shop】★★★ API-only XSS:绕过前端直接调用 API 实施存储型 XSS
0x01 任务简报
💡 提示 (Hints)1. 需要直接调用服务器端 API,通过 API 尝试不同的 HTTP 动作以暴露不同实体。
2. 一个包含已知数据实体及其在 API 中支持的 HTTP 操作动词的矩阵可为你提供帮助。
3. 粗心的开发人员可能暴露了客户端根本不需要的 API 方法。
0x02 实战:复现漏洞
🔍 第一步:API 枚举
这个挑战需要寻找前端没有暴露的 API 接口,使用 FindSomething 插件收集到以下接口:
/api/Addresss
/api/BasketItems
/api/Cards
/api/Challenges
/api/Challenges/?key=nftMintChallenge
/api/Complaints
/api/Deliverys
/api/Feedbacks
/api/Hints
/api/Products
/api/Quantitys
/api/Recycles
/api/SecurityAnswers
/api/SecurityQuestions
/api/Users
🌐 第二步:探测目标接口
使用 curl 逐个访问接口(默认 GET 方法),发现 /api/Products 返回了所有商品列表,将其作为目标。
❯ curl 127.0.0.1:3000/api/Products | python -m json.tool
虽然题目要求不使用前端,但不能被条件完全框住。
我们使用burp的内置浏览器,访问 http://127.0.0.1:3000/api/Products 将对应的请求加入到重放器里


⚙️ 第三步:探测支持的 HTTP 方法
发送 OPTIONS 请求,获取该接口支持的所有请求方法:
GET,HEAD,PUT,PATCH,POST,DELETE

逐一测试各方法:
- PUT — 报错
Error: Unexpected path: /api/Products,无法使用 - POST — 报错
UnauthorizedError: No Authorization header was found,缺少鉴权
🔑 第四步:获取管理员 Authorization
我们使用之前的Login Admin挑战获取一下 Authorization ,直接用admin防止权限不足(这里使用burp内置浏览器,便于捕获本地包)。

将 Authorization 添加到 Burp Repeater 的请求头中,重新发送 POST 请求。

发送成功,响应中出现了新商品,确认该接口为商品添加接口。

💉 第五步:构造 XSS Payload
整理关键信息:
XSS 有效负载(来自题目描述):
<iframe src='javascript:alert(`xss`)'>接口返回的 JSON 结构:
{
"status": "success",
"data": {
"id": 49,
"updatedAt": "2026-04-06T13:25:59.899Z",
"createdAt": "2026-04-06T13:25:59.899Z",
"name": null,
"description": null,
"price": null,
"deluxePrice": null,
"image": null,
"deletedAt": null
}
}关键请求头(上传 JSON 数据时必须添加 Content-Type):
Authorization: Bearer <admin_token>
Content-Type: application/json将 XSS 有效负载注入商品的 description 字段,构造并发送 POST 请求。

✅ 第六步:完成挑战
访问 http://127.0.0.1:3000/#/search,翻到最后一页,找到通过 API 添加的商品,点击后 XSS 弹窗触发。


挑战完成!
吐槽
这个挑战因为一些细节粗心,花费了半天时间,我认为这个挑战是非常考验细节的,3 星有点低啊(雾
最后构建 payload 的时候注意不要少符号,容易搞坏这个 API,发现 GET 访问
/api/Products报错的时候直接重启环境(