Следующая новость
Предыдущая новость

Игра в числа. Разбираем уязвимость Integer Overflow в веб-сервере nginx

25.10.2017 13:15
Игра в числа. Разбираем уязвимость Integer Overflow в веб-сервере nginx

Содержание статьи

  • Тестовый стенд
  • Немного о Range
  • Углубляемся в детали
  • Proof of concept
  • Эксплуатируем уязвимость (видео)
  • Выводы

В популярнейшем веб- и прокси-сервере nginx была обнаружена занятная уязвимость: специально сформированным запросом можно получить информацию о внутренней структуре приложения. Этот баг томился без малого десять лет, и подвержены ей версии с 0.5.6 и до 1.13.2 включительно — то есть с 2007 года по июль 2017-го. Nginx, как известно, используется на каждом третьем-четвертом сайте, так что изучить эту лазейку не помешает.

WARNING

Материал адpесован специалистам по безопасности и тем, кто собираeтся ими стать. Вся информация предоставлена исключительно в ознакомительных целях. Ни редакция, ни автор не несут ответственности за любой возможный вред, причиненный материалами данной статьи.

Тестовый стенд

Для проведения экспериментов нам понадобится тестовая площадка. Конечно, всегда можно самому установить и настроить нужный дистрибутив, но зачем, когда можно просто взять и сразу перейти непосредственно к опытам? Тем более наши китайские коллеги уже собрали готовую уязвимую среду и выложили ее в виде докер-контейнера. Скачать его можно из репозитория vulapps. На странице полно иероглифов, так что вот тебе команда, которая нужна для запуска сервера:

docker run --rm --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -d -p 80:80 medicean/vulapps:n_nginx_1 

Вообще, в этом репозитории ютится множество стендов для тестирования разных уязвимостей, советую изучить на досуге.

После успешного выполнения команды на 80-м порте у нас будет висеть подопытный веб-сервер nginx версии 1.13.1.

Если вдруг тебе захочется немного подебажить, то рекомендую приаттачиться к контейнеру и выполнить

apt-get update && apt-get install nano build-essential gdb nginx-dbg=1.13.1-1~stretch service nginx stop && service nginx-debug start ps -aux|grep nginx 

Теперь можно присоединяться к процессу (worker process) с помощью gdb.

gdb --pid <pid> 

Сразу предупреждаю, что импакт у уязвимости невесть какой, однако покопаться в ней интересно.

Немного о Range

Причина уязвимости — в некорректной обработке байтовых диапазонов в заголовке Range. Возможно, ты в курсе, что это такое, но давай на всякий случай повторим.

Игра в числа. Разбираем уязвимость Integer Overflow в веб-сервере nginx
Базовая информация о заголовке Range

Заголовок Range используется, когда нужно получить не полный ответ от сервера, а только его часть. Формат допустимых значений заголовка подробно описан в спецификации протокола HTTP 1.1 RFC2616.

Согласно стандарту, в качестве значений можно указывать диапазоны для выборки. Они состоят из двух частей: размерность диапазона и список правил выборки. В качестве размерности используются байты.

Range: bytes=[-]<begin>-[<end>][,] 

Саму выборку можно делать двумя способами. Первый — указать две позиции: начало выборки и ее конец. Причем стандарт четко определяет, что начальная позиция должна быть не меньше нуля, а конечная обязательно больше начальной или равна ей. Если это условие не соблюдается, то заголовок должен быть проигнорирован. Если в качестве последней позиции указано значение, которое больше размера запрашиваемого документа или равно ему, то последней позицией считается текущий размер документа в байтах минус один. То же самое касается тех случаев, когда конечная позиция не указана вообще.

К примеру, если размер документа 138 байт, то bytes=1-137 получит от сервера 137 байт информации, начиная со второго и заканчивая последним.

Игра в числа. Разбираем уязвимость Integer Overflow в веб-сервере nginx
Первый способ выборки части контента с помощью Range

Помимо этого, в ответе присутствует заголовок Content-Range, где после слеша указан полный размер документа, который мы запрашиваем.

Второй способ — выборка последних N байт тела документа. Если размер документа меньше, чем указанный в запросе, то будет выбран весь документ. Например, bytes=-7 запрашивает последние 7 байт.

Игра в числа. Разбираем уязвимость Integer Overflow в веб-сервере nginx
Второй способ выборки части контента с помощью Range

Также спецификация разрешает в одном заголовке Range указать несколько диапазонов, в качестве разделителя используется запятая.

Игра в числа. Разбираем уязвимость Integer Overflow в веб-сервере nginx
Использование нескольких байтовых диапазонов в заголовке Range

Отмечу, что если ответ сервера содержит заголовок Accept-Ranges, то он поддерживает получение данных частями, когда в запросах есть хидер Range. Но, конечно же, это не говорит со стопроцентной вероятностью о его поддержке или ее отсутствии. Так что рекомендую все проверять на практике.

Игра в числа. Разбираем уязвимость Integer Overflow в веб-сервере nginx
Наличие заголовка Accept-Ranges говорит о поддержке Range в запросах

Углубляемся в детали

В nginx за обработку заголовка Range отвечает модуль ngx_http_range_header_filter_module, который вызывает функцию ngx_http_range_header_filter.

/src/http/modules/ngx_http_range_filter_module.c
146: static ngx_int_t 147: ngx_http_range_header_filter(ngx_http_request_t *r) 148: { 

Если в пакете указан только один диапазон, то выводом информации занимается функция ngx_http_range_singlepart_header, а если несколько, то ngx_http_range_multipart_header.

Продолжение статьи доступно только подписчикам

Cтатьи из последних выпусков журнала можно покупать отдельно только через два месяца после публикации. Чтобы читать эту статью, необходимо купить подписку.

Подпишись на журнал «Хакер» по выгодной цене!

Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта, включая эту статью. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке

1 год

3200 р.

Экономия 1400 рублей!

1 месяц

490 р.

25-30 статей в месяц

Уже подписан?

Источник

Последние новости