SOAP/JAX-WS ThreadLocal Authentication Bypass
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
摘要
- 一些中间件链将经过认证的
Subject/Principal存储在静态的ThreadLocal中,并且仅在接收到专有的 SOAP header 时才刷新它。 - 由于 WebLogic/JBoss/GlassFish 会回收工作线程,省略该 header 会导致线程上一次处理的具有特权的
Subject被静默重用。 - 用缺少 header 但格式正确的 SOAP body 持续轰击易受攻击的端点,直到被重用的线程授予你被盗用的管理员上下文。
- 2025 年的 HID ActivID/IASP (HID-PSA-2025-002) 是一个真实例子:JAX-WS handler 缓存了一个
SubjectHolderThreadLocal,让未认证的 SOAP 调用继承之前 console/SSP 请求设置的身份。
根本原因
类似下面的 handlers 只在自定义 header 存在时才覆盖线程本地的身份,因此先前请求的上下文会保留:
public boolean handleMessage(SOAPMessageContext ctx) {
if (!outbound) {
SOAPHeader hdr = ctx.getMessage().getSOAPPart().getEnvelope().getHeader();
SOAPHeaderElement e = findHeader(hdr, subjectName);
if (e != null) {
SubjectHolder.setSubject(unmarshal(e));
}
}
return true;
}
侦察
- 枚举 reverse proxy / routing 规则以定位可能屏蔽
?wsdl但接受 POSTs 的隐藏 SOAP 树(将它们与流程在 80,443 - Pentesting Web Methodology 中并列映射)。 - 解压 EAR/WAR/EJB 工件 (
unzip *.ear) 并检查application.xml、web.xml、@WebService注解和处理器链(例如LoginHandlerChain.xml),以发现 handler 类、SOAP header 的 QName 以及后端 EJB 名称。 - 如果元数据缺失,对可能的
ServiceName?wsdl路径进行暴力枚举或临时放宽实验室代理,然后将恢复的 WSDL 导入到像 Burp Suite Wsdler 这样的工具中以生成基线 SOAP envelopes。 - 检查 handler 源码,查找在认证 header 缺失或格式错误时未被清理的
ThreadLocal持有者(例如SubjectHolder.setSubject())。
利用
- 发送包含专有 header 的有效请求,以了解正常的响应码以及针对无效 token 的错误返回。
- 在省略 header 的情况下重发相同的 SOAP body。保持 XML 格式良好并遵守所需命名空间,以便 handler 能干净地退出。
- 循环发送该请求;当请求落到之前执行过特权操作的线程时,被重用的
Subject会解锁受保护的操作,例如用户或凭证管理器。
POST /ac-iasp-backend-jaxws/UserManager HTTP/1.1
Host: target
Content-Type: text/xml;charset=UTF-8
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:jax="http://jaxws.user.frontend.iasp.service.actividentity.com">
<soapenv:Header/>
<soapenv:Body>
<jax:findUserIds>
<arg0></arg0>
<arg1>spl*</arg1>
</jax:findUserIds>
</soapenv:Body>
</soapenv:Envelope>
2025 HID ActivID/IASP 案例研究 (HID-PSA-2025-002)
- Synacktiv 发现 JAX-WS 的
LoginHandler在 ActivID 8.6–8.7 中,当存在mySubjectHeaderSOAP header 或 console/SSP 流量完成认证时,会将SubjectHolder.subject设置为该身份,但当 header 不存在时从不清除它。 - 随后的任何在同一 worker 线程上且缺少该 header 的 SOAP 调用都会继承该缓存的
Subject,从而允许未认证情况下通过诸如UserManager或CredentialManager等端点创建管理员用户或导入凭据。 - 观察到的可靠利用模式:
- 在大量线程上触发已认证上下文(例如,在另一个浏览器标签页向
/ssp发送大量请求或以管理员身份登录/aiconsole)。 - 以高并发向
/ac-iasp-backend-jaxws/UserManager或其他由 EJB 支持的 JAX-WS 端点发送不带 header 的 SOAP 请求洪流;每次命中复用到“被感染”的线程时都会以提升的Subject执行。 - 重复直到返回特权响应;重用 Keep-Alive 连接和较大的 worker 池以最大化线程复用概率。
- 在大量线程上触发已认证上下文(例如,在另一个浏览器标签页向
- Handler 与流程要点:
LoginHandlerChain.xml→LoginHandler.handleMessage()反序列化mySubjectHeader并将Subject存储到SubjectHolder(一个静态的ThreadLocal)。ProcessManager.triggerProcess()随后将SubjectHolder.getSubject()注入到业务流程中,所以缺失 header 会导致陈旧身份保持不变。
- 来自 advisory 的现场 PoC 使用两步 SOAP 滥用:先用
getUsersleak 信息,然后在特权线程被复用时用createUser+importCredential植入 rogue admin。
验证该漏洞
- 附加 JDWP(
-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n)或类似调试钩子,观察每次调用前后ThreadLocal的内容,确认未认证请求继承了先前的管理员Subject。 - 在生产设备上也可以使用 JFR 或 BTrace 对每次请求转储
SubjectHolder.getSubject(),以验证无 header 的复用情况。
References
- Synacktiv – ActivID authentication bypass (HID-PSA-2025-002)
- HID Global – Product Security Advisory HID-PSA-2025-002 SOAP-API Authentication Bypass
- Synacktiv – ActivID administrator account takeover: the story behind HID-PSA-2025-002
- PortSwigger – Wsdler (WSDL parser) extension
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。


