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

Optionsbleed далеко не так опасен, как Heartbleed, поскольку работает лишь на серверах с определенными настройками, да и объем утекающих данных невелик. Но этот баг — из тех, что интересны сами по себе: изучив его, ты сможешь находить подобные или избегать их, если ты разработчик.

 

Стенд

Для успешных испытаний нам нужен веб-сервер Apache версии 2.2.34 и ниже или 2.4.27 и ниже, если речь идет о ветке приложения 2.4.х. Чтобы сократить время установки и настройки сервера, я рекомендую взять готовый докер-контейнер, в котором уже воссозданы все условия, необходимые для эксплуатации. Готовый файл, как водится, можешь найти у меня в репозитории.

docker run -p80:80 --rm --cap-add=SYS_PTRACE --security-opt seccomp=unconfined httpd:2.4.25

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

pkill httpd
gdb httpd
run -X -d /usr/local/apache2/
Подготовка к отладке веб-сервера
Подготовка к отладке веб-сервера

INFO

Optionsbleed назвали по аналогии с Heartbleed, где тоже утекала память процесса и атакующий мог ее читать. Options — от метода, которым производится атака.

 

Детали

Уязвимость существует, когда в директиве Limit используется несуществующий или отключенный метод HTTP. Например, разработчик решил запретить использовать PATCH, однако ошибся и создал такой .htaccess-файл:

<Limit PATC>
</Limit>

В тестовом контейнере этот файл уже создан и находится в папке test веб-рута. Теперь посмотрим, что происходит, когда мы посылаем запрос OPTIONS.

OPTIONS /test/ HTTP/1.1
Host: optionsbleed.visualhack

Каждый раз, когда выполняется обработка входящего запроса, веб-сервер создает для него request_rec. Это сложная структура, которая содержит информацию о нескольких соединениях. Сейчас нас интересует только apr_pool_t — пул памяти запроса.

/include/httpd.h
787: /**
788:  * @brief A structure that represents the current request
789:  */
790: struct request_rec {
791:     /** The pool associated with the request */
792:     apr_pool_t *pool;

В арсенале Apache нет изощренных техник для уменьшения фрагментации, увеличения эффективности и экономии памяти. Не используемая более память даже освобождается-то не особенно часто.

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

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

При выполнении приведенного выше запроса OPTIONS на самом деле выполняется несколько соединений с сервером. Когда обрабатывается первый коннект, выделяется память для хранения запроса.

/modules/http/http_core.c
135: static int ap_process_http_async_connection(conn_rec *c)
136: {
137:     request_rec *r;
...
146:         if ((r = ap_read_request(c))) {
147:
148:             c->keepalive = AP_CONN_UNKNOWN;
Указатель на память, выделенную для структуры request_rec
Указатель на память, выделенную для структуры request_rec

Сервер просматривает директорию, которая указана в запросе, и, если там есть файл .htaccess, он обрабатывается. За это отвечает функция ap_parse_htaccess.

/server/config.c
2149: AP_CORE_DECLARE(int) ap_parse_htaccess(ap_conf_vector_t **result,
2150:     request_rec *r, int override,
2151:     int override_opts, apr_table_t *override_list,
2152:     const char *d, const char *access_names)
2153: {
...
2223:     /* cache it */
2224:     new = apr_palloc(r->pool, sizeof(struct htaccess_result));

При парсинге директивы Limit сервер размещает ее данные в адресном пространстве запроса. Часть памяти выделяется для хранения метода HTTP, который указан в директиве. В нашем случае это строка PATC.

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

Вариант 1. Оформи подписку на «Хакер», чтобы читать все материалы на сайте

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

Вариант 2. Купи один материал

Заинтересовала информация, но нет возможности оплатить подписку? Тогда этот вариант для тебя! Обрати внимание: этот способ покупки доступен только для материалов, опубликованных более двух месяцев назад.


Оставить мнение

Check Also

Микросервисы по-микрософтовски. Пакуем приложения ASP.NET Core с помощью Docker

Кажется, Microsoft все больше и больше любит Linux! Приложения ASP.NET Core теперь по-наст…