
Extrai o hash NetNTLMv2 do usuário atual por meio de proxy de autenticação HTTP, evitando chamadas diretas à SSPI; a v2 delega a autenticação ao serviço BITS para quebrar a atribuição de processo.
Extração de hash NTLM através de proxy de autenticação na camada HTTP, zero chamadas SSPI a partir do processo atacante.
O HashSiphon extrai o hash NetNTLMv2 do usuário atual manipulando fluxos de autenticação HTTP em vez de chamar APIs SSPI diretamente. Ele disponibiliza duas variantes: a v1 encaminha a autenticação NTLM através da pilha HTTP do .NET dentro do mesmo processo, e a v2 delega a autenticação inteiramente ao serviço BITS (svchost.exe) em um PID diferente, quebrando completamente a atribuição em nível de processo.
Todas as ferramentas conhecidas de autoextração de hash NTLM — Internal Monologue, scripts SSPI manuais e seus derivados — chamam AcquireCredentialsHandle → InitializeSecurityContext → AcceptSecurityContext a partir do próprio processo do atacante. Os EDRs interceptam essas funções SSPI e sinalizam a cadeia de chamadas.
O HashSiphon segue um caminho fundamentalmente diferente:
| Aspecto | Internal Monologue | HashSiphon v1 | HashSiphon v2 |
|---|
| Chamadas SSPI a partir do PID atacante | 4+ chamadas diretas | 0 diretas (WinHTTP chama internamente) | 0 em qualquer processo nosso |
| Processo de autenticação | PID do atacante | PID do atacante (via pilha HTTP) | svchost.exe (serviço BITS) |
| Importações de API de segurança | Importações de DLL SSPI necessárias | Nenhuma em nosso código | Nenhuma em nosso código |
| Superfície de detecção | Hooks SSPI, padrões de chamadas de API | Tráfego HTTP em loopback | Job BITS + tráfego em loopback |
| Atribuição de processo | PID do atacante | PID do atacante | Quebrada, PID totalmente diferente |
Ambas as variantes compartilham o mesmo núcleo: um servidor TCP mínimo em 127.0.0.1 que fala apenas o suficiente de HTTP para realizar uma troca de desafio-resposta NTLM, com um desafio controlado de 8 bytes para que o hash capturado seja quebrável 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, vincula a 127.0.0.1:0 (porta atribuída pelo SO)HttpWebRequest + CredentialCache.DefaultCredentialsHTTP 401 com WWW-Authenticate: NTLM para disparar a negociaçãoTrade-off: O WinHTTP chama SSPI internamente dentro do mesmo PID, sem importações diretas, mas a pilha de chamadas ainda aponta para nós.
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 cria um job de download apontando para http://127.0.0.1:<port>/hashsiphon.binsvchost.exe, um PID completamente diferente) conecta ao nosso servidorHTTP 200 com um corpo para que o BITS considere a transferência bem-sucedidaAvanço: Nosso processo nunca chama SSPI, nem diretamente, nem através do WinHTTP, nem de forma alguma. Todo o cálculo NTLM acontece no svchost.exe. Os hooks SSPI do EDR veem a pilha de chamadas no processo do serviço BITS, não no nosso.
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 |
+----------------------------------------------------------+
Se o BITS falhar (serviço desabilitado, módulo indisponível), a v2 automaticamente recorre à inicialização de um processo filho powershell.exe com Invoke-WebRequest -UseDefaultCredentials. Isso ainda alcança a separação de PID, embora o processo filho seja mais visível que o BITS.