stihl не предоставил(а) никакой дополнительной информации.
Фаззинг давно стал стандартным инструментом для поиска уязвимостей, но чаще всего — в контексте бинарных целей: взял AFL, выдал ему ресурсов и ждешь. В мире сетевых протоколов так не сработает, поэтому исследователи часто игнорируют его в этом контексте. Сегодня мы в руках с фаззером Boofuzz попробуем обойти все преграды.
Фаззинг — одна из техник автоматизированного тестирования, при которой цели (программе, протоколу, сервису и так далее) подаются на вход искаженные, неправильные, неожиданные или даже случайные данные в попытке сломать программу.
Почему именно такие данные? Все очень просто: программисты нечасто продумывают «неправильные» сценарии использования программ, полагаясь на то, что пользователь будет действовать разумно. Программе же все равно: что было написано, то и будет исполнено.
В результате слишком длинная строка, пустое поле или несовместимые параметры могут привести к вполне реальным сбоям в работе, которые могут не только нарушить логику исполнения, но и открыть доступ к возможностям, которых быть не должно (если ты понимаешь, о чем я).
По способам генерации данных методы фаззинга делятся на следующие виды:
Чем же бинарный фаззинг так хорош?
Главные мастодонты бинарного фаззинга — это Для просмотра ссылки Войдиили Зарегистрируйся и Для просмотра ссылки Войди или Зарегистрируйся.
Вот что происходит во время их работы:
или Зарегистрируйся на «Хабрахабре».
Несмотря на все ужасы, фаззинг протоколов все же реален, и люди им занимаются. Для этого было создано несколько прекрасных инструментов:
Давай пройдемся по «строительным блокам», из которых составляется описание задачи для Boofuzz.
или Зарегистрируйся.
Чтобы лучше понять, как все перечисленное работает, возьмем известный всем протокол HTTP и попробуем фаззить один конкретный заголовок.
В качестве цели мы возьмем заголовок User-Agent. Несмотря на то что он лежит на поверхности, именно его мутации приводили к самым разным результатам во многих коммерческих продуктах: от простого падения программы до получения заветного шелла в системе.
from http.server import HTTPServer, BaseHTTPRequestHandler
class SimpleHandler(BaseHTTPRequestHandler):
def do_GET(self) -> None:
print("=" * 40)
print("New request!")
print(f"Requested path: {self.path}")
print("Headers:")
for name, value in self.headers.items():
print(f"{name}: {value}")
print("=" * 40)
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write(b"OK\n")
def log_message(self, format, *args) -> None:
return
def run_server(host: str = "127.0.0.1", port: int = 8000) -> None:
httpd = HTTPServer((host, port), SimpleHandler)
print(f"[*] Started HTTP server on {host}:{port}")
httpd.serve_forever()
if name == "main":
run_server()
GET / HTTP/1.1
Host: 127.0.0.1
User-Agent: {Fuzzed data}
Connection: close
Для начала установим Boofuzz:
pip install boofuzz
Ну а дальше... открываем Для просмотра ссылки Войдиили Зарегистрируйся! Согласен, копаться в RFC ради чего бы ни было — то еще удовольствие (учитывая, как некоторые из них написаны). Тем не менее более простых и надежных вариантов мне найти не удалось.
Так как я некоторое время проработал с этим инструментом, я покажу шаблон, по которому обычно пишу фаззеры. Следовать ему или нет — твой выбор.
import boofuzz.helpers
import boofuzz
import time
import sys
import os
ROOT_DIR = os.path.dirname(os.path.abspath(file))
# Настраиваем соединение
class BaseFuzzer():
session: boofuzz.Session
host: str
port: int
def init(self, host: str, port: int) -> None:
self.host = host
self.port = port
self.session = boofuzz.Session(
target=boofuzz.Target(
connection=boofuzz.TCPSocketConnection(
host=self.host,
port=self.port
)
),
ignore_connection_reset=False,
receive_data_after_each_request=True,
receive_data_after_fuzz=True,
fuzz_loggers=[
boofuzz.FuzzLoggerText(
file_handle=sys.stdout
)
],
db_filename=f'{ROOT_DIR}/results/fuzz-{time.time()}.db'
)
# Формируем структуру запроса к серверу
def create_request(host: str, port: int) -> boofuzz.Request:
http_request = boofuzz.Request(
name='HTTP Request',
children=(
boofuzz.String(
name="Method",
default_value="GET",
fuzzable=False
),
boofuzz.Delim(
name="Delim-1",
default_value=" ",
fuzzable=False
),
boofuzz.String(
name="Path",
default_value="/",
fuzzable=False
),
boofuzz.Delim(
name="Delim-2",
default_value=" ",
fuzzable=False
),
boofuzz.String(
name="Version",
default_value="HTTP/1.1",
fuzzable=False
),
boofuzz.Static(
name="End-Section-1",
default_value="\r\n"
),
boofuzz.Static(
name="Host-Header",
default_value="Host: 127.0.0.1\r\n"
),
boofuzz.String(
name="User-Agent",
default_value="User-Agent: ",
fuzzable=False
),
boofuzz.String( # Здесь мы фаззим
name="User-Agent-Value",
fuzzable=True
),
boofuzz.Static(
name="Static-1",
default_value="\r\n",
),
boofuzz.Static(
name="Connection-Header",
default_value="Connection: close\r\n"
),
boofuzz.Static(
name="End-Section-2",
default_value="\r\n"
),
)
)
return http_request
# Запускаем фаззер
def fuzz(fuzzer: BaseFuzzer) -> None:
'''Fuzz all types of requests (watch below)'''
http_request: boofuzz.Request = create_request(fuzzer.host, fuzzer.port)
# В новом способе описания протоколов подключение запросов к сессиям происходит так
fuzzer.session.connect(http_request)
fuzzer.session.fuzz()
def main(host: str = "127.0.0.1", port: int = 8000) -> None:
if not os.path.exists(f'{ROOT_DIR}/results/'):
os.mkdir(f'{ROOT_DIR}/results/')
fuzzer: BaseFuzzer = BaseFuzzer(host, port)
fuzz(fuzzer=fuzzer)
if name == 'main':
main()
Логи сервера:
[*] Started HTTP server on 127.0.0.1:8000
========================================
New request!
Requested path: /
Headers:
Host: 127.0.0.1
User-Agent: !@#$%%^#$%#$@#$%$$@#$%^^**(()
Connection: close
========================================
========================================
New request!
Requested path: /
Headers:
Host: 127.0.0.1
User-Agent:
Connection: close
========================================
========================================
New request!
Requested path: /
Headers:
Host: 127.0.0.1
User-Agent: $(reboot)
Connection: close
========================================
...
Логи фаззера:
[2025-12-01 00:33:24,694] Info: Web interface can be found at Для просмотра ссылки Войдиили Зарегистрируйся
[2025-12-01 00:33:24,696] Test Case: 1: HTTP Request:[HTTP Request.User-Agent-Value:0]
[2025-12-01 00:33:24,696] Info: Type: String
[2025-12-01 00:33:24,696] Info: Opening target connection (127.0.0.1:8000)...
[2025-12-01 00:33:24,696] Info: Connection opened.
[2025-12-01 00:33:24,696] Test Step: Monitor CallbackMonitor#4344316656[pre=[],post=[],restart=[],post_start_target=[]].pre_send()
[2025-12-01 00:33:24,696] Test Step: Fuzzing Node 'HTTP Request'
[2025-12-01 00:33:24,696] Info: Sending 97 bytes...
[2025-12-01 00:33:24,696] Transmitted 97 bytes: 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20 31 32 37 2e 30 2e 30 2e 31 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 21 40 23 24 25 25 5e 23 24 25 23 24 40 23 24 25 24 24 40 23 24 25 5e 5e 2a 2a 28 28 29 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a 0d 0a b'GET / HTTP/1.1\r\nHost: 127.0.0.1\r\nUser-Agent: !@#$%%^#$%#$@#$%$$@#$%^^**(()\r\nConnection: close\r\n\r\n'
[2025-12-01 00:33:24,696] Test Step: Contact target monitors
[2025-12-01 00:33:24,696] Test Step: Cleaning up connections from callbacks
[2025-12-01 00:33:24,696] Check OK: No crash detected.
[2025-12-01 00:33:24,696] Info: Closing target connection...
[2025-12-01 00:33:24,696] Info: Connection closed.
[2025-12-01 00:33:24,697] Test Case: 2: HTTP Request:[HTTP Request.User-Agent-Value:1]
[2025-12-01 00:33:24,697] Info: Type: String
[2025-12-01 00:33:24,697] Info: Opening target connection (127.0.0.1:8000)...
[2025-12-01 00:33:24,697] Info: Connection opened.
[2025-12-01 00:33:24,697] Test Step: Monitor CallbackMonitor#4344316656[pre=[],post=[],restart=[],post_start_target=[]].pre_send()
[2025-12-01 00:33:24,697] Test Step: Fuzzing Node 'HTTP Request'
[2025-12-01 00:33:24,697] Info: Sending 68 bytes...
[2025-12-01 00:33:24,697] Transmitted 68 bytes: 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20 31 32 37 2e 30 2e 30 2e 31 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a 0d 0a b'GET / HTTP/1.1\r\nHost: 127.0.0.1\r\nUser-Agent: \r\nConnection: close\r\n\r\n'
[2025-12-01 00:33:24,697] Test Step: Contact target monitors
[2025-12-01 00:33:24,697] Test Step: Cleaning up connections from callbacks
[2025-12-01 00:33:24,697] Check OK: No crash detected.
[2025-12-01 00:33:24,697] Info: Closing target connection...
[2025-12-01 00:33:24,697] Info: Connection closed.
[2025-12-01 00:33:24,697] Test Case: 3: HTTP Request:[HTTP Request.User-Agent-Value:2]
[2025-12-01 00:33:24,697] Info: Type: String
[2025-12-01 00:33:24,697] Info: Opening target connection (127.0.0.1:8000)...
[2025-12-01 00:33:24,698] Info: Connection opened.
[2025-12-01 00:33:24,698] Test Step: Monitor CallbackMonitor#4344316656[pre=[],post=[],restart=[],post_start_target=[]].pre_send()
[2025-12-01 00:33:24,698] Test Step: Fuzzing Node 'HTTP Request'
[2025-12-01 00:33:24,698] Info: Sending 77 bytes...
[2025-12-01 00:33:24,698] Transmitted 77 bytes: 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20 31 32 37 2e 30 2e 30 2e 31 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 24 28 72 65 62 6f 6f 74 29 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a 0d 0a b'GET / HTTP/1.1\r\nHost: 127.0.0.1\r\nUser-Agent: $(reboot)\r\nConnection: close\r\n\r\n'
[2025-12-01 00:33:24,698] Test Step: Contact target monitors
[2025-12-01 00:33:24,698] Test Step: Cleaning up connections from callbacks
[2025-12-01 00:33:24,698] Check OK: No crash detected.
[2025-12-01 00:33:24,698] Info: Closing target connection...
[2025-12-01 00:33:24,698] Info: Connection closed.
...
Для более удобного просмотра отправляемых запросов есть веб-GUI, по умолчанию по адресу 127.0.0.1:26000.
Для просмотра ссылки Войдиили Зарегистрируйся
Этот пример позволит не только проверить работу самого фаззера, но и узнать, что стандартная библиотека HTTP-сервера Python корректно обрабатывает «плохие» значения в заголовках.
Для просмотра ссылки Войдиили Зарегистрируйся
Если хочешь развить этот пример, попробуй написать фаззер других заголовков или даже описать какой‑нибудь другой протокол. Кто знает, может, именно так ты сможешь найти новую уязвимость!
Пара слов о фаззинге
Прежде чем разбираться с сетевыми протоколами и, тем более, писать код, поговорим о фаззинге в целом.Фаззинг — одна из техник автоматизированного тестирования, при которой цели (программе, протоколу, сервису и так далее) подаются на вход искаженные, неправильные, неожиданные или даже случайные данные в попытке сломать программу.
Почему именно такие данные? Все очень просто: программисты нечасто продумывают «неправильные» сценарии использования программ, полагаясь на то, что пользователь будет действовать разумно. Программе же все равно: что было написано, то и будет исполнено.
В результате слишком длинная строка, пустое поле или несовместимые параметры могут привести к вполне реальным сбоям в работе, которые могут не только нарушить логику исполнения, но и открыть доступ к возможностям, которых быть не должно (если ты понимаешь, о чем я).
info
Как‑то мне задали занятный вопрос: в чем принципиальное отличие фаззинга от брутфорса (ведь и тот и другой отправляют кучу данных в попытке получить несанкционированный доступ)? Ответ на него лежал на поверхности: брутфорс перебирает по словарю в попытке легитимно (честно) пройти авторизацию, а фаззинг — это именно поиск уязвимости.Для чего используют фаззинг?
На данный момент для следующих задач:- Поиск уязвимостей — самый очевидный вариант. Большинство багов сегодня (особенно с учетом разрастающейся кодовой базы серьезных проектов) находятся именно с помощью фаззеров.
- Стресс‑тесты — неожиданно, но крайне приятно бывает знать, что твой условный сервер WebDAV не упадет после первого пустого запроса от curl.
- Обнаружение не критичных, но неприятных багов — согласись, мало радости, если твой сайт станет падать после какого‑нибудь «неправильного» запроса.
Виды фаззинга
Естественно, если есть разные задачи, то решают их разными видами фаззинга. Их разделяют в зависимости от способа генерации данных, полноты обратной связи и цели фаззинга.По способам генерации данных методы фаззинга делятся на следующие виды:
- Dumb fuzzing (он же фаззинг случайными данными) — один из самых примитивных подходов: передача цели случайных значений. К сожалению, сейчас такое срабатывает редко, но, как известно, «раз в год и палка стреляет».
- Mutational fuzzing (мутационный фаззинг) — наиболее популярный на сегодняшний день подход, основанный на мутации (изменении) примеров входных данных по всему диапазону возможных значений.
- Generation-based fuzzing (генеративный фаззинг) — не самый популярный, тем не менее нужный вид, позволяющий получить наиболее полное покрытие всех допустимых состояний.
- Greybox fuzzing (фаззинг методом серого ящика) — фаззер получает от программы обратную связь (чаще всего это покрытие кода), что позволяет умнее и быстрее находить баги.
- Blackbox fuzzing (фаззинг методом черного ящика) — иногда бывает такое, что из обратной связи есть только информация, продолжает ли цель функционировать после очередной порции данных. При отсутствии других вариантов это лучше, чем ничего.
- Binary fuzzing (бинарный фаззинг) — в качестве цели выступает бинарный файл (программа).
- Network fuzzing (сетевой фаззинг) — то же самое, но в качестве цели — сетевой протокол.
Бинарный фаззинг
Это, пожалуй, наиболее известный и популярный вид фаззинга. Неудивительно: благодаря своей результативности он получил огромную поддержку сообщества в виде множества инструментов и отличной документации.Чем же бинарный фаззинг так хорош?
- У него минимальный порог входа — чтобы начать фаззинг, иногда хватает просто бинаря и парочки хороших примеров для мутаций.
- Позволяет использовать покрытие кода — чаще всего фаззер получает обратную связь от программы, что позволяет ему быстрее находить способы тестирования тех или иных участков программы.
- Работает быстро, и скорость выполнения зависит от меньшего числа переменных (что, кстати, значит и меньше задержек).
Главные мастодонты бинарного фаззинга — это Для просмотра ссылки Войди
Вот что происходит во время их работы:
- Компиляция программы со специальными вставками‑флагами, необходимыми для измерения покрытия входа.
- Запуск цели с разными входными данными (основная часть работы).
- Сохранение данных, которые позволили открыть новые пути исполнения кода.
- Фиксация данных, при которых программа свалилась с ошибкой.
- интеграция лучших мутаторов;
- встроенная поддержка Для просмотра ссылки Войди
или Зарегистрируйся, Для просмотра ссылки Войдиили Зарегистрируйся, Для просмотра ссылки Войдиили Зарегистрируйся и некоторых других эмуляторов; - фаззинг без исходников путем пересборки программы с помощью Для просмотра ссылки Войди
или Зарегистрируйся.
Сетевой фаззинг
Сетевой фаззинг — это совершенно другой мир: он обладает рядом крайне неприятных особенностей, которые делают использование привычных инструментов попросту невозможным:- Сложность входных данных — в отличие от бинарей, где все параметры чаще всего можно описать при запуске программы, сетевой протокол требует многоступенчатого общения между клиентом и сервером.
- Необходимость правильной последовательности передачи — нужно не только организовать диалог, данные еще нужно передать в правильном порядке: инициализация → авторизация → выполнение команд.
- Меньше скорость, соединение ненадежно — мало того что скорость фаззинга замедляется (по подсчетам авторов AFL, разница может быть в сто раз!), пакеты могут теряться, что приводит к ложным срабатываниям.
- Сложность распараллеливания — если создать сто процессов одной и той же программы не проблема, то создать сеть из ста условных роутеров — та еще задача (даже если деньги не ограничены).
- Отсутствие обратной связи — чаще всего получить доступ к трейслогу программы невозможно и судить о том, смогла ли очередная порция данных сломать обработку, приходится лишь по наличию ответа от сервера, что сокращает количество потенциальных багов (и, кстати, отсылает нас к третьему пункту этого списка).
www
Кстати, если ты не знал, обработку сетевого взаимодействия чаще всего реализуют в виде конечного автомата (finite state machine), о них есть хорошая Для просмотра ссылки ВойдиНесмотря на все ужасы, фаззинг протоколов все же реален, и люди им занимаются. Для этого было создано несколько прекрасных инструментов:
- Для просмотра ссылки Войди
или Зарегистрируйся — ранее проприетарный фаззер, впоследствии ставший опенсорсным. Сложен в использовании и перестал активно развиваться. - Для просмотра ссылки Войди
или Зарегистрируйся — коммерческий фаззер. Не смогу о нем сказать что‑либо, так как не выпало возможности попробовать. - Для просмотра ссылки Войди
или Зарегистрируйся — расширение классического AFL, адаптированное под сетевые протоколы. «Из коробки» доступны некоторые популярные протоколы. Тестирование все еще происходит методом серого ящика, но в целом это выглядит как очень хороший вектор развития сетевого фаззинга. - Для просмотра ссылки Войди
или Зарегистрируйся — по сути, прародитель всех сетевых фаззеров. Сейчас заброшен, но заложил важные концепции направления. - Для просмотра ссылки Войди
или Зарегистрируйся — один из форков Sulley, разработанный в Cisco SAS и ориентированный на свои специфические задачи. - Для просмотра ссылки Войди
или Зарегистрируйся — еще один форк Sulley, на сегодня самый популярный выбор. Именно о нем мы и будем говорить дальше.
info
Ты тоже заметил отсылку к «Корпорации монстров», увидев, как называются три последних инструмента? И не зря: тулзы действительно названы в честь персонажей из мультфильма.Boofuzz
Для AFL особая настройка перед началом работы не нужна, а вот в случае с Boofuzz все чуть сложнее: первым делом нужно описать сам протокол и порядок сообщений, которые отправляются тестируемому серверу.Давай пройдемся по «строительным блокам», из которых составляется описание задачи для Boofuzz.
Сессии
Это обязательная сущность, описывающая:- адрес цели;
- транспорт, по которому будет происходить соединение;
- обработчики, срабатывающие до и после отправки сообщения;
- параметры логирования;
- особенности обработки ответов от сервера.
Блоки и примитивы
Это поля, с помощью которых мы и будем описывать протокол. В списке доступных вариантов:- статические данные;
- байты;
- строки;
- случайные данные.
Пишем свой первый сетевой фаззер
Куда же без практической части?Чтобы лучше понять, как все перечисленное работает, возьмем известный всем протокол HTTP и попробуем фаззить один конкретный заголовок.
В качестве цели мы возьмем заголовок User-Agent. Несмотря на то что он лежит на поверхности, именно его мутации приводили к самым разным результатам во многих коммерческих продуктах: от простого падения программы до получения заветного шелла в системе.
HTTP-сервер
Для большей наглядности мы напишем свой примитивный HTTP-сервер, который будет выводить информацию о полученном запросе:from http.server import HTTPServer, BaseHTTPRequestHandler
class SimpleHandler(BaseHTTPRequestHandler):
def do_GET(self) -> None:
print("=" * 40)
print("New request!")
print(f"Requested path: {self.path}")
print("Headers:")
for name, value in self.headers.items():
print(f"{name}: {value}")
print("=" * 40)
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write(b"OK\n")
def log_message(self, format, *args) -> None:
return
def run_server(host: str = "127.0.0.1", port: int = 8000) -> None:
httpd = HTTPServer((host, port), SimpleHandler)
print(f"[*] Started HTTP server on {host}:{port}")
httpd.serve_forever()
if name == "main":
run_server()
Фаззер
Структура нашего запроса будет выглядеть следующим образом:GET / HTTP/1.1
Host: 127.0.0.1
User-Agent: {Fuzzed data}
Connection: close
Для начала установим Boofuzz:
pip install boofuzz
Ну а дальше... открываем Для просмотра ссылки Войди
Так как я некоторое время проработал с этим инструментом, я покажу шаблон, по которому обычно пишу фаззеры. Следовать ему или нет — твой выбор.
import boofuzz.helpers
import boofuzz
import time
import sys
import os
ROOT_DIR = os.path.dirname(os.path.abspath(file))
# Настраиваем соединение
class BaseFuzzer():
session: boofuzz.Session
host: str
port: int
def init(self, host: str, port: int) -> None:
self.host = host
self.port = port
self.session = boofuzz.Session(
target=boofuzz.Target(
connection=boofuzz.TCPSocketConnection(
host=self.host,
port=self.port
)
),
ignore_connection_reset=False,
receive_data_after_each_request=True,
receive_data_after_fuzz=True,
fuzz_loggers=[
boofuzz.FuzzLoggerText(
file_handle=sys.stdout
)
],
db_filename=f'{ROOT_DIR}/results/fuzz-{time.time()}.db'
)
# Формируем структуру запроса к серверу
def create_request(host: str, port: int) -> boofuzz.Request:
http_request = boofuzz.Request(
name='HTTP Request',
children=(
boofuzz.String(
name="Method",
default_value="GET",
fuzzable=False
),
boofuzz.Delim(
name="Delim-1",
default_value=" ",
fuzzable=False
),
boofuzz.String(
name="Path",
default_value="/",
fuzzable=False
),
boofuzz.Delim(
name="Delim-2",
default_value=" ",
fuzzable=False
),
boofuzz.String(
name="Version",
default_value="HTTP/1.1",
fuzzable=False
),
boofuzz.Static(
name="End-Section-1",
default_value="\r\n"
),
boofuzz.Static(
name="Host-Header",
default_value="Host: 127.0.0.1\r\n"
),
boofuzz.String(
name="User-Agent",
default_value="User-Agent: ",
fuzzable=False
),
boofuzz.String( # Здесь мы фаззим
name="User-Agent-Value",
fuzzable=True
),
boofuzz.Static(
name="Static-1",
default_value="\r\n",
),
boofuzz.Static(
name="Connection-Header",
default_value="Connection: close\r\n"
),
boofuzz.Static(
name="End-Section-2",
default_value="\r\n"
),
)
)
return http_request
# Запускаем фаззер
def fuzz(fuzzer: BaseFuzzer) -> None:
'''Fuzz all types of requests (watch below)'''
http_request: boofuzz.Request = create_request(fuzzer.host, fuzzer.port)
# В новом способе описания протоколов подключение запросов к сессиям происходит так
fuzzer.session.connect(http_request)
fuzzer.session.fuzz()
def main(host: str = "127.0.0.1", port: int = 8000) -> None:
if not os.path.exists(f'{ROOT_DIR}/results/'):
os.mkdir(f'{ROOT_DIR}/results/')
fuzzer: BaseFuzzer = BaseFuzzer(host, port)
fuzz(fuzzer=fuzzer)
if name == 'main':
main()
Тестируем!
Запускаем сервер, запускаем фаззер... и видим, что он работает!Логи сервера:
[*] Started HTTP server on 127.0.0.1:8000
========================================
New request!
Requested path: /
Headers:
Host: 127.0.0.1
User-Agent: !@#$%%^#$%#$@#$%$$@#$%^^**(()
Connection: close
========================================
========================================
New request!
Requested path: /
Headers:
Host: 127.0.0.1
User-Agent:
Connection: close
========================================
========================================
New request!
Requested path: /
Headers:
Host: 127.0.0.1
User-Agent: $(reboot)
Connection: close
========================================
...
Логи фаззера:
[2025-12-01 00:33:24,694] Info: Web interface can be found at Для просмотра ссылки Войди
[2025-12-01 00:33:24,696] Test Case: 1: HTTP Request:[HTTP Request.User-Agent-Value:0]
[2025-12-01 00:33:24,696] Info: Type: String
[2025-12-01 00:33:24,696] Info: Opening target connection (127.0.0.1:8000)...
[2025-12-01 00:33:24,696] Info: Connection opened.
[2025-12-01 00:33:24,696] Test Step: Monitor CallbackMonitor#4344316656[pre=[],post=[],restart=[],post_start_target=[]].pre_send()
[2025-12-01 00:33:24,696] Test Step: Fuzzing Node 'HTTP Request'
[2025-12-01 00:33:24,696] Info: Sending 97 bytes...
[2025-12-01 00:33:24,696] Transmitted 97 bytes: 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20 31 32 37 2e 30 2e 30 2e 31 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 21 40 23 24 25 25 5e 23 24 25 23 24 40 23 24 25 24 24 40 23 24 25 5e 5e 2a 2a 28 28 29 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a 0d 0a b'GET / HTTP/1.1\r\nHost: 127.0.0.1\r\nUser-Agent: !@#$%%^#$%#$@#$%$$@#$%^^**(()\r\nConnection: close\r\n\r\n'
[2025-12-01 00:33:24,696] Test Step: Contact target monitors
[2025-12-01 00:33:24,696] Test Step: Cleaning up connections from callbacks
[2025-12-01 00:33:24,696] Check OK: No crash detected.
[2025-12-01 00:33:24,696] Info: Closing target connection...
[2025-12-01 00:33:24,696] Info: Connection closed.
[2025-12-01 00:33:24,697] Test Case: 2: HTTP Request:[HTTP Request.User-Agent-Value:1]
[2025-12-01 00:33:24,697] Info: Type: String
[2025-12-01 00:33:24,697] Info: Opening target connection (127.0.0.1:8000)...
[2025-12-01 00:33:24,697] Info: Connection opened.
[2025-12-01 00:33:24,697] Test Step: Monitor CallbackMonitor#4344316656[pre=[],post=[],restart=[],post_start_target=[]].pre_send()
[2025-12-01 00:33:24,697] Test Step: Fuzzing Node 'HTTP Request'
[2025-12-01 00:33:24,697] Info: Sending 68 bytes...
[2025-12-01 00:33:24,697] Transmitted 68 bytes: 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20 31 32 37 2e 30 2e 30 2e 31 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a 0d 0a b'GET / HTTP/1.1\r\nHost: 127.0.0.1\r\nUser-Agent: \r\nConnection: close\r\n\r\n'
[2025-12-01 00:33:24,697] Test Step: Contact target monitors
[2025-12-01 00:33:24,697] Test Step: Cleaning up connections from callbacks
[2025-12-01 00:33:24,697] Check OK: No crash detected.
[2025-12-01 00:33:24,697] Info: Closing target connection...
[2025-12-01 00:33:24,697] Info: Connection closed.
[2025-12-01 00:33:24,697] Test Case: 3: HTTP Request:[HTTP Request.User-Agent-Value:2]
[2025-12-01 00:33:24,697] Info: Type: String
[2025-12-01 00:33:24,697] Info: Opening target connection (127.0.0.1:8000)...
[2025-12-01 00:33:24,698] Info: Connection opened.
[2025-12-01 00:33:24,698] Test Step: Monitor CallbackMonitor#4344316656[pre=[],post=[],restart=[],post_start_target=[]].pre_send()
[2025-12-01 00:33:24,698] Test Step: Fuzzing Node 'HTTP Request'
[2025-12-01 00:33:24,698] Info: Sending 77 bytes...
[2025-12-01 00:33:24,698] Transmitted 77 bytes: 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20 31 32 37 2e 30 2e 30 2e 31 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 24 28 72 65 62 6f 6f 74 29 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a 0d 0a b'GET / HTTP/1.1\r\nHost: 127.0.0.1\r\nUser-Agent: $(reboot)\r\nConnection: close\r\n\r\n'
[2025-12-01 00:33:24,698] Test Step: Contact target monitors
[2025-12-01 00:33:24,698] Test Step: Cleaning up connections from callbacks
[2025-12-01 00:33:24,698] Check OK: No crash detected.
[2025-12-01 00:33:24,698] Info: Closing target connection...
[2025-12-01 00:33:24,698] Info: Connection closed.
...
Для более удобного просмотра отправляемых запросов есть веб-GUI, по умолчанию по адресу 127.0.0.1:26000.
Для просмотра ссылки Войди
Этот пример позволит не только проверить работу самого фаззера, но и узнать, что стандартная библиотека HTTP-сервера Python корректно обрабатывает «плохие» значения в заголовках.
Для просмотра ссылки Войди
Если хочешь развить этот пример, попробуй написать фаззер других заголовков или даже описать какой‑нибудь другой протокол. Кто знает, может, именно так ты сможешь найти новую уязвимость!
Особенности и недостатки Boofuzz
Несмотря на то что Boofuzz — это на данный момент наиболее развитый инструмент для сетевого фаззинга, у него есть и недостатки:- Неполная документация. Некоторые фичи Boofuzz не внесены в документацию, что создает интересные ситуации, в которых ты тратишь несколько часов жизни на создание кое‑как работающего костыля, а через пару дней узнаешь, что это можно было сделать намного проще и надежнее, достаточно всего лишь залезть в код.
- Небольшое комьюнити. С некоторыми вопросами тебе, скорее всего, будет не к кому обратиться, а поисковая система сможет только покрутить пальцем у виска.
- Малая распространенность новой системы описания протоколов. Найти готовый фаззер зачастую невозможно, а даже если получится, он, скорее всего, будет написан в соответствии со старой системой, более запутанной, чем новая.
Заключение
В конце дам пару советов, как сделать жизнь чуть проще:- Внимательно читай RFC. Это спасает от множества потраченных впустую часов из‑за неправильных входных данных.
- Не пытайся объять всё сразу! Если протокол большой, лучше фаззить в несколько этапов, чем убивать время на отладку тысяч строк кода.
- Четко определяй примитивы. Boofuzz по умолчанию фаззит практически все типы, что очень сильно увеличивает время, необходимое для прогона всех данных.
- Готовь отдельный стенд. Несмотря на то что сеть — не всегда надежный и быстрый способ передачи, правильно организованный стенд может свести потери к минимуму.
