
Извлекает NetNTLMv2-хеш текущего пользователя через проксирование HTTP-аутентификации, избегая прямых вызовов SSPI; v2 делегирует аутентификацию службе BITS, чтобы разорвать атрибуцию процесса.
Извлечение NTLM-хэша через проксирование аутентификации на уровне HTTP, без вызовов SSPI из процесса атакующего.
HashSiphon извлекает NetNTLMv2-хэш текущего пользователя, манипулируя потоками HTTP-аутентификации вместо прямого вызова SSPI API. Инструмент поставляется в двух вариантах: v1 направляет NTLM-аутентификацию через HTTP-стек .NET в рамках того же процесса, а v2 полностью делегирует аутентификацию службе BITS (svchost.exe) в другом PID, полностью разрывая атрибуцию на уровне процесса.
Все известные инструменты самостоятельного извлечения NTLM-хэша — Internal Monologue, ручные скрипты на SSPI и их производные — вызывают AcquireCredentialsHandle → InitializeSecurityContext → AcceptSecurityContext из собственного процесса атакующего. EDR перехватывают эти функции SSPI и помечают цепочку вызовов.
HashSiphon идёт принципиально иным путём:
| Аспект | Internal Monologue | HashSiphon v1 | HashSiphon v2 |
|---|
| Вызовы SSPI из PID атакующего | 4+ прямых вызова | 0 прямых (WinHTTP вызывает внутри) | 0 в любом нашем процессе |
| Процесс аутентификации | PID атакующего | PID атакующего (через HTTP-стек) | svchost.exe (служба BITS) |
| Импорты security API | Требуются импорты DLL SSPI | Отсутствуют в нашем коде | Отсутствуют в нашем коде |
| Поверхность обнаружения | Хуки SSPI, паттерны вызовов API | HTTP-трафик на loopback | Задание BITS + трафик на loopback |
| Атрибуция процесса | PID атакующего | PID атакующего | Разорвана, совершенно другой PID |
Оба варианта используют одно ядро: минимальный TCP-сервер на 127.0.0.1, который говорит на ровно достаточном объёме HTTP для выполнения обмена NTLM challenge-response, с контролируемым 8-байтовым challenge, чтобы перехваченный хэш можно было взломать офлайн.
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, привязывается к 127.0.0.1:0 (порт назначает ОС)HttpWebRequest + CredentialCache.DefaultCredentialsHTTP 401 с WWW-Authenticate: NTLM, чтобы запустить согласованиеКомпромисс: WinHTTP внутри вызывает SSPI в том же PID — прямых импортов нет, но стек вызовов всё равно ведёт к нам.
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 создаёт задание загрузки, указывающее на http://127.0.0.1:<port>/hashsiphon.binsvchost.exe, совершенно другой PID) подключается к нашему серверуHTTP 200 с телом, чтобы BITS счёл передачу успешнойПрорыв: Наш процесс никогда не вызывает SSPI — ни напрямую, ни через WinHTTP, никак. Все вычисления NTLM происходят в svchost.exe. Хуки SSPI в EDR видят стек вызовов в процессе службы BITS, а не в нашем.
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 |
+----------------------------------------------------------+
Если BITS не работает (служба отключена, модуль недоступен), v2 автоматически переключается на запуск дочернего процесса powershell.exe с Invoke-WebRequest -UseDefaultCredentials. Это всё ещё обеспечивает разделение PID, хотя дочерний процесс более заметен, чем BITS.