Shellshock: аудит CGI на Apache после патча bash
После патча CVE-2014-6271 прошлись по всем хостам с mod_cgi. Нашли три CGI-скрипта с bash в shebang - два из них мёртвые. Описываем методику быстрого аудита.
Shellshock-эксплойты через CGI/Apache активно эксплуатируются в первые часы после публикации CVE-2014-6271
После экстренного патчинга bash мы не стали расходиться. Патч закрыл CVE-2014-6271, но вопрос «где у нас вообще крутится CGI с bash» оставался открытым. Ответ на него - это отдельная работа, и вот её мы и описываем.
Суть проблемы со стороны Apache: mod_cgi и mod_cgid при обработке запроса передают HTTP-заголовки в переменные окружения и запускают скрипт. Если скрипт вызывает bash - через shebang или явно, - уязвимый bash получает эти переменные и выполняет что угодно из заголовков. Пока bash не пропатчен, любой такой скрипт - открытая дверь.
После патча угроза снята, но список CGI-скриптов никуда не делся. Мы решили сделать полный аудит безопасности того, что вообще лежит под mod_cgi на клиентских серверах.
Шаг первый: найти серверы с активным mod_cgi
Первым делом собрали список хостов, где вообще включён Apache. Потом прошлись по каждому:
apache2ctl -M 2>/dev/null | grep -E 'cgi'
# или на CentOS/RHEL:
httpd -M 2>/dev/null | grep -E 'cgi'
Если в выводе есть cgi_module или cgid_module - сервер потенциально интересен. На нескольких хостах mod_cgi оказался включён по умолчанию ещё при установке Apache и никем не отключался - просто потому что «и так работает».
Шаг второй: найти CGI-скрипты
После того как определились с серверами, искали сами скрипты. Apache отдаёт CGI двумя способами: через ScriptAlias/ScriptAliasMatch или через Options +ExecCGI в конкретной директории. Смотрели в конфигах:
grep -rE 'ScriptAlias|ExecCGI' /etc/apache2/ 2>/dev/null
grep -rE 'ScriptAlias|ExecCGI' /etc/httpd/ 2>/dev/null
Потом шли в найденные директории и смотрели, что там живёт.
Шаг третий: проверить shebang
В каждом найденном скрипте смотрели первую строку:
find /var/www/cgi-bin/ -type f | xargs file | grep -i script
head -1 /var/www/cgi-bin/some-script.pl
Нас интересовало всё, где в shebang написано /bin/bash или /usr/bin/bash. Скрипты на /bin/sh или /usr/bin/perl - меньший приоритет, хотя тоже смотрели.
Что нашли
На трёх хостах обнаружилось суммарно три CGI-скрипта с bash в shebang. Одна находка - скрипт, который используется: небольшая внутренняя утилита, которую клиент написал несколько лет назад и периодически вызывает вручную. Его bash-зависимость была реальной: использовал массивы и подстановку переменных - синтаксис, который /bin/sh не поддерживает. Трогать не стали, но зафиксировали.
Два других скрипта - история классическая. Один оказался тестовым, написанным в 2009 году при первоначальной настройке сервера. Второй - деплойный хук от системы, которую клиент перестал использовать в 2011-м. Оба вызывались последний раз... не вызывались никогда в логах за доступный период. Просто лежали и ждали.
Удалили без переговоров - сначала уточнили у клиентов, получили подтверждение, что скрипты никому не нужны, и убрали. Заодно отключили mod_cgi на хосте, где никаких живых скриптов не осталось.
Пара наблюдений
Логи доступа - первый фильтр. Прежде чем тратить время на разбор скрипта, смотрели, когда он последний раз вызывался. Если в access.log нет обращений к этому пути за несколько месяцев - вопрос «нужен ли он вообще» задаётся сразу.
ScriptAlias без скриптов - не редкость. На одном сервере ScriptAlias /cgi-bin/ /var/www/cgi-bin/ был прописан в дефолтном конфиге Apache, сама директория существовала, но была пуста. mod_cgi включён, потенциально принимает запросы по этому пути - но скриптов нет. Формально не опасно, но зачем держать включённый модуль без цели - непонятно.
Bash через shebang vs. bash внутри скрипта. Мы смотрели на shebang, но есть ещё один вариант: скрипт на perl или python, который внутри вызывает system('/bin/bash ...') или открывает pipe в bash. Такие места тоже ловятся, но уже ручным просмотром кода, а не автоматически. В найденных скриптах такого не было, но иметь в виду стоит.
Состояние после аудита
Три проблемных скрипта - минус два (удалены), один остался под наблюдением. Один хост лишился mod_cgi полностью. На остальных хостах CGI-скриптов с bash не нашлось - либо CGI не используется вовсе, либо скрипты на perl.
Аудит занял несколько часов на несколько десятков серверов - не потому что сложно, а потому что нужно было ходить по конфигам руками и разбираться, что живое, а что артефакт. Автоматизировать можно, но написать скрипт для поиска быстрее, чем проверить находки.
Про дальнейшее hardening bash - отдельный пост, там есть что обсудить помимо обновления пакета.
- Shellshock (CVE-2014-6271): экстренный патчинг под ночь · 25 сентября 2014
- SSL-аудит nginx после Heartbleed: от B до A минимальными правками · 19 августа 2014