
Servidor SMB1 para interceptación de hashes NTLMv2, escrito en C.
Servidor SMB1 para interceptar hashes NTLMv2, escrito en C.
El objetivo del proyecto es implementar un servidor SMB1 como una máquina de estados que acepte y responda correctamente a las solicitudes del cliente para engañarlo, llevándolo a completar una autenticación NTLM y así revelar su propio hash NTLMv2 (en un formato compatible con hashcat/john).
Herramienta destinada a actividades de seguridad ofensiva/red team y con fines educativos (estudio del protocolo SMB1/NTLM), para ser utilizada exclusivamente en entornos autorizados que poseas o con consentimiento explícito.
El servidor se hace pasar por un servidor SMB1 legítimo y guía al cliente a través de una máquina de estados de 3 fases:

| Estado | Transición |
|---|---|
1. NEGOTIATE | Si llega un SMB NEGOTIATE, tras la respuesta del servidor el estado pasa a 2. CHALLENGE |
2. CHALLENGE | Si llega un NTLM_NEGOTIATE, tras la respuesta del servidor el estado pasa a 3. AUTH |
3. AUTH | Si llega un NTLM_AUTH, tras la respuesta del servidor el estado vuelve a 1. NEGOTIATE |
A nivel de implementación, debe tenerse en cuenta el "envoltorio" externo de NetBIOS, compuesto por 4 bytes, los últimos 3 de los cuales indican la longitud en bytes del paquete SMB.
Cada conexión de cliente se rastrea mediante una estructura de estado (client_t en server.h) que, además del estado de la máquina de estados, mantiene:
rx_buf) con su longitud, para almacenar datos leídos del socket pero aún no procesados por completo;tx_buf, con desplazamiento tx_off) para almacenar datos que se enviarán al cliente pero que aún no se han transmitido por completo;netbios_header_recv y netbios_msg_len para el seguimiento del encabezado NetBIOS.Al recibir datos, se verifica que se hayan recibido al menos 4 bytes (encabezado NetBIOS), se determina la longitud del mensaje SMB, se actualizan los campos de estado y, finalmente, se procesa el mensaje, actualizando el estado del cliente para la siguiente recepción.
El bucle principal del servidor se basa en poll() para manejar múltiples conexiones simultáneamente de forma no bloqueante:

Cuando se completa la autenticación NTLM, el servidor imprime en pantalla ([INTERCEPTED] ...) el nombre de usuario, el nombre de host, el dominio y el hash NTLMv2 capturado, en el formato:
username::domain:server_challenge:ntlmv2_response:blob
listo para ser utilizado con herramientas de cracking como hashcat (modo -m 5600) o john.
gcc/clang) y un conjunto de herramientas POSIX (el código utiliza sockets BSD, poll(), signal(), etc., por lo que está destinado a entornos Linux/Unix-like).Se incluye un Makefile:
make # compilar el servidor principal -> ./impostor
make debug # compilación de depuración (símbolos, -O0, AddressSanitizer/UBSan)
make clean # eliminar archivos objeto y ejecutables generados
make run # compilar y ejecutar el servidor
Alternativamente, un comando de compilación manual equivalente es:
gcc -o impostor server.c smb1_parser.c spnego_decoder.c asn1_parser.c ntlm_parser.c
./impostor [puerto]
puerto (opcional): puerto TCP en el que escucha el servidor. Si se omite, se utiliza el puerto predeterminado definido en server.h (SERVER_PORT, 9000). Debe ser un valor entre 1 y 65535.Al iniciarse, el servidor imprime un banner, la versión e información de configuración (puerto, número máximo de clientes), y luego permanece escuchando conexiones. Cuando se captura un hash NTLMv2, los datos interceptados (nombre de usuario, nombre de host, dominio, hash) se imprimen en pantalla. El servidor puede detenerse con Ctrl+C (SIGINT), manejado por intHandler.
___ ___ _ ___
|_ _|_ __ ___ _ __ / _ \ ___| |_ / _ \ _ __
| || '_ ` _ \| '_ \| | | / __| __| | | | '__|
| || | | | | | |_) | |_| \__ \ |_| |_| | |
|___|_| |_| |_| .__/ \___/|___/\__|\___/|_|
|_| (v.1.0) by Lcky
[*] Versión: 1.0
[*] Autor: Lcky <luca9vinci at gmail dot com>
[*] Información del servidor
Puerto: 9090
Máx. clientes: 50
[*] Escuchando en el puerto 9090
[*] Esperando conexiones...
[INTERCEPTED] Usuario: test
[INTERCEPTED] Nombre de host: KALILINUX-2023-02
[INTERCEPTED] Dominio : WORKGROUP
[INTERCEPTED] Hash : test::WORKGROUP:c4ba87a265de9e09:3482d0efa64fc09a94e44faa83d2a936:01010000000000009A3DE84B6235DD01D36FD06DFF4D64BB000000000200080038004E004900490001001E00570049004E002D00310046005800340055004D005000530034005400420004003400570049004E002D00310046005800340055004D00500053003400540042002E0038004E00490049002E004C004F00430041004C000300140038004E00490049002E004C004F00430041004C000500140038004E00490049002E004C004F00430041004C0008003000300000000000000000000000000000000CAFEB574B56CB6139E261228FBFE3075B4FA9393A3B71031AF3280F4D5A27D00A0010000000000000000000000000000000000009001C0063006900660073002F003100320037002E0030002E0030002E00310000000000
^C
[*] Deteniendo el servidor...
| Archivo | Descripción |
|---|
server.c / server.h | Punto de entrada, configuración del listener TCP, máquina de estados del cliente, bucle principal basado en poll(), almacenamiento en búfer RX/TX, impresión de hashes interceptados |
smb1_parser.c / smb1_parser.h | Análisis/construcción de paquetes SMB1 (encabezado, comandos NEGOTIATE, SESSION_SETUP, flags/flags2, etc.) |
spnego_decoder.c / spnego_decoder.h | Decodificación del token SPNEGO (negociación del mecanismo de autenticación, extracción del blob NTLMSSP) contenido en los mensajes SMB |
asn1_parser.c / asn1_parser.h | Analizador ASN.1 DER mínimo, utilizado por el decodificador SPNEGO para construir el árbol de estructura ASN.1 |
ntlm_parser.c / ntlm_parser.h | Análisis de mensajes NTLMSSP (NEGOTIATE, CHALLENGE, AUTHENTICATE) y extracción de nombre de usuario, dominio, nombre de host y respuesta NTLMv2 |
endianness.h | Utilidad para manejar el endianness (conversiones little/big endian en tiempo de ejecución) |
test.c, test2.c | Archivos de prueba/experimentación para los analizadores |
docs/ | Diagramas y material de apoyo (esquema de la máquina de estados, bucle principal) |