Вообще, это мой первый опыт написания статьи на хабре, но с выпуска патча прошло несколько дней, и вдруг я решил поделиться самим процессом исследования.
Всем привет, я Daytrift Newgen, и вот моя простая и весьма смешная история обнаружения байпаса от начала исследований до патча и публикации advisory.
Этап 0 - Начало и эпичный финал исследований
Еще где-то в конце 2025 года я решил попробовать вкатиться в исследования open-source продуктов и, недолго думая, выбрал тему байпасов WAF, ибо любой коллега знает, насколько такие продукты бывают противными.
Начал я с немного другого ответвления - комбинации известных методик с обходом WAF как побочным эффектом. Тогда я выбрал HTTP Request Smuggling как путь к будущим байпасам. Сильно в этот этап углубляться не буду, отмечу лишь то, насколько убийственным был процесс постойки докеровских стендов для тестирования...но это было необходимым злом, которое в будущем сыграет ключевую роль в обнаружении обсуждаемой в этой статье баги.
Спустя череду неудач в создании стендов я сделал паузу. Но случилось то, что вернуло меня в фазу активных исследований — статья в канале «Поросёнок Пётр» с кратким разбором репортов обхода Vercel WAF. Это меня смотивировало, и я вернулся к работе.
Так я поменял исследуемый продукт - выбрал нишевый WAF на основе рулов OWASP CRS. Цель оставалась той же - полностью или почти полностью ослепить механизмы защиты. Для этого я использовал самую свежую версию. Вспомнив вышеуказанный пост, я решил начать экспериментировать с чарсетами. Меньше десяти минут ушло на цепочку "чтение логов -> определение вайтлистов". Упрощенный regex для чарсетов оказался примерно таким: utf-8|iso-8859-1?|windows-1252
Из этого стало понятно, с чем стоит бороться в первую очередь - WAF блокирует чарсеты, если они не в белом списке еще до того, как я продолжу атаку. В моменте я вспомнил, что есть такая замечательноя вещь, как MIME-тип multipart/form-data. И тут поворотный в моей голове момент - а что, если я попробую как-то "перезаписать" для WAF чарсет так, что вредоносный будет игнорироваться? Неожиданно, но именно эта затея отработала на все 100%.
Забегая немного вперед, что до самого CRS - cуть проблемы оказалась до ужаса простой. Правило 922110 просто перезаписывало хранимое в переменной TX:1 значение charset при каждом новом объявлении. Так через WAF может пройти незамеченной любая закодированная полезная нагрузка, достаточно лишь объявить в последней части multipart charset, входящий в белый список.
Так был готов первый PoC, который на свой github я выложил уже после патча вместе с уязвимым стендом. Дальше новогодняя ночь, и вдруг я резко задумался: "а что, если уязвимость куда шире и затрагивает далеко не только исследуемый мной WAF?", и не прогадал. Хорошенько отдохнув в первые дни нового года, я пересобрал стенд на чистом ModSecurity на Nginx перед бэкендом на Flask, который декодировал чарсеты из multipart, если на него мои данные пропустит WAF. Убедившись, что мой PoC работает, я перешел к следующему этапу.
Этап 1 - Репорт на почту OWASP
Я тщательно отполировал свой репорт и выслал его как Security Advisory на почту, указанную в github проекта ModSecurity. Скажу честно, я сильно нервничал на темы "А что если проигнорируют?", "А что если это false-positive?" и прочие. Сейчас я понимаю, что причин волноваться не было. Advisory позже перенаправили в репо CRS.
Этап 2 - Реакция разработчиков, присвоение внутреннего идентификатора уязвимости и выпуск патча
Весь этот этап продлился всего 4 дня, за что отдельное спасибо @fzipi и @airween, они отреагировали очень оперативно, учитывая то, сколько этапов от разбора проблемы до разработки патча за это время было пройдено.
Этап 3 - Публикация раскрытия и последующего блогпоста с разбором уязвимости
В этот день (6 января) вышел полный обзор на уязвимость, а в раскрытии на github уже красовалась CVE, которую запросили разработчики проекта.
Заключение
Так в недлинной статье я в общих чертах описал весь процесс от обнаружения до раскрытия. При написании я больше опирался на свой опыт в исследовании (что видно по непропорциональному размеру описания нулевого этапа, простите), но суть статьи не только в том, как неожиданная идея может привести к критической CVE с высоким импактом и, что немаловажно, большой распространенностью, но и в том, что разработчики продукта во всем процессе на самом деле делают огромную часть работы. Для меня процесс присвоения CVE всегда представлялся как какой-то долгий, утомительный формальный процесс, и на деле я очень рад, что я в этом ошибся.
Подводя итоги, хочу повторно поблагодарить разработчиков за содействие и напомнить всем, кто тоже задумывается начать собственные ресерчи — иногда одно решение не откладывать это на потом может сыграть ключевую роль в вашем карьерном росте и росте безопасности всемирной паутины.
