Перейти к содержимому

Nmap NSE скрипт для SMB аудита: проверяем signing, версию протокола и шары за один проход

Nmap NSE скрипт для SMB аудита: проверяем signing, версию протокола и шары за один проход
Время чтения: 14 мин.

Представь: внутренний пентест, подсеть на 200 Windows-хостов, и тебе нужно проверить SMB-конфигурацию каждого. Стандартная связка smb-protocols + smb-security-mode + smb-enum-shares — это три отдельных TCP-сессии на каждый IP. Итого 600 соединений, три блока разрозненного вывода и минут 15 на парсинг, прежде чем данные попадут в отчёт. Кастомный NSE-скрипт решает эту проблему: один файл, один проход, структурированный результат. Разберём, как написать такой скрипт — от анатомии .nse-файла до рабочего аудита подсети.

Место аудита SMB конфигурации в цепочке атаки

Прежде чем лезть в код, стоит понять, зачем пентестер вообще проверяет SMB. SMB (Server Message Block) — сетевой протокол Windows для доступа к файлам, принтерам и именованным каналам. Если ты встречал термин «шара» — это как раз про него.

MITRE ATT&CK (открытая база тактик и техник атак, где каждая техника имеет свой T-код) помещает SMB-разведку в тактику Discovery: техника Network Service Discovery (T1046) описывает сканирование сетевых сервисов для построения карты инфраструктуры. Перечисление открытых шар (сетевых папок) — это Network Share Discovery (T1135). Обе техники — отправная точка для более серьёзных действий.

Вот как это выглядит в реальном engagement:

  1. Discovery (T1046, T1135) — обнаружение SMB-сервисов и перечисление шар. На выходе — карта: кто слушает на 445, какие шары доступны.
  2. Credential Access / Collection (T1557.001) — если SMB signing отключён (а на рабочих станциях Windows это дефолт), запускаем NTLM relay через Responder + ntlmrelayx. Signing — криптографическая подпись пакетов между клиентом и сервером. Без неё атакующий перехватывает и переотправляет аутентификационные данные. По сути, ты говоришь серверу «я — администратор», и сервер верит, потому что подпись никто не проверяет.
  3. Lateral Movement — полученные хеши или сессии используются для перемещения по сети.

Три факта, которые определяет аудит SMB:

  • SMB signing не required → хост уязвим к NTLM relay. На внутреннем пентесте это почти гарантированный lateral movement, если в сети есть хотя бы один администратор, который аутентифицируется по сети.
  • SMBv1 включён → хост потенциально уязвим к EternalBlue (MS17-010) и другим уязвимостям устаревшего протокола. Скрипт smb-vuln-ms17-010 в составе Nmap проверяет это отдельно, но сам факт включённого SMBv1 — уже красный флаг в отчёте.
  • Открытые шары с анонимным доступом → утечка данных без аутентификации. На практике встречаются шары с бэкапами баз, конфигурациями VPN и даже файлами с паролями.

[Применимо: внутренний пентест, grey box с сетевым доступом. На внешнем периметре порт 445 почти всегда закрыт файрволом.]

Работает если: целевые хосты доступны по порту 445/TCP, Nmap установлен, есть root/sudo для SYN-сканирования. Не работает если: порт 445 заблокирован межсетевым экраном между сегментами, хосты за NAT без проброса портов.

Штатные NSE-скрипты для SMB enumeration

NSE (Nmap Scripting Engine) — встроенный движок скриптов Nmap, работающий на языке Lua. В комплекте около 600 скриптов (точное число зависит от версии — проверяйте на nmap.org/book/nse.html). Для SMB-аудита нужны четыре:

smb-protocols — определяет, какие версии SMB поддерживает хост: SMBv1, SMBv2, SMBv3. Видите SMBv1 — фиксируйте в отчёте. По рекомендациям DISA STIG для Windows Server 2022, SMBv1 должен быть отключён на всех системах.

smb-security-mode — проверяет уровень аутентификации (user-level или share-level), поддержку challenge/response и статус message signing. Скрипт входит в категории default, discovery, safe — можно запускать без опасений сломать что-то в продакшене. Типичный вывод для уязвимого хоста: message_signing: disabled (dangerous, but default). Это значит, что сервер уязвим к man-in-the-middle и SMB relay атакам.

smb2-security-mode — то же самое, но для SMBv2/3. Отдельный скрипт нужен потому, что SMBv2 использует другой механизм согласования signing.

smb-enum-shares — перечисляет сетевые шары через MSRPC-функцию srvsvc.NetShareEnumAll. Если анонимный доступ к этой функции закрыт (на Windows новее 2000 обычно закрыт), скрипт перебирает список распространённых имён шар. В выводе — тип шары, путь и уровень доступа.

Проблема: чтобы получить полную картину, нужно запустить все четыре скрипта. Типичная команда: sudo nmap -p 445 --script smb-protocols,smb-security-mode,smb2-security-mode,smb-enum-shares 192.168.1.0/24. Работает, но каждый скрипт устанавливает собственное SMB-соединение, вывод перемешивается, и для отчёта приходится вручную сопоставлять результаты по каждому хосту. Кастомный скрипт объединяет всё в одну структуру.

Nmap — активно поддерживаемый проект с регулярными релизами (актуальную версию и число скриптов проверяйте на nmap.org).

Пишем кастомный NSE-скрипт на Lua для аудита SMB

Анатомия NSE-скрипта

Каждый .nse-файл — Lua-скрипт (Lua — лёгкий встраиваемый язык; если ты писал на Python, синтаксис покажется непривычным, но порог входа низкий) с фиксированной структурой. Чтобы Nmap его подхватил, файл должен содержать четыре элемента:

Переменная description — текстовое описание скрипта. Nmap показывает его при вызове --script-help. Записывается как description = [[Текст описания]] — двойные квадратные скобки позволяют многострочный текст.

Таблица categories — список категорий скрипта. Для нашего аудитора подходят "discovery" и "safe": скрипт собирает информацию и не может нарушить работу целевой системы. Категория влияет на то, запустится ли скрипт при вызове --script safe или --script discovery.

Функция-правило — определяет, для каких хостов/портов скрипт должен сработать. Два варианта: portrule (срабатывает когда Nmap находит конкретный открытый порт) и hostrule (для каждого обнаруженного хоста). Для SMB используем portrule: нам нужен только порт 445. Библиотека shortport даёт готовый хелпер — shortport.port_or_service(445, "microsoft-ds") вернёт true, если на хосте открыт порт 445 или обнаружен сервис microsoft-ds.

Функция action — основная логика. Принимает два аргумента: host (таблица с информацией о хосте — IP, имя, результаты предыдущих скриптов) и port (данные о порте). Возвращает строку или таблицу, которая попадает в вывод Nmap.

Импорт библиотек — через require: local smb = require "smb" подключает SMB-библиотеку Nmap, которая умеет устанавливать соединение, выполнять negotiate и вызывать MSRPC-функции.

Собираем smb-audit-combo.nse

Ниже — ядро функции action, объединяющее проверку signing и версии протокола. Полный файл начинается с description, categories и portrule, описанных выше, а затем содержит эту логику:

action = function(host, port)
  local out = stdnse.output_table()
  -- SMBv1 negotiate
  local ok, state = smb.start(host)
  if not ok then return "SMB: connection failed" end
  ok = smb.negotiate_protocol(state, {})
  if ok then
    out.smbv1 = "supported"
    local mode = state.security_mode or 0
    -- SMBv1: SIGNING_REQUIRED = 0x08 (MS-CIFS §2.2.4.52.2)
    -- Для Nmap < 7.25BETA1 (Lua 5.2) замените & на bit.band(mode, 0x08)
    out.signing_v1 = ((mode & 0x08) ~= 0) and "required" or "not required"
  end
  smb.stop(state)
  -- SMBv2/3 negotiate (см. smb2-security-mode.nse)
  local smb2 = require "smb2"
  local ok2, state2 = smb.start(host)
  if ok2 then
    local overrides = {}
    local s2ok = smb2.negotiate_v2(state2, overrides)
    if s2ok then
      out.dialect = state2.dialect or "unknown"
      local mode2 = state2.security_mode or 0
      -- SMBv2: SIGNING_REQUIRED = 0x0002
      out.signing = ((mode2 & 0x0002) ~= 0) and "required" or "not required"
    end
    smb.stop(state2)
  end
  return out
end

Что здесь происходит, строка за строкой. smb.start(host) открывает TCP-соединение к порту 445 и возвращает (status, smbstate). smb.negotiate_protocol(state, {}) отправляет SMBv1 Negotiate — после него state.security_mode содержит raw-байт из SMB_COM_NEGOTIATE response. Имена полей и порядок вызовов могут отличаться между версиями Nmap — сверяйтесь с исходником smb-security-mode.nse и /usr/share/nmap/nselib/smb.lua вашей версии. Для SMBv2/3 используется отдельная библиотека smb2 с вызовом smb2.negotiate_v2(state, overrides) (имя функции может отличаться — смотрите исходник smb2-security-mode.nse), после которого state.dialect содержит согласованную версию (например, "SMB 3.0.2"). Битовые маски signing различаются между версиями протокола. Для SMBv1 (MS-CIFS §2.2.4.52.2, поле SecurityMode): NEGOTIATE_SECURITY_SIGNATURES_ENABLED = 0x04, NEGOTIATE_SECURITY_SIGNATURES_REQUIRED = 0x08. Для SMBv2 (MS-SMB2 2.2.4): SMB2_NEGOTIATE_SIGNING_ENABLED = 0x0001, SMB2_NEGOTIATE_SIGNING_REQUIRED = 0x0002. Проверка — через (mode & флаг) ~= 0 (нативные битовые операторы Lua 5.3+, доступны в Nmap 7.25BETA1 и новее). Для совместимости с Nmap < 7.25BETA1 (Lua 5.2) используйте bit.band(mode, флаг) ~= 0.

Для перечисления шар нужна библиотека msrpc. После проверки signing добавляем блок: открываем соединение через smb.start_ex(host, true, true, "\\IPC$", nil, nil), выполняем msrpc.bind(smbstate, msrpc.SRVSVC_UUID, msrpc.SRVSVC_VERSION, nil), затем вызываем msrpc.srvsvc_netshareenumall(smbstate, host.ip). Результат — таблица с именами шар, типами и путями. Нужно обработать STATUS_ACCESS_DENIED при анонимном доступе и закрыть pipe после вызова. Полную последовательность смотрите в исходнике smb-enum-shares.nse.

Полный файл smb-audit-combo.nse включает: пять строк require (для smb, smb2, stdnse, shortport, msrpc), блок description, строку categories = {"discovery", "safe"}, строку portrule = shortport.port_or_service(445, "microsoft-ds") и функцию action из примера выше с расширением на шары. Перед использованием сверьте вызовы API с исходниками smb-security-mode.nse и smb2-security-mode.nse вашей версии Nmap — имена полей state могут отличаться. Итого — около 35 строк Lua-кода.

Проверка SMB signing через Nmap: пошаговый запуск

Требования к окружению

  • ОС: Kali Linux 2024+ или любой Linux с установленным Nmap. На macOS и Windows Nmap тоже работает, но SYN-сканирование может потребовать дополнительных настроек.
  • Nmap: версия 7.80 и выше (рекомендуется 7.92+, где обновлены SMB-библиотеки).
  • Права: root или sudo — без этого Nmap не сможет использовать SYN-сканирование (-sS) и часть SMB-функций.
  • Сеть: прямой доступ к целевым хостам по порту 445/TCP. Если между вами и целью стоит межсетевой экран — порт должен быть открыт.
  • RAM: Nmap потребляет минимум ресурсов (50–100 МБ даже на подсетях /16), специальных требований нет.
  • Текстовый редактор: nano, vim или VS Code для создания .nse-файла.

Шаг 1 — размещаем скрипт и обновляем базу

Скопируйте файл smb-audit-combo.nse в каталог скриптов Nmap и обновите индекс:

sudo cp smb-audit-combo.nse /usr/share/nmap/scripts/
sudo nmap --script-updatedb

--script-updatedb перестраивает файл script.db — индекс всех доступных скриптов. Если обновление прошло успешно, в выводе будет строка с количеством скриптов. Проверить, что ваш скрипт попал в базу: grep smb-audit-combo /usr/share/nmap/scripts/script.db — в ответе должна быть строка с именем скрипта и его категориями.

Шаг 2 — запускаем сканирование подсети

Запускаем аудит: sudo nmap -p 445 --script smb-audit-combo -oX smb-audit.xml 192.168.1.0/24. Флаг -p 445 ограничивает сканирование единственным портом — ускоряет процесс и снижает шум. Флаг -oX smb-audit.xml сохраняет результаты в XML — потом из него удобно генерировать таблицу для отчёта через xsltproc или парсить скриптом на Python.

Для одного хоста: sudo nmap -p 445 --script smb-audit-combo 192.168.1.10.

Если нужен аутентифицированный доступ (для перечисления шар на Windows 10+ это почти всегда необходимо), добавьте: --script-args smbusername=audit,smbpassword=P@ssw0rd. Nmap передаст данные SMB-библиотеке, и скрипт выполнит проверки от имени указанного пользователя.

Шаг 3 — читаем вывод и принимаем решения

Ожидаемый вывод для уязвимого хоста:

| smb-audit-combo:
|   dialect: NT LM 0.12
|   signing: not required
|   shares:
|     ADMIN$ (STYPE_DISKTREE_HIDDEN) - Remote Admin
|     C$ (STYPE_DISKTREE_HIDDEN) - Default share
|     IPC$ (STYPE_IPC_HIDDEN) - Remote IPC
|_    SharedDocs (STYPE_DISKTREE) - Documents

Как это читать:

dialect: NT LM 0.12 — хост согласовал SMBv1. Самая старая версия протокола, именно на ней работают эксплойты семейства EternalBlue. В отчёте — рекомендация отключить SMBv1 через групповую политику или PowerShell: Set-SmbServerConfiguration -EnableSMB1Protocol $false.

signing: not required — хост принимает неподписанные SMB-пакеты. Прямое следствие: атака NTLM relay возможна. Исправление — включить обязательную подпись через GPO: Computer Configuration → Policies → Windows Settings → Security Settings → Local Policies → Security Options → Microsoft network server: Digitally sign communications (always) → Enabled. По классификации OWASP Top 10 (A05:2021 — Security Misconfiguration), отключённый signing — типичный пример мисконфигурации, ведущей к компрометации.

shares — список сетевых папок. Административные шары (ADMIN$, C$, IPC$) стандартны для Windows. Если рядом есть пользовательские шары с анонимным доступом — это находка для отчёта.

Для хоста с правильной конфигурацией вывод будет: dialect: SMB 3.1.1, signing: required, список шар без анонимного доступа. Такой хост можно отметить как compliant.

Ограничения и обнаружение NSE-сканирования

Любой инструмент имеет границы. Вот конкретные ограничения кастомного NSE-скрипта для SMB-аудита.

Сетевой шум. Каждое SMB-соединение — TCP-сессия с negotiate-пакетом. На подсети /24 (254 хоста) скрипт создаст 254 TCP-соединения к порту 445. IDS/IPS (системы обнаружения и предотвращения вторжений) это заметят. Suricata и Snort имеют правила для обнаружения массовых подключений к SMB-портам. На стороне Windows при аутентифицированных сканах события логируются в Security Event Log (Event ID 4624/4625 — вход/неудачный вход). Для детекции доступа к шарам более релевантны Event ID 5140 (сетевой доступ к share) и 5145 (детальная проверка доступа к объекту share) — но они фиксируются только при включённых политиках Advanced Audit Policy → Object Access → Audit File Share (для 5140) и Audit Detailed File Share (для 5145). По умолчанию эти политики отключены на большинстве Windows-систем. Microsoft Defender for Endpoint при массовом сканировании порта 445 из одного источника сгенерирует алерт «Suspicious network scanning activity». CrowdStrike Falcon аналогично фиксирует паттерны горизонтального сканирования.

Аутентификация. Без учётных данных перечисление шар работает ограниченно: на Windows Vista/Server 2008 и новее анонимный вызов NetShareEnumAll обычно возвращает ACCESS_DENIED. Скрипт при анонимном подключении откатится на перебор распространённых имён, но часть шар останется невидимой. Для полного аудита используйте --script-args с учётной записью с минимальными привилегиями.

SMB over QUIC. Windows Server 2022 и новее поддерживают SMB over QUIC (порт 443/UDP) — Nmap по умолчанию его не сканирует. Если целевая инфраструктура использует этот транспорт, NSE-скрипт для порта 445 просто не найдёт хосты.

Скорость vs скрытность. Nmap по умолчанию использует агрессивный тайминг. Для снижения заметности можно добавить -T2 или --scan-delay 500ms, но сканирование /24 при таких настройках займёт десятки минут.

Кастомный NSE-скрипт vs CrackMapExec vs enum4linux

Для SMB-аудита существует несколько инструментов. Ниже — trade-off таблица с конкретными техническими отличиями:

Критерий Кастомный NSE CrackMapExec / NetExec enum4linux-ng
Проверка signing Да Да (флагом —gen-relay-list) Нет
Версия протокола Да (из negotiate) Частично (определяет SMB1 vs SMB2) Нет
Перечисление шар Да Да Да
Кастомизация вывода Полная (Lua) Через модули Python Ограниченная
Формат экспорта XML, grepable, JSON (с NSE) JSON, CSV stdout
Зависимости Только Nmap Python 3, Impacket Python 3, samba-tools
Когда использовать Массовый аудит подсети с кастомным отчётом Быстрая проверка signing + spray credentials Полная разведка пользователей и групп
Когда НЕ использовать Если нужен spray паролей или pass-the-hash Если нужен только вывод версии протокола Если нужна проверка signing

CrackMapExec (активно развивается как NetExec — форк после архивации оригинального проекта) удобнее для быстрого теста: nxc smb 192.168.1.0/24 --gen-relay-list relay-targets.txt за один вызов покажет хосты без обязательного signing. Но если нужно получить signing + версию протокола + шары в одном структурированном XML для автоматической генерации отчёта — кастомный NSE-скрипт выигрывает.

enum4linux-ng (поддерживаемый форк enum4linux) хорош для глубокого перечисления пользователей, групп и политик паролей (Password Policy Discovery, T1201 по MITRE ATT&CK), но не проверяет signing — для полного аудита его придётся комбинировать с другими инструментами.

Чеклист SMB hardening для отчёта

По результатам аудита — готовый список действий для передачи системному администратору:

  1. Отключить SMBv1 на всех хостах: Set-SmbServerConfiguration -EnableSMB1Protocol $false (PowerShell). Через GPO: Computer Configuration → Administrative Templates → Network → Lanman Server → Allow SMB1 protocol → Disabled.
  2. Включить обязательный signing для серверов: GPO Microsoft network server: Digitally sign communications (always) → Enabled. Для клиентов: Microsoft network client: Digitally sign communications (always) → Enabled.
  3. Ревизия шар. Удалить или ограничить доступ к пользовательским шарам с анонимным доступом. Проверить ACL на каждой шаре: Get-SmbShareAccess -Name "ShareName".
  4. Ограничить анонимный доступ. GPO: Network access: Restrict anonymous access to Named Pipes and Shares → Enabled. Дополнительно: Network access: Do not allow anonymous enumeration of SAM accounts and shares → Enabled.
  5. Мониторинг. Настроить правила в SIEM для детекции массовых SMB-подключений из одного источника (Event ID 4624 с LogonType 3 от одного IP к множеству хостов за короткий интервал).
  6. Повторный аудит. После применения изменений — повторно запустить скрипт. Ожидаемый результат: signing: required, dialect: SMB 3.x, отсутствие анонимного доступа к нестандартным шарам.

Большая часть организаций знает, что SMB signing «надо включить» — и не включает. Причина банальна: на рабочих станциях Windows signing отключён по умолчанию, а его принудительное включение через GPO ломает старые принтеры, легаси-сканеры и ту одну 1С-шару, которая «работала 10 лет и не трогайте». В результате на каждом внутреннем пентесте NTLM relay отрабатывает без единого сбоя. Это не технический пробел — это организационный: решение принимает не безопасник, а менеджер, которому проще жить с риском, чем объяснять бухгалтерии, почему принтер на третьем этаже перестал печатать.

Кастомный NSE-скрипт тут помогает ровно одним — он даёт числа. Не «signing может быть отключён», а «137 из 200 хостов принимают неподписанные пакеты, вот XML, вот таблица, вот подпись аудитора». Цифры в отчёте работают лучше рекомендаций.

Что касается самих NSE-скриптов — порог входа в Lua ниже, чем кажется. Структура фиксированная: description, categories, portrule, action. Библиотека smb делает тяжёлую работу за тебя. Первый рабочий скрипт можно собрать за вечер. Второй — за полчаса. А третий уже будет закрывать конкретную задачу, которую ни один штатный скрипт не решает. Если тебе интересно разобраться не только в SMB, но и в фундаменте — как работают протоколы, что такое kill chain на практике и как проводятся первые проверки инфраструктуры — на IB Basics показывают именно это, без требований «вы должны знать Linux на уровне X».

Эту тему и смежные навыки разбирают на практике в курсе «Специалист по тестированию на проникновение» Codeby Academy.