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 ヘッダが到着した場合のみそれを更新する。
  • WebLogic/JBoss/GlassFish がワーカースレッドを再利用するため、そのヘッダを送らないとスレッドが最後に処理した特権付きの Subject が無音で再利用される。
  • ヘッダ無しだが正しく構成された SOAP ボディを脆弱なエンドポイントに繰り返し送信し、再利用されたスレッドが盗まれた管理者コンテキストを返すまで試行する。
  • 2025 HID ActivID/IASP (HID-PSA-2025-002) は実例で、JAX-WS ハンドラが SubjectHolder ThreadLocal をキャッシュし、未認証の SOAP 呼び出しが以前の console/SSP リクエストで設定されたアイデンティティを継承してしまう。

根本原因

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

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 をブロックするが POSTs を受け入れる可能性のある隠れた SOAP ツリーを特定する(80,443 - Pentesting Web Methodology のフローに沿ってマッピングする)。
  2. EAR/WAR/EJB アーティファクトを展開(unzip *.ear)し、application.xmlweb.xml@WebService アノテーション、およびハンドラチェーン(例: LoginHandlerChain.xml)を調査して、ハンドラクラス、SOAP ヘッダーの QName、およびバックエンド EJB 名を突き止める。
  3. メタデータが欠けている場合は、可能性のある ServiceName?wsdl パスを brute-force するかラボのプロキシを一時的に緩め、回収した 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>

2025 HID ActivID/IASP ケーススタディ (HID-PSA-2025-002)

  • Synacktiv は ActivID 8.6–8.7 の JAX-WS LoginHandler が、mySubjectHeader SOAP ヘッダが存在する場合や console/SSP トラフィックで認証が行われた場合に SubjectHolder.subject を設定するが、ヘッダが存在しないときにそれをクリアしないことを示した。
  • 同じワーカースレッド上でヘッダを欠いた任意の後続の SOAP 呼び出しはそのキャッシュされた Subject を継承し、UserManagerCredentialManager のようなエンドポイントを通じて認証なしに管理者ユーザの作成や credential のインポートが可能になる。
  • 観察された再現性の高い悪用パターン:
  1. 多数のスレッドで認証コンテキストをトリガーする(例: /ssp を大量に叩く、別ブラウザタブで /aiconsole に admin としてログインする)。
  2. 高並列でヘッダ無しの SOAP ボディを /ac-iasp-backend-jaxws/UserManager や他の EJB バックの JAX-WS エンドポイントに集中送信する;「感染した」スレッドを再利用した各ヒットは昇格した Subject で実行される。
  3. 特権応答が返るまで繰り返す;Keep-Alive 接続や大きなワーカープールを再利用してスレッド再利用の確率を最大化する。
  • ハンドラとプロセスフローの要点:
  • LoginHandlerChain.xmlLoginHandler.handleMessage()mySubjectHeader を unmarshal し、SubjectSubjectHolder(静的な ThreadLocal)に格納する。
  • ProcessManager.triggerProcess() が後で SubjectHolder.getSubject() をビジネスプロセスに注入するため、ヘッダが欠けていると残留した識別情報がそのまま使われる。
  • Advisory にあるインフィールド PoC は二段階の SOAP 悪用を使用する:まず getUsers で情報を leak し、続いて createUser + importCredential で特権スレッドが当たったときに不正な管理者を植え付ける。

バグの検証

  • JDWP(-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n)や同等のデバッグフックをアタッチして、各呼び出しの前後で ThreadLocal の内容を監視し、認証されていないリクエストが以前の管理者 Subject を継承していることを確認する。
  • 本番アプライアンスでは JFR や BTrace で各リクエストごとに SubjectHolder.getSubject() をダンプして、ヘッダ無しの再利用を検証することもできる。

References

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