
SMB1-сервер для перехвата NTLMv2-хешей, написанный на C.
SMB1-сервер для перехвата NTLMv2-хешей, написанный на C.
Цель проекта — реализовать SMB1-сервер в виде конечного автомата, который корректно принимает и обрабатывает запросы клиента, чтобы обмануть его, подводя к завершению NTLM-аутентификации и тем самым раскрывая его собственный NTLMv2-хеш (в формате, совместимом с hashcat/john).
Инструмент предназначен для наступательной безопасности/задач red team и для образовательных целей (изучение протокола SMB1/NTLM) и должен использоваться исключительно в авторизованных средах, которыми вы владеете, или с явного согласия.
Сервер притворяется легитимным SMB1-сервером и проводит клиента через конечный автомат из 3 фаз:

| Состояние | Переход |
|---|---|
1. NEGOTIATE | Если приходит SMB NEGOTIATE, после ответа сервера состояние переходит в 2. CHALLENGE |
2. CHALLENGE | Если приходит NTLM_NEGOTIATE, после ответа сервера состояние переходит в 3. AUTH |
3. AUTH | Если приходит NTLM_AUTH, после ответа сервера состояние возвращается в 1. NEGOTIATE |
На уровне реализации необходимо учитывать внешний NetBIOS-«конверт», состоящий из 4 байт, последние 3 из которых указывают длину SMB-пакета в байтах.
Каждое клиентское соединение отслеживается через структуру состояния (client_t в server.h), которая помимо статуса конечного автомата поддерживает:
rx_buf) с его длиной для буферизации данных, прочитанных из сокета, но ещё не полностью обработанных;tx_buf, со смещением tx_off) для буферизации данных, которые нужно отправить клиенту, но которые ещё не полностью переданы;netbios_header_recv и netbios_msg_len для отслеживания NetBIOS-заголовка.При получении данных проверяется, что получено как минимум 4 байта (NetBIOS-заголовок), определяется длина SMB-сообщения, обновляются поля состояния и, наконец, обрабатывается сообщение, обновляя состояние клиента для следующего приёма.
Основной цикл сервера основан на poll() для одновременной обработки нескольких соединений в неблокирующем режиме:

Когда NTLM-аутентификация завершена, сервер выводит на экран ([INTERCEPTED] ...) имя пользователя, имя хоста, домен и перехваченный NTLMv2-хеш в формате:
username::domain:server_challenge:ntlmv2_response:blob
готовый к использованию с инструментами взлома, такими как hashcat (режим -m 5600) или john.
gcc/clang), и POSIX-инструментарий (код использует BSD-сокеты, poll(), signal() и т.д., поэтому предназначен для Linux/Unix-подобных сред).Включён Makefile:
make # сборка основного сервера -> ./impostor
make debug # отладочная сборка (символы, -O0, AddressSanitizer/UBSan)
make clean # удаление сгенерированных объектных файлов и исполняемых файлов
make run # сборка и запуск сервера
В качестве альтернативы эквивалентная команда ручной компиляции:
gcc -o impostor server.c smb1_parser.c spnego_decoder.c asn1_parser.c ntlm_parser.c
./impostor [port]
port (необязательно): TCP-порт, на котором слушает сервер. Если опущен, используется порт по умолчанию, определённый в server.h (SERVER_PORT, 9000). Должен быть значением от 1 до 65535.При запуске сервер выводит баннер, версию и информацию о конфигурации (порт, максимальное количество клиентов), затем остаётся в режиме ожидания соединений. Когда NTLMv2-хеш перехвачен, перехваченные данные (имя пользователя, имя хоста, домен, хеш) выводятся на экран. Сервер можно остановить с помощью Ctrl+C (SIGINT), обрабатываемого intHandler.
___ ___ _ ___
|_ _|_ __ ___ _ __ / _ \ ___| |_ / _ \ _ __
| || '_ ` _ \| '_ \| | | / __| __| | | | '__|
| || | | | | | |_) | |_| \__ \ |_| |_| | |
|___|_| |_| |_| .__/ \___/|___/\__|\___/|_|
|_| (v.1.0) by Lcky
[*] Version: 1.0
[*] Author: Lcky <luca9vinci at gmail dot com>
[*] Server Info
Port: 9090
Max Clients: 50
[*] Listening on port 9090
[*] Waiting for connections...
[INTERCEPTED] Username: test
[INTERCEPTED] Hostname: KALILINUX-2023-02
[INTERCEPTED] Domain : WORKGROUP
[INTERCEPTED] Hash : test::WORKGROUP:c4ba87a265de9e09:3482d0efa64fc09a94e44faa83d2a936:01010000000000009A3DE84B6235DD01D36FD06DFF4D64BB000000000200080038004E004900490001001E00570049004E002D00310046005800340055004D005000530034005400420004003400570049004E002D00310046005800340055004D00500053003400540042002E0038004E00490049002E004C004F00430041004C000300140038004E00490049002E004C004F00430041004C000500140038004E00490049002E004C004F00430041004C0008003000300000000000000000000000000000000CAFEB574B56CB6139E261228FBFE3075B4FA9393A3B71031AF3280F4D5A27D00A0010000000000000000000000000000000000009001C0063006900660073002F003100320037002E0030002E0030002E00310000000000
^C
[*] Stopping the server...
| Файл | Описание |
|---|
server.c / server.h | Точка входа, настройка TCP-слушателя, конечный автомат клиента, основной цикл на основе poll(), RX/TX-буферизация, вывод перехваченных хешей |
smb1_parser.c / smb1_parser.h | Разбор/сборка SMB1-пакетов (заголовок, команды NEGOTIATE, SESSION_SETUP, флаги/flags2 и т.д.) |
spnego_decoder.c / spnego_decoder.h | Декодирование SPNEGO-токена (согласование механизма аутентификации, извлечение NTLMSSP-блобов), содержащегося в SMB-сообщениях |
asn1_parser.c / asn1_parser.h | Минимальный ASN.1 DER-парсер, используемый SPNEGO-декодером для построения дерева ASN.1-структур |
ntlm_parser.c / ntlm_parser.h | Разбор NTLMSSP-сообщений (NEGOTIATE, CHALLENGE, AUTHENTICATE) и извлечение имени пользователя, домена, имени хоста и NTLMv2-ответа |
endianness.h | Утилита для работы с порядком байтов (преобразования little/big endian во время выполнения) |
test.c, test2.c | Тестовые/экспериментальные файлы для парсеров |
docs/ | Диаграммы и вспомогательные материалы (схема конечного автомата, основной цикл) |