Популярность 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/
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
— пул памяти запроса.
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
на самом деле выполняется несколько соединений с сервером. Когда обрабатывается первый коннект, выделяется память для хранения запроса.
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;
Сервер просматривает директорию, которая указана в запросе, и, если там есть файл .htaccess
, он обрабатывается. За это отвечает функция ap_parse_htaccess
.
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
.
Cтатьи из последних выпусков журнала можно покупать отдельно только через два месяца после публикации. Чтобы читать эту статью, необходимо купить подписку.
Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта, включая эту статью. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке
1 год4690 р. Экономия 1400 рублей! |
1 месяц490 р. 25-30 статей в месяц |
Уже подписан?
Читайте также
Последние новости