CVE-2021-41773: как мы закрыли path traversal в Apache за 40 минут
CVE-2021-41773 в Apache HTTP Server 2.4.49 - path traversal и RCE. Рассказываем, как мониторинг аномалий URI поднял алерт раньше IDS и что было дальше.
CVE-2021-41773 - критическая уязвимость path traversal и RCE в Apache HTTP Server 2.4.49, массовая эксплуатация в первые часы после публикации PoC
6 октября опубликовали CVE-2021-41773 - path traversal в Apache HTTP Server 2.4.49, который при определённых условиях превращается в RCE. К вечеру того же дня в сети уже гуляли рабочие PoC, а сканеры стали методично прощупывать всё, что торчит на 80 и 443. Нам повезло: у одного из клиентов под managed-сопровождением алерт прилетел раньше, чем IDS успела что-то сказать. Вот как это вышло и что мы с этим сделали.
Откуда взялась уязвимость
Быстрый разбор для понимания масштаба. CVE-2021-41773 - это path traversal в нормализации пути. Apache 2.4.49 некорректно обрабатывает последовательности вида /../ в URL: сервер не отклоняет запрос, а резолвит его относительно корня файловой системы. Если mod_cgi включён и Options Indexes FollowSymLinks стоит в конфигурации - это уже RCE через передачу команды в CGI.
Запрос выглядит примерно так:
GET /cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh HTTP/1.1
Или вариант для чтения файлов без CGI:
GET /icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd HTTP/1.1
Процент-кодирование точки в .%2e - вот и весь фокус. Уязвимость затрагивает только 2.4.49; 2.4.48 и старее не уязвимы, 2.4.50 патч внесли. Для эксплуатации нужен require all denied отсутствующий или Require all granted в конфигурации каталога - то есть не совсем дефолтная конфигурация, но встречается часто.
Как мы узнали раньше IDS
Для клиента у нас настроен мониторинг на основе метрик из nginx/Apache access-логов, которые идут в Elastic Stack. Помимо стандартного - 5xx, latency, коды ответов - есть набор правил на аномалии в URI.
Одно из них: резкий рост доли запросов с процент-кодированными спецсимволами в пути - %2e, %2f, %2e%2e и подобными. В обычном трафике такие последовательности встречаются редко и в специфических контекстах. Когда сканер начинает методично слать /.%2e/.%2e/, профиль URI-трафика резко меняется.
Алерт сработал примерно через 10-15 минут после начала активного сканирования. IDS (Suricata) подняла сигнал позже - у неё правила на этот паттерн на тот момент ещё не были актуализированы под только что появившийся CVE. Суриката работает по сигнатурам, которые нужно обновлять; наш мониторинг на аномалии URI - по поведенческому профилю, который не зависит от того, знает ли база про конкретный CVE.
Это не попытка сказать, что IDS лишняя - сигнатурный движок ловит много того, что поведенческий пропустит. Но вот в этом конкретном кейсе порядок оказался обратным.
Следующие 40 минут
Хронология была примерно такая.
Т+0 - алерт. Дежурный получает уведомление: аномальный процент %2e/%2f в URI, источник - несколько IP из AS, которая нам не знакома. Смотрим в логи, видим характерный паттерн.
Т+5 - быстрая квалификация. Поиск по CVE, опубликованному несколько часов назад. Версия Apache у клиента - 2.4.49 (обновляли в рамках планового апгрейда за несколько дней до этого, не зная про уязвимость). Конфигурация mod_cgi - уточняем у клиента. CGI включён для одного легаси-скрипта.
Т+10 - проверка эксплуатации. Смотрим, были ли в логах до алерта запросы с похожим паттерном и 200-ми ответами. Находим несколько запросов с кодом 400 и один с 403 - попыток с успешным ответом нет. Это не гарантия, но снижает срочность с «у нас взломали» до «активное сканирование, пока без успеха».
Т+15 - временная мера. Пока готовится апгрейд, блокируем на уровне WAF/nginx запросы с %2e в пути вне контекста query string. Это грубо, но быстро. Для конкретного клиента это не ломает продуктовый трафик - паттерн не встречается в легитимных запросах.
Т+25 - апгрейд Apache. Репозиторий уже содержит 2.4.50 (Apache Software Foundation выкатила патч оперативно). На тестовой среде клиента проверяем поведение приложения - 5 минут. Всё нормально.
Т+35 - деплой на прод. Apache обновлён, сервис перезапущен, проверяем работоспособность.
Т+40 - подтверждение. Алерты затихли, сканирующие IP получают 400 на попытки эксплуатации - новая версия корректно отклоняет запросы. Инцидент закрыт.
Что это говорит про мониторинг
Несколько наблюдений по итогам.
Аномалии URI-профиля - дешёвый детектор. Правило не требует знания про конкретный CVE. Оно реагирует на изменение распределения запросов. Когда появляется новая атака, которая использует нетипичное кодирование или структуры URL - такое правило срабатывает раньше, чем появятся сигнатуры.
Версии компонентов нужно отслеживать явно. Мы знали, что у клиента Apache 2.4.49, потому что ведём инвентарь версий в рамках managed-сопровождения. Когда вышел CVE с прямым указанием версии, квалификация заняла минуты, а не часы.
Временная мера не равна фиксу. Блок на %2e в WAF - это способ выиграть время на нормальный апгрейд, не более. Если бы апгрейд по каким-то причинам затянулся - нужно было бы аккуратнее проработать правило, проверить на false positive и подумать про другие векторы.
CGI - это риск, который стоит явно инвентаризировать. В данном случае CVE без CGI давал только path traversal (читать файлы), а не RCE. Включённый mod_cgi с единственным легаси-скриптом - типичная ситуация «включили и забыли». После инцидента разговор с клиентом про этот скрипт стал проще: его переписали на нормальный стек и CGI отключили.
Суть происходящего сейчас такова: атаки на N-day уязвимости становятся всё быстрее - от публикации CVE до массовой эксплуатации счёт идёт на часы. Реагирование, которое занимает дни, перестаёт работать.