|
Professor Seleznov
|
 Привет! Ни для кого не секрет, что качественные вордлисты - это ключ к эффективному фаззингу и, как следствие, большему покрытию скоупа и хорошим файндингам во время пентеста и баг-баунти. Однако вордлисты в общем доступе далеко не всегда дадут достаточное покрытие, какими бы большими они ни были. У веб-приложения может быть свой специфический нейминг путей и параметров. Некоторые ручки могут находиться на внескоуповых доменах и дублироваться на скоуповых, иногда даже с измененной функциональностью. Часть параметров и вовсе не удастся найти без ручного анализа JavaScript-кода приложения. Здесь в игру вступают кастомные вордлисты, закрывающие все вышеперечисленные нюансы. Благодаря ним можно значительно эффективнее проводить фаззинг путей веб-приложения, а также брутить параметры его запросов. Эта статья - первая из цикла про кастомные словари, рассказывающая про сбор базового вордлиста без особых усилий. В следующей статье я расскажу про создание более комплексного кастомного вордлиста, требующего больших затрат по времени. А мне точно это нужно? Не важно, баунти-хантер вы или пентестер, большее покрытие таргета - это хорошо, ведь всегда есть шанс наткнуться на забытые разработчиками параметры и пути. Даже один новый найденный ассет может дать вам преимущество перед другими исследователями. Если у вас широкий скоуп с большим количеством поддоменов, шансы найти такие ассеты куда больше, чем на пентесте небольшой компании с парой поддоменов. Но даже в этом случае, если есть время, не стоит пренебрегать созданием кастомных вордлистов. Как-то раз во время пентеста небольшой компании благодаря кастомному вордлисту мне удалось обнаружить XSS в скрытом параметре на платёжной странице. Отдельно стоит упомянуть, что кастомные словари неплохо себя показывают на регулярных пентестах (Penetration Testing as a Service) и в баг-баунти на больших программах с регулярно обновляющейся кодовой базой. Формируя кастомный вордлист на основе текущего состояния системы, вы делаете его ключом к скрытой поверхности атаки в будущем. Например, вы перехватили JSON-ответы API аутентифицированного пользователя и получили слова, которые невозможно найти в веб-архивах, сфокусированных в основном на сохранении статики. Эти уникальные слова в данный момент могут не участвовать в активной логике приложения, но с большой вероятностью могут появиться в следующих итерациях разработки приложения во время вашего следующего тестирования. В рабочем флоу важно правильно распределять свое время и не делать самоцелью создание вордлиста. Иначе может случиться так, что вы потратите много времени на это в надежде найти скрытый функционал, но не успеете уделить достаточно внимания исследованию основной бизнес-логики таргета. Воспринимайте кастомные вордлисты как дополнительную часть OSINT. Лично я при пентесте составляю вордлист во второй половине работы, уже после того, как сделал базовый рекон и посмотрел основной функционал. После чего выборочно использую словарь, руководствуясь своей хакерской интуицией. Иногда не делаю кастомный вордлист вообще, если требуется проверить много бизнес-логики. Базовый кастомный вордлист Ниже написал процесс сбора базового кастомного вордлиста на примере тестового приложения. 1. Ручной краулинг с прокси Все начинается с того, чтобы вручную посетить таргеты с включенным прокси и собрать достаточное количество запросов. В своей работе я использую Firefox с расширением FoxyProxy, направляющим запросы в Burp Suite.


 Сохраненные в Burp Suite запросы и ответы нам понадобятся к концу этой главы, чтобы распарсить их через расширение и собрать вордлист. Автоматизированные краулеры смогут прокликать все статичные страницы, однако они плохо справляются с динамическим функционалом, поэтому без ручного этапа никуда. Зарегистрируйтесь в личном кабинете, поменяйте пароль, отправьте сообщение в поддержку, оплатите подписку и т.д. - сделайте все возможные действия, доступные через UI. Так вы получите больше запросов к API и соответствующих ответов сервера. 2. Автоматизированный краулинг Как я упоминал выше, посещением всех статичных страниц займется автоматика. Я использую краулер Katana - он достаточно быстрый, и в нем есть удобный динамический анализ ссылок в JavaScript-файлах. Не забудьте передать краулеру сессионную Cookie, если на таргете имеется функционал, закрытый за авторизацией. Запросы краулера аналогично проксируйте в Burp Suite. Также для перестраховки от блокировки WAF-ом советую менять User-Agent на стандартный агент браузера. Пример команды (можете заменить параметр глубины кроулинга -depth по вашему желанию, то же самое с рейт-лимитами в параметре -rl):
katana -u https://example.com (-list urls.txt) -depth 5 -js-crawl -jsluice -known-files all -proxy http://127.0.0.1:8080 -rl 100 -o katana-example-com.out -v -H 'User-Agent: xxx' -H 'Cookie: xxx=xxx'
 3. Фаззинг со стандартными вордлистами Также важно пофаззить пути веб-приложения общедоступными вордлистами, чтобы найти скрытые ручки и, самое главное, сохранить ответы на них. Содержимое ответов на открытой кастомной админ-панели может содержать достаточно много слов для нашего вордлиста, а JS-файлы на странице входа - еще больше. Для фаззинга я использую инструмент ffuf и вордлисты fuzz.txt, content discovery all.txt. Второй достаточно большой, его советую оставлять запущенным на ночь на VPS в tmux. Валидные страницы можно сразу отправлять в Burp через параметры -r -replay-proxyhttp://127.0.0.1:8080 (-r — следовать редиректам, -replay-proxy — направлять в прокси Burp Suite только те запросы, которые прошли фильтрацию). Это позволяет за один проход и собрать результаты фаззинга и запроксировать валидные эндпоинты в Burp. Если нужно отфильтровать другой код ответа, меняйте 403 в -fc на соответствующий (можно перечислять через запятую, например -fc 403,404). Пример команды:
ffuf -c -w fuzz.txt -u https://example.com/FUZZ -rate 80 -t 5 -fc 403 -H "User-Agent: Mozilla Firefox" -r -replay-proxy http://127.0.0.1:8080 -o ffuf/-fuzz.out
 4. Собираем URL из архивов через gau gau - инструмент, позволяющий собрать сохраненные URL домена на различных сайтах-архивах вроде webarchive.org. То есть, по сути, осуществить быстрый автоматизированный OSINT - найти URL, которые в приложении уже нигде не фигурируют, но остались в истории Интернета. Не игнорируйте этот шаг - очень много файндингов идёт именно отсюда. Пример команды:
cat | gau --blacklist ttf,woff,svg,png,jpg --fc 404 --o gau.out --verbose
На практике аргумент blacklist не всегда работает корректно, поэтому советую инверсивно грепать статику из вывода gau:
cat gau.out | grep -vE '\.ttf|\.woff|\.svg|\.png|\.jpg'
Полученные URL прогоняем через тот же ffuf, чтобы запроксировать их в Burp, как во втором шаге. Так как мое тестовое приложение локальное и не оставило следов в сети, для примеров, связанных с OSINT, буду использовать сайт www.spacex.com:
 5. Парсим JavaScript-файлы через xnLinkFinder xnLinkFinder - инструмент для краулинга и поиска URL в JavaScript-файлах. Примечателен тем, что умеет проверять относительные пути, а также собирать отдельный вордлист параметров, который мы потом совместим с нашим основным кастомным словарем. Инструмент нужен для увеличения покрытия - он находит ручки, скрытые в JS-файлах. Хотя инструмент и позиционируется как краулер, я не вижу смысла делать краулинг повторно после того, как мы сделали его через Katana. Поэтому рекомендую использовать xnLinkFinder как парсер для JavaScript-файлов. Сохраните запросы-ответы из Burp, выделив все URL в таргете - ПКМ - Save selected items - base64-encode requests and responses.

 Пример команды (-sp - домен со схемой для подстановки перед относительными URL, -sf - фильтр по одному или нескольким доменам в XML-файле Burp Suite, если их несколько):
xnLinkFinder -i -sp https://example.com -sf example.com -o xnlinkfinder.out -op xnlinkfinder-params.out -d 3
 В результате вы получите список найденных URL и вордлист с параметрами. Полученные URL также нужно спроксировать в Burp Suite через ffuf. 6. Формируем кастомный вордлист через GAP GAP - расширение для Burp от автора xnLinkFinder. Именно ради него мы проксировали все запросы в Burp на предыдущих этапах. Оно парсит все URL в таргете и составляет на их основе кастомный вордлист. Скачать его можете из BApp Store. Для более полного покрытия советую перед запуском расширения включить следующие опции:
- Include URL path words? (в Parameters mode и в Words mode)
- JSON params (в Request и Response Parameters)
- Cookie names
- Name and Id attributes of HTML input fields
- Include potential params?
- Params from links found
- Selected target(s)
Также укажите директорию в поле Auto save output directory и нажмите Save options. Для запуска: ПКМ по домену в Target - Extensions - GAP.
 В результате получаются два вордлиста (Params, Words) и список URL (Links). В завершение совмещаем вордлисты GAP-а с вордлистом параметров xnLinkFinder, удаляем дубли и получаем кастомный вордлист!
cat xnlinkfinder-deiteriypay-params.out http-deiteriypay.local/deiteriypay.local_20260414_155944_params.txt http-deiteriypay.local/deiteriypay.local_20260414_155944_words.txt | sort -u > wordlist-final.txt
 Использование вордлистов на практическом примере
Param Miner - расширение для Burp Suite от небезызвестного Джеймса Кеттла. Для начала его нужно настроить в одноименной вкладке сверху, указав ему наш вордлист и поставив галочку use custom wordlist. Также я использую некоторые другие опции, которые вы можете видеть на скриншоте.
 Запустить расширение очень просто - ПКМ по запросу - Extensions - Param Miner - Guess …
 Советую для каждого запроса выбирать логичные варианты: Guess query params для GET-запросов, body params для POST/PUT/PATCH-запросов. Guess cookies/headers советую сканить лишь один раз, логика с большой вероятностью будет повторяться на всем таргете (но, естественно, смотрите по ситуации). Если хотите побольше узнать про другие опции Param Miner’а, можете почитать об этом в нашей статье. После завершения сканирования видим новый Issue о том, что найден скрытый параметр internal_receipt_id на ручке deiteriypay.local:8090/checkout:
 Параметр internal_receipt_id был зашит в файл app.js и был успешно извлечён расширением GAP.
 Благодаря этому legacy-параметру на тестовом стенде удалось найти XSS:
 2. ffuf Кастомный вордлист не ограничивается брутом параметров. Он может быть использован и для фаззинга путей. Однако пути зачастую куда капризнее к неймингу, и на реальном таргете словарь с параметрами требует доработки, чтобы использоваться для фаззинга путей. Я не знаю ни одного инструмента, который умел бы анализировать нейминг путей и генерировать на его основе потенциальные URL. Нечто похожее реализовано в kiterunner - фаззере API, однако его функционал рекурсивного фаззинга ограничен встроенными вордлистами. Возможно, в этой задаче могут хорошо помочь нейросети. Если знаете подходящие инструменты для работы с кастомными словарями - делитесь в комментариях! Поэтому для грамотного покрытия таргета стоит уделить хотя бы немного времени ручному анализу нейминга URL и редактуре вордлиста с параметрами. Но, конечно, можно и просто закинуть вордлист с параметрами на фаззинг как https://example.com/FUZZ. На тестовом стенде, прочитав вордлист Links от GAP, можно увидеть, что в нейминге часто используется разделение нескольких слов через - и префиксы типа deiteriy-, deit-. Также мы знаем, что API расположен на /api/v1/.
 На основании этих данных сделаем мутации вордлиста с параметрами, добавив к словам, начинающимся со строчной буквы, префиксы, а также соединив эти слова через дефисы. Сканировать будем URL http://deiteriypay.local:8090/api/v1/FUZZ. Пример баш-скрипта для очистки и мутаций словаря будет приведен ниже. Мутации вордлиста стоит проводить на как можно более чистом и маленьком вордлисте, чтобы он не раздулся в размерах. Более подробно про очистку вордлистов я расскажу в следующей части статьи. А пока что приведу пример мутации вордлиста для тестового стенда. Я заметил, что в вордлисте много повторяющихся слов с заглавной буквы. Решил почистить вордлист, убрав слова с заглавной буквы и слова короче 3 символов, и сделать конкатенацию слов с дефисами и префиксами. Я написал баш-скрипт, но можно удобнее это делать через Python. В помощь с написанием простых скриптов рекомендую использовать ИИ.
#!/usr/bin/env bash set -euo pipefail INPUT="${1:-wordlist-final.txt}" OUTPUT="${2:-paths-mutated.txt}" PREFIXES="deiteriy deit" if [[ ! -f "$INPUT" ]]; then exit 1 fi ATOMS=$(mktemp) # Очистка и подготовка "атомов" sed 's/[-_]/\n/g' "$INPUT" | \ grep -v '[A-Z]' | \ awk 'length >= 3' | \ grep -vxE "$(echo $PREFIXES | tr ' ' '|')" | \ sort -u > "$ATOMS" # Генерация мутаций awk -v prefixes="$PREFIXES" ' BEGIN { np = split(prefixes, px, " ") } { a[NR] = $0; n = NR } END { for (i = 1; i <= n; i++) { print a for (p = 1; p <= np; p++) print px[p] "-" a } for (i = 1; i <= n; i++) { for (j = 1; j <= n; j++) { if (i == j) continue combo = a "-" a[j] print combo for (p = 1; p <= np; p++) print px[p] "-" combo } } }' "$ATOMS" | sort -u > "$OUTPUT" rm -f "$ATOMS"

 Вордлист получился внушительным, именно поэтому выше я упоминал, что для мутаций стоит работать с максимально очищенным вариантом словаря. Фаззинг API тестового стенда и результаты:

 Выводы Кастомные вордлисты могут помочь более широко покрыть таргет, а также найти скрытый функционал, недоступный при использовании стандартных вордлистов. Однако создание вордлистов - процесс не полностью автоматический и требует времени. Важно грамотно его распределять, воспринимая кастомные вордлисты как дополнение к OSINT. В итоге общий флоу создания кастомного вордлиста получается таким:
 Делитесь в комментариях мнениями насчет статьи, своими подходами к составлению и использованию вордлистов, а также инструментами, которые для этого применяете. Увидимся в следующей части! В ней я расскажу про более продвинутое составление кастомных вордлистов с добавлением во флоу OSINT, а также про утилиты и подходы к очистке словарей. Ещё затрону инструменты, которые помогают собрать вордлист без GAP - например, если вы используете Caido вместо Burp.-Источник
|