
Extrae el hash NetNTLMv2 del usuario actual mediante proxy de autenticación HTTP, evitando llamadas directas a SSPI; la v2 delega la autenticación al servicio BITS para romper la atribución del proceso.
Extracción de hash NTLM mediante proxy de autenticación a nivel de capa HTTP, cero llamadas SSPI desde el proceso atacante.
HashSiphon extrae el hash NetNTLMv2 del usuario actual manipulando los flujos de autenticación HTTP en lugar de llamar directamente a las API SSPI. Incluye dos variantes: v1 enruta la autenticación NTLM a través de la pila HTTP de .NET dentro del mismo proceso, y v2 delega la autenticación por completo al servicio BITS (svchost.exe) en un PID diferente, rompiendo por completo la atribución a nivel de proceso.
Todas las herramientas conocidas de autoextracción de hash NTLM Internal Monologue, scripts SSPI manuales y sus derivados llaman a AcquireCredentialsHandle → InitializeSecurityContext → AcceptSecurityContext desde el propio proceso del atacante. Los EDR enganchan estas funciones SSPI y marcan la cadena de llamadas.
HashSiphon toma un camino fundamentalmente diferente:
| Aspecto | Internal Monologue | HashSiphon v1 | HashSiphon v2 |
|---|
| Llamadas SSPI desde el PID atacante | 4+ llamadas directas | 0 directas (WinHTTP llama internamente) | 0 en cualquier proceso que poseamos |
| Proceso de autenticación | PID atacante | PID atacante (vía pila HTTP) | svchost.exe (servicio BITS) |
| Importaciones de API de seguridad | Se requieren importaciones de DLL SSPI | Ninguna en nuestro código | Ninguna en nuestro código |
| Superficie de detección | Hooks SSPI, patrones de llamadas API | Tráfico HTTP de loopback | Trabajo BITS + tráfico de loopback |
| Atribución de proceso | PID atacante | PID atacante | Rota, PID completamente diferente |
Ambas variantes comparten el mismo núcleo: un servidor TCP mínimo en 127.0.0.1 que habla lo justo de HTTP para realizar un intercambio de desafío-respuesta NTLM, con un desafío controlado de 8 bytes para que el hash capturado sea crackeable offline.
HashSiphon.ps1)┌──────────────────────────┐
│ PowerShell (PID X) │
│ │
│ ┌────────────────────┐ │ ┌──────────────────────┐
│ │ TCP Server (C#) │◄─┼──────────┤ HttpWebRequest + │
│ │ Loopback :random │ │ HTTP │ DefaultCredentials │
│ │ │──┼──────────► │
│ │ 1. Send 401+NTLM │ │ NTLM │ WinHTTP auto-auths │
│ │ 2. Send Type 2 │ │ Type │ using current user's │
│ │ 3. Capture Type 3 │ │ 1/2/3 │ credentials │
│ │ 4. Extract hash │ │ │ │
│ └────────────────────┘ │ └──────────────────────┘
└──────────────────────────┘
Add-Type, se enlaza a 127.0.0.1:0 (puerto asignado por el SO)HttpWebRequest + CredentialCache.DefaultCredentialsHTTP 401 con WWW-Authenticate: NTLM para desencadenar la negociaciónContrapartida: WinHTTP llama internamente a SSPI dentro del mismo PID, sin importaciones directas, pero la pila de llamadas sigue remontándose a nosotros.
HashSiphonV2.ps1)┌─────────────────────┐ ┌───────────────────────────┐
│ PowerShell (PID X) │ │ svchost.exe (PID Y) │
│ │ │ BITS Service │
│ ┌───────────────┐ │ HTTP │ │
│ │ TCP Server │◄─┼─────────┤ BITS downloads from our │
│ │ (Background │ │ NTLM │ server, auto-authenticates│
│ │ Runspace) │──┼─────────► using job owner's creds │
│ └───────────────┘ │ Type │ │
│ │ 1/2/3 │ SSPI calls happen HERE, │
│ Start-BitsTransfer─┼────────►│ not in PID X │
│ (Trigger only) │ COM │ │
└─────────────────────┘ └───────────────────────────┘
│
└── Our process: TcpListener + Start-BitsTransfer
Zero SSPI. Zero security API imports.
Start-BitsTransfer crea un trabajo de descarga apuntando a http://127.0.0.1:<port>/hashsiphon.binsvchost.exe, un PID completamente diferente) se conecta a nuestro servidorHTTP 200 con un cuerpo para que BITS considere la transferencia exitosaAvance clave: Nuestro proceso nunca llama a SSPI, ni directamente, ni a través de WinHTTP, ni en absoluto. Todo el cálculo NTLM ocurre en svchost.exe. Los hooks SSPI del EDR ven la pila de llamadas en el proceso del servicio BITS, no en el nuestro.
powershell -ExecutionPolicy Bypass -File HashSiphon.ps1
powershell -ExecutionPolicy Bypass -File HashSiphonV2.ps1
[*] Compiling HashSiphon v2 server...
[+] Server compiled
HashSiphon v2.0 - BITS Service Proxy Authentication
Auth by svchost.exe (BITS), not our process
[1] NTLM HTTP server ready on 127.0.0.1:52847
[2] Controlled challenge: 1122334455667788
[3] Triggering BITS transfer to our server...
[4] BITS transfer initiated
[+] User: ivan
[+] Domain: DESKTOP-ABCDEF
[+] NT response: 280 bytes (NTLMv2)
+----------------------------------------------------------+
| NetNTLMv2 HASH - Extracted via BITS service proxy! |
+----------------------------------------------------------+
| hashcat -m 5600 | john --format=netntlmv2 |
+----------------------------------------------------------+
ivan::DESKTOP-ABCDEF:1122334455667788:<NTProofStr>:<ClientBlob>
+----------------------------------------------------------+
| ATTRIBUTION ANALYSIS |
+----------------------------------------------------------+
| Our PID: 844 (PowerShell) |
| Auth by: BITS service (svchost.exe, PID 5500) |
| SSPI calls: Zero from PID 844 |
| Our APIs: TcpListener + Start-BitsTransfer only |
+----------------------------------------------------------+
Si BITS falla (servicio deshabilitado, módulo no disponible), v2 recurre automáticamente a lanzar un proceso hijo powershell.exe con Invoke-WebRequest -UseDefaultCredentials. Esto sigue logrando la separación de PID, aunque el proceso hijo es más visible que BITS.