
Servidor SMB1 para intercepção de hashes NTLMv2, escrito em C.
Servidor SMB1 para interceptar hashes NTLMv2, escrito em C.
O objetivo do projeto é implementar um servidor SMB1 como uma máquina de estados que aceita e responde corretamente às solicitações do cliente para enganá-lo, levando-o a concluir uma autenticação NTLM e, assim, revelar seu próprio hash NTLMv2 (em um formato compatível com hashcat/john).
Ferramenta destinada a atividades de segurança ofensiva/red team e para fins educacionais (estudo do protocolo SMB1/NTLM), para uso exclusivo em ambientes autorizados que você possua ou com consentimento explícito.
O servidor se passa por um servidor SMB1 legítimo e conduz o cliente por uma máquina de estados de 3 fases:

| Estado | Transição |
|---|---|
1. NEGOTIATE | Se um SMB NEGOTIATE chegar, após a resposta do servidor o estado passa para 2. CHALLENGE |
2. CHALLENGE | Se um NTLM_NEGOTIATE chegar, após a resposta do servidor o estado passa para 3. AUTH |
3. AUTH | Se um NTLM_AUTH chegar, após a resposta do servidor o estado retorna para 1. NEGOTIATE |
No nível de implementação, deve-se levar em conta o "envelope" externo NetBIOS, composto por 4 bytes, dos quais os últimos 3 indicam o comprimento em bytes do pacote SMB.
Cada conexão de cliente é rastreada por meio de uma estrutura de estado (client_t em server.h) que, além do status da máquina de estados, mantém:
rx_buf) com seu comprimento, para armazenar dados lidos do socket mas ainda não totalmente processados;tx_buf, com deslocamento tx_off) para armazenar dados a serem enviados ao cliente mas ainda não totalmente transmitidos;netbios_header_recv e netbios_msg_len para rastreamento do cabeçalho NetBIOS.Ao receber dados, verifica-se que pelo menos 4 bytes (cabeçalho NetBIOS) foram recebidos, determina-se o comprimento da mensagem SMB, atualizam-se os campos de estado e, finalmente, a mensagem é processada, atualizando o estado do cliente para a próxima recepção.
O loop principal do servidor é baseado em poll() para lidar com múltiplas conexões simultaneamente de forma não bloqueante:

Quando a autenticação NTLM é concluída, o servidor imprime na tela ([INTERCEPTED] ...) o nome de usuário, hostname, domínio e o hash NTLMv2 capturado, no formato:
username::domain:server_challenge:ntlmv2_response:blob
pronto para ser usado com ferramentas de quebra de senha como hashcat (modo -m 5600) ou john.
gcc/clang) e um toolchain POSIX (o código usa sockets BSD, poll(), signal(), etc., portanto é destinado a ambientes Linux/Unix-like).Um Makefile está incluído:
make # compilar o servidor principal -> ./impostor
make debug # compilação de depuração (símbolos, -O0, AddressSanitizer/UBSan)
make clean # remover arquivos objeto e executáveis gerados
make run # compilar e executar o servidor
Alternativamente, um comando de compilação manual equivalente é:
gcc -o impostor server.c smb1_parser.c spnego_decoder.c asn1_parser.c ntlm_parser.c
./impostor [porta]
porta (opcional): porta TCP na qual o servidor escuta. Se omitida, a porta padrão definida em server.h (SERVER_PORT, 9000) é usada. Deve ser um valor entre 1 e 65535.Na inicialização, o servidor imprime um banner, versão e informações de configuração (porta, número máximo de clientes) e permanece escutando por conexões. Quando um hash NTLMv2 é capturado, os dados interceptados (nome de usuário, hostname, domínio, hash) são impressos na tela. O servidor pode ser interrompido com Ctrl+C (SIGINT), tratado por intHandler.
___ ___ _ ___
|_ _|_ __ ___ _ __ / _ \ ___| |_ / _ \ _ __
| || '_ ` _ \| '_ \| | | / __| __| | | | '__|
| || | | | | | |_) | |_| \__ \ |_| |_| | |
|___|_| |_| |_| .__/ \___/|___/\__|\___/|_|
|_| (v.1.0) by Lcky
[*] Versão: 1.0
[*] Autor: Lcky <luca9vinci at gmail dot com>
[*] Informações do servidor
Porta: 9090
Máx. de clientes: 50
[*] Escutando na porta 9090
[*] Aguardando conexões...
[INTERCEPTED] Username: test
[INTERCEPTED] Hostname: KALILINUX-2023-02
[INTERCEPTED] Domain : WORKGROUP
[INTERCEPTED] Hash : test::WORKGROUP:c4ba87a265de9e09:3482d0efa64fc09a94e44faa83d2a936:01010000000000009A3DE84B6235DD01D36FD06DFF4D64BB000000000200080038004E004900490001001E00570049004E002D00310046005800340055004D005000530034005400420004003400570049004E002D00310046005800340055004D00500053003400540042002E0038004E00490049002E004C004F00430041004C000300140038004E00490049002E004C004F00430041004C000500140038004E00490049002E004C004F00430041004C0008003000300000000000000000000000000000000CAFEB574B56CB6139E261228FBFE3075B4FA9393A3B71031AF3280F4D5A27D00A0010000000000000000000000000000000000009001C0063006900660073002F003100320037002E0030002E0030002E00310000000000
^C
[*] Parando o servidor...
| Arquivo | Descrição |
|---|
server.c / server.h | Ponto de entrada, configuração do listener TCP, máquina de estados do cliente, loop principal baseado em poll(), buffers RX/TX, impressão de hashes interceptados |
smb1_parser.c / smb1_parser.h | Análise/construção de pacotes SMB1 (cabeçalho, comandos NEGOTIATE, SESSION_SETUP, flags/flags2, etc.) |
spnego_decoder.c / spnego_decoder.h | Decodificação do token SPNEGO (negociação do mecanismo de autenticação, extração do blob NTLMSSP) contido nas mensagens SMB |
asn1_parser.c / asn1_parser.h | Analisador mínimo de ASN.1 DER, usado pelo decodificador SPNEGO para construir a árvore de estrutura ASN.1 |
ntlm_parser.c / ntlm_parser.h | Análise de mensagens NTLMSSP (NEGOTIATE, CHALLENGE, AUTHENTICATE) e extração de nome de usuário, domínio, hostname e resposta NTLMv2 |
endianness.h | Utilitário para lidar com endianness (conversões little/big endian em tempo de execução) |
test.c, test2.c | Arquivos de teste/experimentação para os analisadores |
docs/ | Diagramas e material de apoio (esquema da máquina de estados, loop principal) |