Обсудить проект

Nuclei templates: пиши свои, перестань быть скриптокиддером

28.09.2026

Хватит юзать чужие темплейты из репы как школьник с чужой домашкой — погнали учиться клепать свои. Держи мини-гайд в формате RedTeam-отчёта.

Почему скрипткидди не пишут темплейты

Community-темплейты из nuclei-templates — это база, но они детектят только то, что уже известно и запатчено. Ты сканишь чужой стек с кастомным API или самописной админкой — стандартные шаблоны молчат, а ты сидишь и думаешь, что цель «чистая». На самом деле ты просто не написал детект под конкретную аномалию. Свой темплейт — это твой личный 0day-радар: нашёл уязвимость руками через Burp — заверни в YAML и гоняй по всей подсети за секунды.

Точка входа: анатомия темплейта
Nuclei-темплейт — это YAML-файл с DSL-надстройкой поверх. Скелет всегда один:

id: my-custom-git-config-leak

info:
  name: Exposed .git config
  author: твой-ник
  severity: medium
  description: Утечка конфигурации git через публичный .git/config
  tags: exposure,git,misconfig

http:
  - method: GET
    path:
      - "{{BaseURL}}/.git/config"
    matchers-condition: and
    matchers:
      - type: status
        status:
          - 200
      - type: word
        part: body
        words:
          - "[core]"
          - "repositoryformatversion"

{{BaseURL}} и {{Hostname}} — динамические переменные, подставляются на каждый таргет автоматически. Это твой юниверсальный payload-шаблон, который летает по листу из тысяч хостов одинаково.

Матчеры — логика срабатывания

Всего 7 типов матчеров, и если ты знаешь только word — ты жжёшь, но недостаточно ярко:

  • status — сверка HTTP-кода ответа
  • size — длина контента
  • word — поиск строк в теле/заголовках
  • regex — регулярки для банеров версий
  • binary — hex-сигнатуры (магические байты файлов)
  • dsl — Go-подобные выражения с хелперами
  • xpath — выборка по XML/HTML-дереву

Самый сочный — dsl. Он открывает функции типа contains(), md5(), base64(), compare_versions(), dns_resolve():

matchers:
  - type: dsl
    dsl:
      - 'status_code == 200 && contains(body, "Spring")'
      - 'compare_versions(extracted_version, "< 5.3.39")'
    condition: and

Лайфхак: matchers-condition: and — требует совпадения всех, or — хотя бы одного. Забыл про это — получишь ливень false positive и админ будет ржать над твоим отчётом.

Экстракторы: тащи данные, а не просто галочку

Матчер говорит «есть» или «нет». Экстрактор — вытаскивает конкретное значение (версию, токен, заголовок) для дальнейшей цепочки атак:

extractors:
  - type: regex
    part: header
    name: server_version
    regex:
      - "Server: nginx/([0-9.]+)"

Дальше это значение можно прокинуть в DSL-матчер того же темплейта через compare_versions(server_version, "< 1.25.0") — вот тебе автоматизированная проверка на CVE без ручного грепа логов.

Пошаговый разбор: как рожается свой темплейт

  1. Найди уязвимость руками. Burp Suite, ручной реквест, curl — зафиксируй точный запрос и уникальный индикатор в ответе (не общую фразу типа «error», а что-то специфичное).
  2. Выбери протокол. http, dns, tcp, ssl, file, headless — под то, что реально тестируешь.
  3. Опиши info-блок. id, name, author, severity, tags — без этого темплейт даже не запустится валидацией.
  4. Пропиши request и матчеры так, чтобы они ловили именно твой кейс, а не полсети (иначе получишь FP-эпидемию).
  5. Валидируй синтаксис:
nuclei -validate -t your-template.yaml
  1. Тестируй с дебагом на своей уязвимой инстанции:

nuclei -t your-template.yaml -target vulnerable-instance.com -debug

Векторы атак, которые стоит зашить в пентест

  • Subdomain takeover / exposed .git, .env, .DS_Store — классика, но кастом под структуру конкретного проекта бьёт точнее community-шаблона.
  • CVE-цепочки с версией — DSL + compare_versions() даёт мгновенный скан парка серверов на конкретный патч.
  • Кастомные API-эндпоинты — если у цели самописный бэкенд, ни один публичный темплейт его не знает. Только твой.
  • SSRF/blind-инъекции через DNS-callback — используй протокол dns с интерактивным OOB-сервером (Interactsh) внутри матчера.

Не забывай про обфускацию нагрузки в payload’ах — голый <script>alert(1)</script> в word-матчере палится любым мониторингом за километр, эй, ты серьёзно забыл про это? 😏

Что дальше

Гоняй новый темплейт через -tags для группировки по проекту:

nuclei -t my-templates/ -tags custom -list targets.txt

И да — нашёл рабочий 0day-паттерн через свой темплейт? Молчи, как и положено 😎. Зашивай в приватную репу, а не пуш в публичный nuclei-templates.