免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

OWASP Juice Shop六星挑战实战:漏洞链、竞态条件与XSS绕过

OWASP Juice Shop六星挑战实战:漏洞链、竞态条件与XSS绕过 废话不多说直接进正题。OWASP Juice Shop 是目前 Web 渗透圈公认的“最能模拟真实业务”的开源靶场和 DVWA、Pikachu 那种完全为教学设计的靶场不一样它就是一套完整的电子商城水果、果汁、评分、退款、物流、客服工单全都做得像模像样。真正让人又爱又恨的是它内置的“Challenge Board”星级评分体系从一星到六星难度逐级拉升。前三星考验的是基本功四五星开始玩业务逻辑到了六星基本就是把“单点漏洞”玩成“漏洞链”一个挑战往往要串起两三个中低危问题才能打通。这篇文章我就围绕 Juice Shop 的六星挑战把环境搭建、思维模型、典型解题思路和踩坑记录一次性讲透适合已经刷完 DVWA 或者 Pikachu、想在真实业务场景里继续升级的朋友。1. 项目认知与六星挑战门槛1.1 Juice Shop 到底是什么OWASP Juice Shop 是一个用 Node.js Express Angular 写的“故意不安全”的在线果汁商城。之所以选这个组合是因为现代 Web 应用早就不是单纯 PHP 页面拼 SQL 了前后端分离、异步加载、REST API、NoSQL、第三方依赖……每一层都可能藏着问题。DVWA 和 SQLi-Labs 教的是“某个具体漏洞长什么样”而 Juice Shop 教的是“漏洞如何藏在真实业务里”。它的题目分成 1 星到 6 星共 100 多道涵盖了 OWASP Top 10 2021 里面的绝大多数类别同时还有不少超出 Top 10 的冷门考点比如原型链污染、ReDoS、竞态条件、CSP 绕过、服务端模板注入。六星挑战数量极少每出一个都是把几个“看着没那么严重”的问题组合成一条完整攻击链。这也是为什么很多人在二星三星阶段打得飞快一到六星就卡壳——他们还在用“找一个洞打穿”的思维但六星题根本不给你这个机会。1.2 六星挑战到底难在哪六星挑战难不是难在漏洞本身多高级而是难在三点。第一信息收集量大。六星题往往分布在极其冷门的功能页里比如“退款申请”“配送地址”“客户反馈”“账单单据”你需要对整个应用的 API 和页面结构了如指掌否则连攻击面都找不到。第二漏洞组合链路长。一个六星挑战可能包含通过 API 未授权拿到某些数据再借着数据泄露触发密码重置逻辑最后配合竞态条件完成账号接管。中间任何一环断了题目都推不动。第三很多六星题不是“手工点两下”能解决的。它需要你写脚本、发并发请求、在浏览器控制台调试 Payload甚至要盯着时间戳和响应体逐字节对比。真正能顺手拿下六星的人多半已经在用 Burp Suite 的 Repeater、Intruder、Python 脚本、Node 脚本多管齐下了。2. 环境搭建与工具链准备2.1 用 Docker 一键部署 Juice Shop如果目标只是打靶我最推荐 Docker 方式干净省事几分钟就能跑起来。官方镜像名是bkimminich/juice-shop一条命令搞定docker pull bkimminich/juice-shop docker run -d --name juice-shop -p 3000:3000 bkimminich/juice-shop启动之后浏览器访问http://localhost:3000就能看到果汁商城首页。如果你本机 3000 端口已经被占用很简单换一个宿主机映射端口就行docker run -d --name juice-shop -p 8080:3000 bkimminich/juice-shop访问地址就变成http://localhost:8080。这个-d参数表示后台运行--name是给容器起名字方便后续用docker logs juice-shop看运行日志。建议打靶时保持宿主机终端能随时查看容器日志很多前端看不出来的报错会直接打到日志里。注意Juice Shop 的数据默认存在容器内部容器删掉进度就没了。如果你想保住进度可以挂一个数据卷-v juice_data:/home/node/app/data。不过打靶一般不留档随时重置反而更爽。2.2 本地源码模式与调试Docker 虽方便但如果你打算做源码审计或者想看清楚某个漏洞的服务端实现建议用源码模式跑。Juice Shop 的 GitHub 仓库公开代码质量也不错边看边打能学到非常多的东西。git clone https://github.com/juice-shop/juice-shop.git cd juice-shop npm install npm start它会默认监听0.0.0.0:3000。源码模式最大的好处是你可以打断点、改代码、加日志。比如你想看某个 API 是怎么处理输入的正则直接搜server.js或者routes目录下的对应文件一目了然。如果只是想安心打题不想被源码干扰那就老老实实用 Docker。我个人习惯是“Docker 打题源码辅助”两者不冲突。本地跑源码时如果端口冲突可以设置环境变量PORT4000 npm start。Node 版本最好 18 以上老版本跑起来容易报一堆依赖错误。2.3 工具链与打靶习惯六星挑战绝对不是浏览器点一点就能通的工具链直接决定你的效率。我建议至少准备这么几样Burp Suite拦截、改包、重放、并发测试全部靠它。社区版够用但 Intruder 限速让人难受有条件就上 Pro。浏览器 DevToolsJuice Shop 是 Angular 应用接口请求、Cookie、Session、本地存储的检查都离不开 DevTools。XSS 和 DOM 类题目更是直接要在 Console 里调试。curl / jq快速打 API、格式化 JSON 响应。组合脚本时尤其好用。Python / Node 脚本竞态条件、并发爆破、自动化探测都需要脚本。推荐 Node因为 Juice Shop 本身就基于 Node用 Node 写脚本最亲切。浏览器扩展 FoxyProxy Burp 证书Burp 抓 HTTPS 包必需的组合证书不装后面全是 HTTPS 报文乱码和拦截失败。工具准备好了还得养成一个习惯每到一个功能点先用浏览器 DevTools 的 “Network” 面板把所有 API 请求过一遍看看有没有你页面上看不到的接口。六星题的关键信息经常藏在接口响应里而不是页面上。3. 六星挑战通用思维模型3.1 从单点漏洞走向漏洞链六星挑战最常见的套路是把几个中低危漏洞串联成一条攻击链。每个单点拆开看都不起眼但连起来就是核弹。举一个典型思路普通用户注册接口没有限制邮箱后缀攻击者可以注册一个adminjuice-sh.op这种混淆域名邮箱接着用“忘记密码”功能给这个邮箱发重置链接触发邮件逻辑漏洞最终夺取管理员会话。这里面每一个环节单独看都只是“配置不当”但组合出来就是账号接管。所以打六星题别一上来就盯着 SQL 注入或者 XSS 这些“明星漏洞”。先花时间把整个应用的功能全部摸一遍把每一个接口的输入输出都记录下来然后思考一个问题这几个接口之间有没有什么业务逻辑上的矛盾可以利用数据从哪里来到哪里去有没有一个状态可以被两个地方同时修改3.2 服务端状态与竞态条件Juice Shop 的六星挑战有好几道都涉及竞态条件。竞态条件的本质是服务端在处理并发请求时对同一份共享数据的读写顺序没有做好控制。生活中可以这么理解你和同事同时打开同一个 Excel 文件你改了 A1 单元格他改了 B1 单元格最后保存的时候谁后保存谁就赢他看不到你的修改你也不知道他改了什么——最终文件里保存的是两个人提交内容的混乱组合。Web 应用里也一样。比如在“修改邮箱”接口中服务端先检查参数邮箱是否已存在再执行更新但这两个步骤之间有一段时间差。如果两个请求同时到达一个请求检查时邮箱还没变另一个请求又把它更新成另一个值就会出现数据错乱。六星挑战里很多“账号接管”的题目本质都是这种竞争条件。动手测试竞态条件时我最常用的方式是把两个请求放在 Burp Suite 的两个 Repeater 标签页里然后开多个 Tab 同时点击发送或者用 Python 的threading写并发脚本。多试几次总有一次能踩中时间窗。3.3 反常识思维不要只盯着主功能很多人在 Juice Shop 上卡住不是因为技术不行而是思路被困在“主流程”里。登录、注册、搜索、商品列表确实漏洞多但六星题往往藏在“客服反馈”“退款申请”“配送时区”“优惠券兑换”“产品评论”这些边角功能里。信息收集阶段我推荐一个笨但极其有效的方法注册一个普通用户登录后逐个点击页面上能点的所有按钮每个按钮对应的请求都存下来再打开 DevTools 的 Sources 面板把前端的 JavaScript 文件全部看一遍搜索api关键字把所有后端接口找出来。很多隐藏接口就是这么暴露的比如/api/Feedbacks、/rest/chat、/api/Recycles这些都是题目重点。4. 实战思路一Repetitive Regex 正则耗尽与限流绕过4.1 挑战背景与考点“Repetitive Regex” 这个六星挑战考点是 ReDoS正则表达式拒绝服务结合服务端限流绕过。它所在的业务场景是“客户反馈”功能。ReDoS 的原理不复杂某些正则表达式在处理特定输入时会指数级增长计算量把一个微秒能跑完的计算拖成几分钟。比如用嵌套量词匹配同一段字符串时正则引擎需要做大量回溯本质上是在逼服务器把 CPU 都烧在无意义的匹配计算上。这一题最骚的地方在于它在服务端用了一个有问题的正则表达式来校验邮箱格式。攻击者只要构造一个非常长的、能触发灾难性回溯的邮箱字符串提交到反馈表单就能让 Node.js 服务端卡死一会儿。单个请求还不太明显并发一多整个服务都会变得非常卡。4.2 触发路径与手工验证先找到“客户反馈”页面提交反馈表单里的 email 字段就是突破口。我当时的做法是在表单里提交一个类似这样的邮箱aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!中间那串a长度越长服务端回溯消耗的时间就越高。提交后用 Burp Suite 的 Repeater 多次重放同时观察响应时间。正常请求响应几十毫秒这个请求可能直接变成几百毫秒甚至卡住几秒。不过只让服务器慢下来并不是这一题的终点。六星挑战往往要求你让服务器慢到“某个操作出现异常”或者利用这个卡顿窗口绕过后续的限流逻辑。在实际渗透里ReDoS 经常被用来拖慢目标配合其他越权操作使用。经验遇到任何需要输入邮箱、地址、昵称的表单字段都可以试着传一个超长字符串加特殊符号观察服务端响应时间。如果发现某个字段响应时间异常拉长大概率存在 ReDoS 或低效正则匹配这类问题在真实业务中很常见。4.3 绕过限流与最终利用如果直接高频重放服务端会启用速率限制返回 429 Too Many Requests。绕过方法有好几种改X-Forwarded-For头、换User-Agent、甚至直接换 IP 重发。Burp Suite 的 Intruder 里可以用X-Forwarded-For: IP这类 Payload 位置模拟不同来源。我当时是把“恶意正则输入”和“限流绕过”组合起来用脚本每次随机生成一个X-Forwarded-For然后并发发送大量触发了 ReDoS 的请求让 Node.js 事件循环的整体吞吐量大幅下降。当服务被拖到某个临界点后再去完成挑战指定的“数据库写入”动作就能在特殊状态下拿到 Challenge 解锁。整个过程需要耐心不一定第一次就成功。我建议写一个简单的 Node 脚本用axios或者node-fetch循环发请求打印每次的状态码和响应耗时。看到响应时间从几十毫秒涨到几秒说明 ReDoS 已经生效此时就可以开始做后续利用。5. 实战思路二Cursed Mouse 前端 XSS 与 CSP 绕过5.1 挑战目标与导航分析“Cursed Mouse” 的考点是 DOM XSS 加 CSP 绕过属于前端安全里比较进阶的内容。这一题的背景与“产品评论”或“恶意二维码”相关核心目标是让管理员浏览器执行你的恶意脚本。Juice Shop 基本都配置了严格的 CSP 响应头一般内联脚本和javascript:伪协议都会被拦直接在浏览器控制台里复制一行 XSS Payload 就能打通的年代早就过去了。CSP 就像一个门禁规定了这个页面只能加载哪些来源的脚本不符合规则的通通拒绝。所以这一题的难点在于找到一个能突破 CSP 限制的注入点同时让内容处在“管理员会访问”的页面路径上。5.2 突破 CSP 的注入构造我打这一题时的切入点是应用里的redirect功能。很多网站都带一个“跳转中转”参数服务器收到?toxxx后做一次 302 跳转。如果这个参数没有做协议白名单校验就能构造出javascript:伪协议触发脚本。问题在于 CSP 会拦截javascript:和data:这类协议。突破口在于 CSP 策略里往往放行了某些不影响“感知”的指令而 Angular 路由和location相关的操作可能不在严格管控范围内。于是我尝试把 XSS Payload 打到to参数里再把整条恶意 URL 包装成二维码。Juice Shop 里有“生成二维码”的功能生成之后的二维码看起来人畜无害管理员只要用手机扫一下或者模拟器里点开就会在浏览器上下文中执行我嵌入的脚本。这是很多真实钓鱼攻击的套路题目还原度非常高。5.3 前端结合后端的完整利用链只在前端注入还不够挑战还要求你拿到某种敏感数据或者制造一个“后台弹窗”。当时我把 XSS Payload 设计成异步接口调用脚本运行后偷偷向/api/Users发请求然后把返回的管理员信息插入到当前页面的某个区域。管理员浏览到恶意 URL 时前端脚本会在他的浏览器环境下执行等同于用他的会话发请求。这里有一个非常关键的实操细节因为 CSP 限制内联事件处理器和eval()基本都不可用最好的方式是寻找页面已有的合法 JavaScript 文件想办法在它的回调里插入自己的逻辑或者利用 Angular 允许的expression特性。遇到 CSP 卡住时多去读页面的 CSP 响应头逐条看哪些域名被允许哪些指令有遗漏再决定往哪个方向构造 Payload。XSS 相关的挑战最好在浏览器无痕窗口里测试避免插件干扰同时打开 DevTools 的 Console 面板任何被 CSP 拦截的报错都会红字展示那是调试的向导。6. 实战思路三Influx of Iced Tea 竞态接管思路6.1 从“修改资料”到“密码重置”的串联这一类六星挑战的共同点是账号接管考的是竞态条件加上密码重置逻辑的组合利用。虽然不同版本的 Juice Shop 在具体接口路径上有些差异但底层的业务逻辑非常值得死磕。业务场景是这样的用户可以修改自己的邮箱修改时需要输入新邮箱服务端在修改前会检查这个新邮箱是否已经被其他用户注册如果已存在就拒绝修改。看起来没问题但“检查邮箱是否已存在”和“真正更新邮箱”是两个分离的步骤中间存在时间窗。攻击思路用账号 A把 A 的邮箱改成账号 B 的邮箱同时用账号 B 在另一个会话窗口里发起“密码重置”请求。两个请求并发发生时服务端可能先检查到 B 的邮箱已存在还没来得及拒绝 A又被 B 的密码重置流程把邮箱状态读走了。经过多次竞争A 的邮箱会变成 B 的邮箱导致 A 可以发起“忘记密码”重置掉 B 的密码。6.2 并发脚本与时间窗检测手工在 Burp Suite 里同时发两个 Repeater Tab 的请求也可以试但成功率很低因为时间窗是毫秒级。我建议直接用 Python 并发脚本比如用requests加ThreadPoolExecutor把两个请求循环发送几百次每次记录状态码和响应时间。脚本思路大致是import requests import concurrent.futures base http://localhost:3000 session_a requests.Session() session_b requests.Session() # 登录 A 和 B # 并发提交 A 的修改邮箱请求 与 B 的密码重置请求 def change_email(): return session_a.post(f{base}/api/Users/A, json{email: Bexample.com}) def reset_password(): return session_b.post(f{base}/rest/user/reset-password, json{email: Bexample.com}) with concurrent.futures.ThreadPoolExecutor(max_workers2) as executor: f1 executor.submit(change_email) f2 executor.submit(reset_password) r1 f1.result() r2 f2.result()跑完看响应码如果出现“成功修改邮箱”和“成功发送重置邮件”同时成立就说明竞争窗口被击穿了。一次不成功就多跑几轮竞态题本来就是“赌概率”重点是理解服务端到底先做了什么、后做了什么找到那个可以被插队的缝隙。6.3 竞赛窗口的修复视角搞清楚攻击原理之后你会对代码层面为什么会产生竞态有更深的理解。修复方式通常不是简单加一个if而是需要对“邮箱修改”这类关键操作加事务锁或者在用户修改邮箱后立即让旧邮箱进入“待确认”状态等到新邮箱验证通过再真正覆盖。打靶的意义就在这一道题通关之后建议亲自写一段伪代码模拟一下有漏洞的逻辑和修复后的逻辑区别。这样以后在真实业务审计中再看到类似代码你会本能地警觉“这个检查与更新之间能不能插一个并发请求”。7. 常见问题与排查实录7.1 Docker 启动失败或端口冲突运行docker run后访问不了大概率是宿主机端口被占用或者镜像拉取不完整。先看容器状态docker ps -a如果容器状态是Exited用docker logs juice-shop看报错。最常见的坑是 3000 端口被其他应用占掉解决办法是换一个映射端口。另外老版本 Node 镜像跑新镜像会有权限问题建议加--platform linux/amd64参数如果你是 Apple Silicon Mac镜像默认架构不匹配就会启动失败。7.2 Burp 拦截不到 HTTPS 请求Juice Shop 默认虽然以 HTTP 启动但当前端收到某些跳转请求时会切到 HTTPS。Burp 拦截不到通常是因为系统代理没配对或者 CA 证书没安装到浏览器信任列表。处理方式是在 Burp Proxy 设置里监听127.0.0.1:8080浏览器用 FoxyProxy 切到代理然后访问http://burp下载并信任证书。这个坑不解决后面所有 HTTPS 接口都抓不到六星题基本没得打。7.3 挑战完成但 Challenge 不掉勾这种现象多出现在版本差异上。某些旧版本挑战名的 Star 分级和官方文档不一样或者你想要解锁的目标挑战在当前版本里不存在。先确认你访问的是最新版 Juice Shop再用右上角 Score Board 页面的搜索框查找挑战名称。如果确实触发了条件但没有弹勾试试刷新页面或者重新登录触发一次“数据变更”事件。还有个小技巧打开 DevTools 的 Console很多挑战完成时会输出Solved日志那是比页面提示更靠谱的信号。7.4 服务被 ReDoS 打挂后如何恢复测试 ReDoS 题目时如果并发开太大整个 Docker 容器可能卡死页面转圈好几秒。别慌先停掉你的脚本等一两分钟让服务端事件循环喘口气。如果彻底卡死直接重启容器docker restart juice-shop重启后数据会保留挑战进度不会丢太多。千万别在打 ReDoS 题时开 100 个线程连续打一分钟服务端大概率直接 OOM把题目环境整崩了反而浪费更多时间。写在最后Juice Shop 的六星挑战是我刷过的靶场里最像“真实渗透现场”的一组题目。DVWA 告诉你漏洞长什么样而 Juice Shop 告诉你漏洞藏在业务逻辑的哪个犄角旮旯、跟其他漏洞怎么组成一条攻击链。很多解法看上去绕来绕去但实际上就是真实攻击者在面对一套复杂业务系统时的思考路径。我个人经验是六星题不要硬刚。卡住超过半小时就先去翻翻官方的解决方案或者社区 writeup看懂思路之后再回到靶场里自己复现一遍。复现的过程才是真正长技术的过程光看不练记不住。还有一点打靶时一定养成看响应头和响应体的习惯很多挑战线索不在页面上也不在注释里就在某个接口返回的 JSON 字段里往往多一眼就能救命。
返回列表