SOAP/JAX-WS ThreadLocal Authentication Bypass

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

TL;DR

  • Alcune catene middleware memorizzano il Subject/Principal autenticato dentro uno ThreadLocal statico e lo aggiornano solo quando arriva un header SOAP proprietario.
  • Poiché WebLogic/JBoss/GlassFish riciclano i thread di lavoro, l’assenza di quell’header fa sì che l’ultimo Subject privilegiato processato dal thread venga riutilizzato silenziosamente.
  • Bombarda l’endpoint vulnerabile con body SOAP privi dell’header ma ben formati finché un thread riutilizzato non ti concede il contesto amministratore rubato.
  • Il caso reale del 2025 HID ActivID/IASP (HID-PSA-2025-002): un handler JAX-WS memorizza nella cache un SubjectHolder ThreadLocal, permettendo a chiamate SOAP non autenticate di ereditare l’identità impostata da precedenti richieste console/SSP.

Causa principale

Handler simili al seguente sovrascrivono l’identità ThreadLocal solo quando è presente l’header personalizzato, quindi il contesto della richiesta precedente sopravvive:

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

Ricognizione

  1. Esegui l’enumerazione delle regole del reverse proxy / routing per individuare alberi SOAP nascosti che possono bloccare ?wsdl ma accettare POST (mappali insieme al flusso in 80,443 - Pentesting Web Methodology).
  2. Estrai gli artifact EAR/WAR/EJB (unzip *.ear) e ispeziona application.xml, web.xml, le annotazioni @WebService e le handler chain (es., LoginHandlerChain.xml) per scoprire la classe handler, il QName dell’header SOAP e i nomi degli EJB sottostanti.
  3. Se i metadata mancano, forza per tentativi i probabili percorsi ServiceName?wsdl o rilassa temporaneamente i proxy di laboratorio, poi importa qualsiasi WSDL recuperato in tooling come Burp Suite Wsdler per generare envelope di base.
  4. Esamina il sorgente degli handler alla ricerca di keeper ThreadLocal (es., SubjectHolder.setSubject()) che non vengono mai puliti quando l’header di autenticazione manca o è malformato.

Sfruttamento

  1. Invia una richiesta valida con l’header proprietario per apprendere i codici di risposta normali e gli eventuali errori usati per token non validi.
  2. Reinvia lo stesso body SOAP omettendo l’header. Mantieni l’XML ben formato e rispetta gli namespace richiesti in modo che l’handler termini correttamente.
  3. Ripeti la richiesta in loop; quando viene servita da un thread che in precedenza ha eseguito un’azione privilegiata, il Subject riutilizzato sblocca operazioni protette come i gestori utenti o delle credenziali.
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 Studio di caso HID ActivID/IASP (HID-PSA-2025-002)

  • Synacktiv ha mostrato che il JAX-WS LoginHandler in ActivID 8.6–8.7 imposta SubjectHolder.subject quando è presente un header SOAP mySubjectHeader o quando il traffico console/SSP si autentica, ma non lo cancella mai quando l’header è assente.
  • Qualsiasi chiamata SOAP successiva priva dell’header sullo stesso thread worker eredita quel Subject memorizzato nella cache, permettendo la creazione non autenticata di utenti amministratori o l’importazione di credenziali tramite endpoint come UserManager o CredentialManager.
  • Pattern di sfruttamento affidabile osservato:
  1. Indurre un contesto autenticato su molti thread (es. spam di /ssp o login su /aiconsole come admin in un’altra tab del browser).
  2. Inviare in massa corpi SOAP privi di header a /ac-iasp-backend-jaxws/UserManager o ad altri endpoint JAX-WS basati su EJB con alta parallelità; ogni hit che riusa un thread “infettato” viene eseguito con il Subject elevato.
  3. Ripetere finché non si ricevono risposte privilegiate; riutilizzare connessioni Keep-Alive e grandi pool di worker per massimizzare la probabilità di riuso dei thread.
  • Punti salienti di handler e flow di processo:
  • LoginHandlerChain.xmlLoginHandler.handleMessage() unmarshals mySubjectHeader e salva il Subject in SubjectHolder (un ThreadLocal statico).
  • ProcessManager.triggerProcess() in seguito inietta SubjectHolder.getSubject() nei processi di business, quindi header mancanti lasciano identità stale intatte.
  • Il PoC in campo dall’advisory usa un abuso SOAP in due fasi: prima getUsers per leak di info, poi createUser + importCredential per piantare un admin rogue quando il thread privilegiato viene colpito.

Validazione del bug

  • Allegare JDWP (-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n) o hook di debug simili per osservare il contenuto del ThreadLocal prima e dopo ogni chiamata, confermando che una richiesta non autenticata ha ereditato un precedente Subject di amministratore.
  • Su appliance di produzione è possibile anche instrumentare con JFR o BTrace per dumpare SubjectHolder.getSubject() per richiesta, verificando il riuso senza header.

Riferimenti

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks