Как фаззинг нашёл DoS-уязвимость в ActivityPub-сервере snac2

· Безопасность
Начинающий исследователь под впечатлением от споров о будущем поиска уязвимостей взял популярный минималистичный сервер snac2 и за минуты фаззинга обнаружил удалённый отказ в обслуживании без аутентификации.

cover.svg

Автор блога Nullenvk рассказывает, как под впечатлением от дискуссий о том, останется ли поиск уязвимостей уделом человека в эпоху продвинутых LLM, он решил проверить простой вопрос: насколько трудно неопытному исследователю в 2026 году найти хотя бы одну ошибку средней тяжести в нетривиальном открытом проекте. Опыт у него был лишь по бинарной эксплуатации в CTF, реального софта он прежде почти не ломал.

Выбор цели

Ломать поделки, которыми пользуется горстка энтузиастов, автор счёл неинтересным, поэтому взял snac2 — минималистичный сервер ActivityPub, на котором работает множество мелких и несколько крупных инстансов Fediverse. Проект написан на C (со всеми классическими рисками работы с памятью), содержит собственные парсеры и при этом использует настоящие меры защиты — опциональный Landlock в Linux и pledge/unveil в OpenBSD.

Поверхность атаки

Автор ограничился кодом, доступным удалённому неаутентифицированному злоумышленнику. Оказалось, что POST-запрос с заголовком Content-Type: application/activity+json запускает разбор JSON ещё до проверки эндпоинта. Это и стало удобной мишенью.

Фаззинг

Вместо ручного чтения кода он натравил на функцию разбора JSON фаззер AFL++, написав простейший обвязочный код, который читает файл и передаёт его парсеру. Уже через минуты появились первые падения. Подозрительный ввод удалось упростить до последовательности с \u0000, после чего локальный сервер стабильно падал от небольшого запроса.

Суть ошибки

Причину нашёл его друг dzwdz, пока автор спал. В парсере есть проверка, заменяющая опасные управляющие символы на визуальные представления. Но условие strchr("\r\n\t", cp) при нулевом символе считает, что байт 0x00 входит в строку — ведь ноль является её терминатором. В результате нулевой байт попадает внутрь строки. Дальше размер буфера вычисляется через strlen, который на нулевом байте обрывается, и буфер бесконечно перевыделяется под тот же размер, тогда как новые символы пишутся за его пределы — классическое переполнение кучи.

Последствия и этика раскрытия

Маленький POST-запрос мгновенно роняет любой сервер snac2 — это удалённый отказ в обслуживании без аутентификации. Хуже того, вредоносный инстанс мог бы оформить легитимный объект ActivityPub, который распространялся бы по сети и валил другие узлы. Превратить переполнение в произвольную запись и полноценное RCE автору пока не удалось: мешают ASLR и защита указателей. Уязвимость уже исправлена (ссылка на коммит приведена в оригинале), запрос на CVE подан в MITRE, а публикация вышла спустя пару недель после выхода исправленной версии.


Источник: Lobsters

Комментарии

Войдите, чтобы комментировать.

  • Пока нет комментариев.