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

Автоматизация перебора HTTP-методов на Python: скрипт вместо Burp Intruder

Автоматизация перебора HTTP-методов на Python: скрипт вместо Burp Intruder
Время чтения: 14 мин.

На HTB-машине GET-запрос к /admin/upload.php вернул 403 Forbidden. PUT к тому же URL — 200 OK, пустое тело, сервер принял запрос без вопросов. Скрипт на Python с библиотекой requests перебрал 11 HTTP-методов за три секунды и нашёл эту разницу. Через PUT загрузился PHP-шелл, через шелл — user-флаг. Девять строк кода, одна команда в терминале, переиспользование на каждой следующей машине.

Та же задача в Burp Intruder (модуль Burp Suite для массовой отправки запросов с подстановкой значений из списка) — это ручная настройка: выделить позицию метода в запросе, вбить список payload’ов, запустить, отсортировать результаты. Работает, но каждый раз заново. Скрипт работает из терминала, без GUI и умеет то, чего Intruder из коробки не даёт: добавлять произвольную логику после перебора.

Verb tampering и перебор HTTP-методов: место в цепочке атаки

HTTP-методы (их часто называют verbs — «глаголы») — команды, которые клиент (браузер, скрипт, curl) отправляет серверу вместе с URL. Самые частые: GET (получить данные), POST (отправить), PUT (заменить ресурс), DELETE (удалить), PATCH (обновить частично), HEAD (получить только заголовки без тела ответа), OPTIONS (узнать, какие методы сервер поддерживает для этого URL). Есть менее знакомые: TRACE (вернуть отправленный запрос обратно для диагностики), CONNECT (для туннелирования), а также WebDAV-методы — PROPFIND, MOVE, MKCOL, COPY, LOCK, UNLOCK. WebDAV (Web Distributed Authoring and Versioning) — расширение HTTP для удалённого управления файлами. Если оно включено на сервере и не защищено — это фактически полный доступ к файловой системе через HTTP. Полный реестр методов определён в RFC 9110 и расширениях к нему.

Verb tampering (подмена HTTP-метода) — атака, при которой вместо ожидаемого GET или POST отправляется другой метод. Этот процесс ещё называют HTTP verb fuzzing — перебор HTTP-методов для выявления нестандартного поведения сервера. Почему это работает: разработчики и администраторы часто настраивают контроль доступа только для GET и POST. Правило в конфигурации Apache вроде <Limit GET POST> блокирует два метода, но пропускает PUT, DELETE и всё остальное. В коде приложения — та же история: обработчик проверяет авторизацию в ветке if request.method == "GET", а для остальных методов проверки просто нет.

В терминах MITRE ATT&CK (открытая база тактик и техник атак; T-коды вроде T1190 — её идентификаторы) перебор HTTP-методов ложится на две фазы:

  • Разведка — Active Scanning: Wordlist Scanning (T1595.003): систематическое сканирование цели списком HTTP-методов для выявления разрешённых.
  • Начальный доступ — Exploit Public-Facing Application (T1190): если разрешённый метод позволяет загрузить файл (PUT), модифицировать данные (PATCH/DELETE) или раскрыть заголовки (TRACE) — это уже эксплуатация.

Дальше по цепочке: через PUT-загрузку размещается веб-шелл (Web Shell — T1505.003, тактика Persistence), атакующий получает выполнение команд на сервере. Одна неправильная директива в конфигурации — и цепочка от разведки до удалённого выполнения кода проходится за минуты.

По классификации OWASP (Open Worldwide Application Security Project — организация, публикующая стандарты безопасности веб-приложений) verb tampering попадает под A05:2021 — Security Misconfiguration: небезопасные конфигурации, оставленные по умолчанию. Разрешённые HTTP-методы, которые не нужны приложению и не защищены авторизацией — именно этот класс ошибок.

Бизнес-логика атаки: что даёт verb tampering злоумышленнику

Verb tampering — не теоретическое упражнение. Вот конкретные последствия, ради которых атакующий пробует подмену метода:

Обход 403 и загрузка файлов. Страница закрыта для GET, но открыта для PUT или PATCH. Атакующий записывает шелл или бэкдор в директорию, к которой не должен иметь доступа. На HTB (HackTheBox — платформа с уязвимыми виртуальными машинами для тренировки пентеста) это один из частых начальных векторов.

Модификация данных без авторизации. DELETE разрешён на API-эндпоинте без проверки прав — можно удалять записи, пользователей, файлы. PATCH без авторизации — менять пароли или роли. В терминах OWASP API Security Top 10 (десять критичных рисков для API) это связано с API1:2023 — Broken Object Level Authorization (BOLA): сервер не проверяет, что пользователь имеет право на действие с конкретным объектом.

Разведка через OPTIONS. Ответ на OPTIONS содержит заголовок Allow: GET, POST, PUT, DELETE, OPTIONS — перечень разрешённых методов прямым текстом. Один запрос — и карта доступных глаголов готова.

Кража заголовков через TRACE. TRACE возвращает отправленный запрос в теле ответа, включая все заголовки — Cookie, Authorization. Если приложение уязвимо к XSS (межсайтовый скриптинг), атакующий комбинирует XSS + TRACE для кражи токенов. Эта техника называется Cross-Site Tracing (XST).

Burp Intruder vs Python: альтернатива для автоматизации перебора методов

Burp Suite — основной инструмент веб-пентестера. Intruder — его модуль для массовой отправки запросов с подстановкой значений из списка. Для перебора HTTP-методов процесс в Intruder выглядит так:

  1. Перехватить запрос через Proxy → отправить в Intruder (Ctrl+I).
  2. Во вкладке Positions выделить название метода как точку подстановки: §GET§ /admin/upload.php HTTP/1.1.
  3. Во вкладке Payloads ввести список: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, TRACE.
  4. Запустить атаку, дождаться результатов, отсортировать по столбцу Status.

Работает. Но в трёх сценариях Python-скрипт удобнее.

Переиспользование. На HTB и в багбаунти проверяются десятки URL. Скрипт запускается одной командой: python3 verb_enum.py http://target/path. В Intruder каждый URL — новая итерация с ручной настройкой позиций и payload-списков.

Логика после перебора. Скрипт может автоматически отправить PUT с телом (шеллом), если метод вернул 200. Или распарсить заголовок Allow из ответа на OPTIONS и сузить дальнейший перебор. В Intruder для каждого такого шага нужен отдельный ручной запрос через Repeater.

Работа без GUI. На VPS через SSH, в пайплайне автоматизации, на Kali без рабочего стола — Burp с графическим интерфейсом неудобен. Community Edition (бесплатная версия) ещё и искусственно ограничивает скорость Intruder — запросы идут с задержкой. Python-скрипт отправляет запросы без ограничений.

Burp остаётся лучшим инструментом для интерактивной работы: Repeater для ручной правки запросов, встроенный рендеринг HTML-ответов, подсветка синтаксиса. Но для рутинного перебора методов, который повторяется на каждой машине, скрипт экономит время и масштабируется.

Python-скрипт для перебора HTTP-методов: делай раз, делай два, делай три

Предпосылки

  • Python 3.8+ — проверить: python3 --version.
  • Библиотека requests версии 2.32.0+ — установка: pip install 'requests>=2.32.0'. Версия 2.32.0 критична: в ней исправлена уязвимость CVE-2024-35195, подробнее — ниже.
  • Целевой URL. На HTB — IP машины с портом и путём, например http://10.10.10.X/admin/upload.php. Убедитесь, что VPN-соединение с HTB активно: ping 10.10.10.X должен получать ответы.
  • Текстовый редактор и терминал. Любой: nano, vim, VS Code. Скрипт сохраняется в файл verb_enum.py.

Шаг 1 — список методов и ключевой вызов requests.request()

Главное API-знание для этой задачи: функция requests.request(method, url) принимает любую строку в качестве HTTP-метода. Не нужны отдельные requests.get(), requests.post(), requests.put() — один вызов requests.request("PROPFIND", url) работает для любого метода, включая нестандартные и вымышленные. Один цикл по списку строк — и все варианты проверены. Вместо десяти разных функций — одна универсальная.

Список методов для перебора. Минимальный набор — стандартные по RFC 9110: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, TRACE, CONNECT. Расширенный — с WebDAV-методами: PROPFIND, PROPPATCH, MOVE, COPY, MKCOL, LOCK, UNLOCK. На практике хватает 11 методов; WebDAV добавляется, когда есть основания подозревать IIS или Apache с mod_dav.

Два параметра, без которых перебор не имеет смысла:

  • allow_redirects=False — без него requests автоматически следует за редиректами (301, 302). Вы увидите статус-код конечной страницы, а не первый ответ сервера на ваш метод. Для verb tampering нужен именно первый ответ — он показывает, как сервер обрабатывает конкретный метод.
  • timeout=5 — ограничение ожидания ответа в секундах. Без timeout скрипт зависнет, если сервер молчит. Пять секунд — разумный баланс между надёжностью и скоростью для HTB-машин.

Весь скрипт. Сохраните в файл verb_enum.py:

import requests, sys
url, methods = sys.argv[1], ["GET","POST","PUT","DELETE","PATCH",
    "HEAD","OPTIONS","TRACE","PROPFIND","MOVE","MKCOL"]
for m in methods:
    try:
        r = requests.request(m, url, timeout=5, allow_redirects=False)
        print(f"{m:10s} → {r.status_code} | {len(r.content)} bytes")
    except requests.exceptions.RequestException as e:
        print(f"{m:10s} → ERROR: {type(e).__name__}")

Построчно: sys.argv[1] — первый аргумент командной строки, URL цели. Список methods содержит все HTTP-глаголы для перебора. Цикл for m in methods проходит по каждому. requests.request(m, url, ...) — ключевой вызов, отправляет запрос с текущим методом. f"{m:10s}" — форматирование с выравниванием на 10 символов, чтобы вывод выглядел ровной таблицей. len(r.content) — размер тела ответа в байтах (помогает отличить осмысленный ответ от пустого). Блок except ловит все ошибки соединения — таймаут, отказ, DNS — и выводит тип исключения вместо падения скрипта.

Шаг 2 — запуск и чтение результатов

Запустите скрипт, передав URL целевого эндпоинта как аргумент:

$ python3 verb_enum.py http://10.10.10.X/admin/upload.php
GET        → 403 | 287 bytes
POST       → 403 | 287 bytes
PUT        → 200 | 0 bytes
DELETE     → 405 | 312 bytes
PATCH      → 405 | 312 bytes
HEAD       → 403 | 0 bytes
OPTIONS    → 200 | 0 bytes
TRACE      → 405 | 0 bytes

Как читать статус-коды — тут важно не просто видеть цифры, а понимать, что за ними стоит:

  • 200 OK — метод разрешён и обработан. PUT с кодом 200 — потенциальная загрузка файла. OPTIONS с кодом 200 — сервер раскрывает список разрешённых методов (проверьте заголовок Allow через curl -X OPTIONS -v http://target/path).
  • 403 Forbidden — сервер распознал метод, но запретил доступ. Если 403 приходит на GET, а PUT или PATCH возвращает 200 — это verb tampering в действии.
  • 405 Method Not Allowed — сервер явно отклоняет метод как неподдерживаемый для этого URL. Безопасная конфигурация — когда все ненужные методы возвращают именно 405.
  • 501 Not Implemented — сервер не реализует метод (характерно для WebDAV-методов на серверах без WebDAV).
  • ERROR: ConnectTimeout / ConnectionError — сервер не ответил. Возможна фильтрация на уровне файрвола или разрыв VPN-соединения.

Ключевой принцип: ищите расхождения. GET возвращает 403, а PUT — 200? Верный признак неполной настройки контроля доступа. Разница в размере тела ответа (bytes) тоже информативна: одинаковый размер у 403 и 200 может означать одну и ту же страницу ошибки; разный — разные обработчики и потенциально разное поведение.

Что делать с находками: если PUT вернул 200, следующий шаг — отправить PUT с телом запроса. Для проверки подойдёт curl -X PUT http://10.10.10.X/admin/test.txt -d 'hello' — если файл появился, сервер принимает запись. Но это уже эксплуатация, допустимая только на HTB-машинах или в рамках легального пентеста с разрешением.

Шаг 3 — сессии, заголовки и обход WAF через X-HTTP-Method-Override

На реальных целях и на части HTB-машин эндпоинт требует авторизации: без Cookie или Bearer-токена любой метод вернёт 401 Unauthorized или 302 с редиректом на логин. Для таких случаев используйте requests.Session() — объект, который хранит заголовки и куки между запросами. Куку берите из браузера: DevTools (F12) → вкладка Application → Cookies → скопируйте значение PHPSESSID или аналогичного токена.

Второй приём — заголовок X-HTTP-Method-Override. Некоторые фреймворки (Rails, Django REST Framework, Spring) позволяют переопределить HTTP-метод через этот заголовок: отправляете POST, но добавляете X-HTTP-Method-Override: DELETE — бэкенд обрабатывает запрос как DELETE. Зачем: WAF (Web Application Firewall — фильтр вредоносных HTTP-запросов) может блокировать нестандартные методы на транспортном уровне, пропуская POST. Заголовок Override обходит эту защиту — WAF видит легитимный POST, а приложение обрабатывает DELETE.

import requests, sys
s = requests.Session()
s.headers["Cookie"] = "PHPSESSID=abc123_from_browser"
url = sys.argv[1]
for m in ["PUT","DELETE","PATCH","TRACE"]:
    headers = {"X-HTTP-Method-Override": m}
    r = s.post(url, headers=headers, timeout=5, allow_redirects=False)
    print(f"POST+Override({m:7s}) → {r.status_code}")

Все запросы уходят как POST, но бэкенд обрабатывает их как PUT, DELETE, PATCH или TRACE благодаря заголовку Override. Куку подставляйте из реальной сессии. Если фреймворк не поддерживает X-HTTP-Method-Override, попробуйте альтернативные имена: X-Method-Override, X-HTTP-Method. Вариант _method часто передаётся как POST-параметр в теле запроса: data={"_method": "DELETE"} — это подход Ruby on Rails.

Обход 403 через verb tampering: типичные сценарии и готовый инструмент

Несколько устойчивых паттернов, которые встречаются на HTB-машинах и при реальном пентесте веб-приложений:

Apache с <Limit> вместо <LimitExcept>. Директива <Limit GET POST> в .htaccess или конфигурации виртуального хоста блокирует только перечисленные методы. Все остальные — PUT, DELETE, PATCH — проходят свободно. Правильная конфигурация — <LimitExcept GET POST>, которая блокирует всё кроме указанных. Одна директива — разница между безопасным и уязвимым сервером.

IIS с включённым WebDAV. На серверах Windows с IIS WebDAV иногда включён по умолчанию или остаётся от предыдущих конфигураций. Методы PROPFIND, MOVE, MKCOL позволяют перечислять содержимое директорий, перемещать файлы и создавать папки. Без авторизации — полный контроль над файловой системой через HTTP.

nginx с пропущенной limit_except. Директива limit_except в блоке location ограничивает доступ для всех методов, кроме перечисленных. Если администратор её не добавил — все методы разрешены и обрабатываются одинаково.

API-фреймворки без явной проверки метода. В Flask декоратор @app.route('/admin') без параметра methods= принимает только GET и HEAD. Но если маршрут настроен через класс-обработчик или middleware перехватывает запрос до роутера — могут пройти другие методы. В Django REST Framework APIView без явного списка http_method_names по умолчанию принимает GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS.

Нестандартные методы для обхода WAF. Некоторые WAF фильтруют по белому списку стандартных методов. Запрос с несуществующим методом (например, GETS или FOOBAR) может пройти WAF и быть обработан бэкендом как GET — если бэкенд отвечает на неизвестные методы обработчиком по умолчанию. Крайний случай, но на CTF-задачах встречается.

Готовый инструмент для быстрого скана — httpmethods от ShutdownRepo, open-source утилита на Python для автоматизации перебора HTTP-методов. Установка: pipx install git+https://github.com/ShutdownRepo/httpmethods. Запуск: httpmethods -u http://target/path. Утилита поддерживает прокси (-x http://localhost:8080 для логирования в Burp), куки (-b), кастомные заголовки (-H) и собственный словарь методов (-w). Для разовой быстрой разведки — хватает. Для кастомной логики (автоматическая отправка тела при 200, парсинг заголовка Allow, интеграция в пайплайн) — собственный скрипт на Python гибче и прозрачнее.

Безопасность скрипта: CVE-2024-35195 и verify=False в requests

При написании скриптов для пентеста часто добавляют verify=False — отключение проверки TLS-сертификатов. На HTB-машинах с самоподписанными сертификатами это избавляет от ошибок SSL. Но до версии 2.32.0 библиотеки requests этот параметр создавал скрытую проблему.

CVE-2024-35195 (CVSS 5.6, severity MEDIUM): если первый запрос в объекте Session отправлен с verify=False, все последующие запросы к тому же хосту продолжают игнорировать проверку сертификата — даже при явном verify=True. Поведение сохраняется на время жизни соединения в пуле. CWE-670 — Always-Incorrect Control Flow Implementation: логика проверки сертификата реализована с ошибкой в потоке управления.

Разбор CVSS-вектора: AV:L — атака возможна только локально (атакующий контролирует окружение скрипта). AC:H — высокая сложность (нужны специфические условия). PR:H — нужны высокие привилегии. UI:R — требуется действие пользователя. EPSS (Exploit Prediction Scoring System — оценка вероятности эксплуатации в течение 30 дней, шкала 0–1) = 0.0034, ниже медианы всех CVE. CISA (Агентство по кибербезопасности и защите инфраструктуры США) присвоило статус Track (мониторить) — активная эксплуатация не зафиксирована.

На практике это значит следующее: если скрипт использует Session() и первый запрос идёт с verify=False к HTB-машине, а потом тот же Session обращается к внешнему API (отправляет уведомление, логирует результат) — второй запрос тоже пропустит проверку сертификата. Это открывает возможность для MitM (перехвата трафика посредником). Для скриптов, работающих только с локальными HTB-машинами по HTTP без TLS, проблема не актуальна.

Решение: pip install 'requests>=2.32.0'. Red Hat выпустил исправления в RHSA-2024:3781 (Ansible Automation Platform), Ubuntu — в USN-8344-1. В PyPI пакет requests исправлен начиная с версии 2.32.0. Проверка текущей версии: python3 -c "import requests; print(requests.__version__)".

Половина вопросов в чатах начинающих пентестеров — «какой инструмент использовать?». Burp или ZAP. Nmap или masscan. Python или Go. Мой ответ: инструмент — наименее важная переменная. Скрипт из этой статьи — 9 строк. Каждую можно переписать на curl-однострочник, на Go, на PowerShell. Результат не изменится. Суть не в requests.request(), а в понимании, почему PUT проходит там, где GET заблокирован.

Я регулярно вижу одну и ту же картину: человек запускает готовый сканер, получает таблицу статус-кодов — и не знает, что делать дальше. PUT вернул 200 — и что? Без понимания, что PUT принимает тело запроса и записывает файл на диск, находка мертва. Без знания, что TRACE возвращает заголовки в теле ответа, не распознаешь вектор XST. Автоматизация перебора HTTP-методов без понимания протокола — иллюзия прогресса.

Мой подход: прежде чем автоматизировать перебор чего угодно — разберитесь, что перебираете. RFC 9110 — 20 минут на семантику методов. Дефолтная конфигурация Apache и nginx для каждого HTTP-глагола — ещё 15 минут. После этого скрипт пишется за пять минут, потому что вы точно знаете, что ищете и зачем. На WAPT эту цепочку — от verb tampering до загрузки шелла — проходят в двух модулях с лабами, и после них вопрос «PUT вернул 200, что дальше?» больше не возникает.

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