- Регистрация
- 23.09.18
- Сообщения
- 12.347
- Реакции
- 176
- Репутация
- 0
Год назад, 21 марта 2019, в
You must be registered for see links
на HackerOne пришел очень хороший
You must be registered for see links
от
You must be registered for see links
. При внедрении нулевого байта (ASCII 0) в POST-параметр одного из API-запросов веб-почты, который возвращал HTTP-редирект, в данных редиректа виднелись куски неинициализированной памяти, в которых чаще всего раскрывались фрагменты из GET-параметров и заголовков других запросов к тому же серверу. Это критическая уязвимость, т.к. запросы содержат в том числе сессионные куки. Через несколько часов был сделан временный фикс, который фильтровал нулевой байт (как потом выяснилось, этого было недостаточно, т.к. оставалась возможность инъекции CRLF /ASCII 13, 10, что позволяет манипулировать заголовками и данными HTTP-ответа, это менее критично, но все равно неприятно). Одновременно с этим проблема была передана аналитикам безопасности и разработчикам для поиска и устранения причин возникновения бага.
Почта Mail.ru — это очень непростое приложение, в формировании ответа может участвовать большое количество различных фронтенд/бекенд-компонентов, как опенсорсных (большое спасибо всем разработчикам свободного ПО), так и собственной разработки. Удалось исключить все компоненты кроме nginx и openresty и локализовать проблему до вызова
You must be registered for see links
в OpenResty-скрипте, который вел себя не так, как ожидалось (воткнуть нулевой байт или перевод строки через GET-параметры с rewrite в ngx_http_rewrite_module, который, согласно документации используется и, казалось бы, должен работать абсолютно аналогично не получится). Были устранены возможные последствия, добавлена максимально строгая фильтрация и было проверено, что фильтрация устраняет все возможные векторы. Но механизм, который приводил к утечке содержимого памяти так и остался загадкой. Через месяц багрепорт закрыли как разрешенный, а разбор причин возникновения бага отложили до лучших времен.OpenResty — это весьма популярный плагин, позволяющий писать Lua-скрипты внутри nginx, и он используется в нескольких проектах Mail.ru, поэтому проблема не считалась решенной. И спустя некоторое время к ней все-таки вернулись, чтобы понимать истинные причины, возможные последствия и составить рекомендации для разработчиков. В раскопках исходного кода участвовали
You must be registered for see links
и
You must be registered for see links
. Выяснилось что:- Nginx защищает GET-параметры от инъекции служебных символов и дает возможность использовать в rewrite только GET-параметры. Поэтому эксплуатировать инъекцию через контролируемые пользователем параметры в nginx не получается. POST параметры при этом не защищены. OpenResty позволяет работать и с GET и с POST параметрами, поэтому при использовании POST параметров через OpenResty появляется возможность инъекции специальных символов.
- В nginx при использовании rewrite с пользовательскими данными есть возможность directory traversal (и вероятно SSRF) в некоторых конфигурациях, но это известный факт, и он должен обнаруживаться статическими анализаторами конфигураций в
You must be registered for see linksиYou must be registered for see linksот Яндекс (да, мы его тоже используем, спасибо). При использовании OpenResty такую возможность легко пропустить, но нашу конфигурацию это не затрагивало.
- В nginx есть ошибка, приводящая к утечке содержимого памяти, если строка rewrite содержит нулевой байт. При отдаче редиректа nginx выделяет новый буфер памяти, соответствующий полной длине строке, но копирует туда строку через строчную функцию, в которой нулевой байт является терминатором строки, поэтому строка копируется только до нулевого байта, остаток буфера содержит неинициализированные данные. Подробный разбор можно найти
You must be registered for see links.
Дальнейшая реакция
О проблеме сообщили разработчикам nginx и OpenResty, разработчики не рассматривают проблему как ошибку безопасности в nginx, т.к. в самом nginx нет возможности эксплуатации ошибки через инъекцию спецсимволов, фикс
You must be registered for see links
был опубликован 16 декабря. За 4 месяца с момента репорта в OpenResty так же не было сделано каких-либо изменений, хотя было понимание, что необходим безопасный вариант функции ngx.req.set_uri(). 18 марта 2020 мы опубликовали информацию, 21 марта OpenResty выпустила
You must be registered for see links
, которая добавляет проверку URI.Portswigger
You must be registered for see links
хорошую статью и взял комментарии у OpenResty и Nginx (правда комментарий о том, что раскрывается только небольшой фрагмент памяти является неверной и вводит в заблуждение, это определяется длиной строки, следующей за нулевым байтом и, при отсутствии явных ограничений на длину может контролироваться атакующим).Так в чем же была ошибка и что делать, чтобы ее предотвратить?
Была ли ошибка в nginx? Да, была, потому что утечка содержимого памяти это в любом случае ошибка.
Были ли ошибка в OpenResty? Да, как минимум не был исследован и документирован вопрос о безопасности предлагаемой OpenResty функциональности.
Была ли допущена ошибка конфигурации / использования OpenResty? Да, потому что в отсутствии явного указания, было сделано непроверенное предположение о безопасности используемой функциональности.
Какая из этих ошибок является уязвимостью безопасности с баунти на $10000? Для нас это в общем-то не важно. В любом ПО, особенно на стыке нескольких компонент, особенно предоставляемых разными проектами и разработчиками никто и никогда не может гарантировать, что все особенности их работы известны и документированы и отсутствуют ошибки. Поэтому любая уязвимость безопасности возникает именно там, где она влияет на безопасность.
В любом случае, хорошей практикой будет нормализовать или максимально ограничивать/фильтровать входные данные, которые уходят в любой внешний модуль/API, если нет явных указаний и однозначного понимания, что этого не требуется.
Errata
По опыту
You must be registered for see links
, ради сохранения чистоты языка:баг баунти — конкурс охоты за ошибками
багрепорт — уведомление об ошибке
редирект — перенаправление
опенсорсный — с открытым кодом
errata — работа над ошибками