В Erlang/OTP обнаружен набор уязвимостей, затронувших преимущественно встроенный HTTP-сервер inets httpd, а также несколько смежных компонентов платформы. Проблемы позволяют удалённому неаутентифицированному злоумышленнику выводить сервер из строя, обходить защиту каталогов и манипулировать HTTP-трафиком при размещении httpd за обратным прокси. Уязвимы версии OTP начиная с 17.0, для ряда проблем - начиная с более поздних веток.
Детали уязвимостей
Значительная часть найденных дефектов относится к некорректной работе httpd с установленными ограничениями. Так, сервер не применяет задокументированный лимит одновременных подключений max_clients, который по умолчанию должен составлять 150. Фактически этот предел действует только при явной настройке параметра, а в конфигурации по умолчанию httpd принимает неограниченное число соединений. Этого достаточно, чтобы исчерпать доступные процессы, память и файловые дескрипторы, просто открыв множество подключений и удерживая их. Аналогичная проблема возникает при приёме тела запроса, разбитого на фрагменты: установленный лимит max_body_size проверяется лишь после получения целого блока данных, поэтому клиент может передавать тело бесконечно, заставляя сервер накапливать его в памяти без какого-либо ограничения.
Другой вектор отказа в обслуживании связан с некорректным значением размера фрагмента в запросе с передачей данных блоками. Если заголовки уже обработаны, а затем приходит строка, не являющаяся шестнадцатеричным числом, httpd не отклоняет запрос и не закрывает соединение. Вместо этого занимается рабочий процесс сервера и ожидает данных, которые злоумышленник не отправляет, при этом таймаут запроса уже отменён. Такой запрос не требует постоянной передачи данных - достаточно одного некорректного фрагмента, после чего соединение можно просто держать открытым, занимая один рабочий слот. Повторяя операцию, атакующий блокирует всех воркеров и делает сервис недоступным для легитимных клиентов. Отдельная разновидность этой атаки - отправка валидных заголовков с большим значением Content-Length и остановка после первого байта тела. Поскольку таймер чтения тела не восстанавливается, соединение зависает навсегда. Вместе эти уязвимости образуют семейство slowloris-подобных атак, не требующих высокой пропускной способности.
Помимо проблем с доступностью, в httpd обнаружены обходы аутентификации модуля mod_auth. Один из них связан с нормализацией пути: сервер соединяет корень документа и URI после нормализации, но не схлопывает повторяющиеся слэши. Запрос к двойному слэшу, например, к пути, начинающемуся с //, нормализуется в ту же строку с двумя слэшами, файловая система же при открытии файла обрабатывает их как один. В результате проверка регулярным выражением не находит совпадения с защищённым каталогом, и файл отдаётся без запроса учётных данных. Достаточно добавить один лишний слэш перед именем каталога. Второй вариант работает на файловых системах, не различающих регистр символов, таких как Windows и macOS: мод_auth выполняет сравнение с учётом регистра, тогда как файловая система открывает файл независимо от него. Замена букв в пути к защищённому ресурсу позволяет скачать его без аутентификации. Отдельный дефект проявляется при использовании в mod_auth хранилищ dets или mnesia: все каталоги получают общее пространство имён пользователей, из-за чего учётные данные, выданные для одного каталога, подходят для доступа к другим.
Кроме того, httpd неправильно обрабатывает несколько видов HTTP-сообщений, что создаёт условия для межзапросных подделок. Сервер принимает запросы, содержащие одновременно заголовки Transfer-Encoding и Content-Length, не закрывая соединение после ответа, как того требует спецификация. Это позволяет рассинхронизировать интерпретацию границ запроса между httpd и обратным прокси и протащить второй запрос внутри первого. Аналогичный эффект достигается при помощи перевода строки с последующим пробелом перед заголовком: httpd превращает такую строку в самостоятельный заголовок, тогда как прокси, следующий стандартам, склеивает её с предыдущим. Наконец, сервер молча отбрасывает заголовки, в которых перед двоеточием есть пробел. Если прокси пропускает такой заголовок Content-Length, httpd считает длину тела нулевой, а реальные байты тела воспринимает как начало следующего запроса. Успешная эксплуатация этих проблем позволяет обходить контроль доступа на уровне прокси и отравлять ответы другим пользователям.
За пределами httpd обнаружились схожие по сути проблемы в других компонентах. В SNMP-модуле, LDAP-клиенте eldap и HTTP-клиенте httpc используется неограниченное преобразование чисел неограниченной точности из строкового представления и обратно. Некоторые из этих операций выполняются в C-коде без возможности прерывания, поэтому обработка даже умеренно большого числа, которое злоумышленник может сгенерировать дешёвой операцией, надолго занимает поток планировщика. Атака приводит к замедлению или остановке узла. Эти дефекты оценены как умеренные, но они доступны удалённо и не требуют аутентификации.
Отдельно отмечается уязвимость в TCP-драйвере inet при использовании режима упаковки {packet,4}. Из-за ошибки в вычислении длины пакета со знаком возникает переполнение буфера приёма, которое может разрушить память виртуальной машины BEAM и вызвать её аварийное завершение. Хотя точная эксплуатация для выполнения кода маловероятна, крах узла возможен при подключении к открытому порту из ненадёжной сети.
Для всех перечисленных проблем опубликованы исправления. Закрытые версии включают OTP 29.0.6, 28.5.0.6 и 27.3.4.17, а также соответствующие исправления для подпакетов inets, snmp, eldap и erts. Пользователям рекомендуется обновить Erlang/OTP до одной из указанных версий. Если обновление невозможно, стоит использовать обходные меры: явно задавать в конфигурации httpd лимиты max_clients и max_body_size, включать проверку минимальной скорости передачи данных с помощью параметра minimum_bytes_per_second и размещать перед сервером обратный прокси, который нормализует пути и отклоняет некорректные заголовки. Для защиты от проблемы в inet driver следует ограничить размер пакета опцией packet_size и не использовать режим {packet,4} на портах, доступных недоверенным клиентам.
Массовое выявление несоблюдения задокументированных ограничений и расхождений между документацией и реальным поведением сервера показывает, что даже зрелые платформы с длинной историей остаются подвержены хорошо известным классам ошибок. Особую ценность уязвимости приобретают в конфигурациях за обратным прокси, где различия в обработке HTTP между системами превращаются в практические векторы атак.
Ссылки
- https://github.com/erlang/otp/security/advisories
- https://github.com/erlang/otp/security/advisories/GHSA-c3cq-q8x6-547g
- https://github.com/erlang/otp/security/advisories/GHSA-7j6m-4ffg-hg46
- https://github.com/erlang/otp/security/advisories/GHSA-qh2f-33hj-37qf
- https://github.com/erlang/otp/security/advisories/GHSA-6v7q-jwgh-cx8p
- https://github.com/erlang/otp/security/advisories/GHSA-5vp4-58hc-h8cc
- https://github.com/erlang/otp/security/advisories/GHSA-mh78-93cr-jx8f
- https://github.com/erlang/otp/security/advisories/GHSA-r4vv-vc2c-2fw6
- https://github.com/erlang/otp/security/advisories/GHSA-8m6r-2pj2-25pm
- https://github.com/erlang/otp/security/advisories/GHSA-cqx9-9hq6-m8wf
- https://github.com/erlang/otp/security/advisories/GHSA-9vgh-c8cm-m9p4
- https://github.com/erlang/otp/security/advisories/GHSA-q7cq-pfgf-5hr7
- https://github.com/erlang/otp/security/advisories/GHSA-mr35-8h7w-w3gq
- https://github.com/erlang/otp/security/advisories/GHSA-8qrh-x566-5xv5
- https://github.com/erlang/otp/security/advisories/GHSA-pwvh-c689-f8q5