Многие сайты, расположенные в интернете, базируются на CMS. Часто это вполне
оправдано. Не стал исключением и официальный сайт одной конторы, обратившейся ко
мне по поводу тестирования на проникновение методом "черного ящика". Перейдем
сразу к делу, мой друг, – сейчас я расскажу тебе про все тонкости проведенного
аудита.
Поверхностный серфинг по сайту сразу же выявил админку, на которой в
заголовке страницы красовалась надпись "Система управления сайтами NetCat 3.0
Extra". Работать на уровне "black-box", конечно, креативно, но более
продуктивно – иметь возможность искать баги в режиме "grey-box" и "white-box".
Поэтому, не мудрствуя лукаво, с сайта производителя была загружена Demo-версия
этой движки. Гугление по баг-трекам результатов не принесло, а значит,
предстояло расковырять CMS самостоятельно.
Я загрузил к себе на машину полный комплект дистрибутива и с умным видом
проследовал все этапы а-ля "Next". Браузер отобразил диалог установки нового
сайта, – и через пару минут в моем распоряжении был полигон для тестирования.
Первый рубеж обороны
Первая преграда состояла в том, что все файлы NetCat закодированы с
использованием Zend. Но это защита от домохозяек. После того, как я достал из
своего арсенала комплект "dezend" (который можно легко найти на просторах Сети)
и обработал им все файлы, моему взору предстали откровения CMS – его сорцы.
Для облегчения работы стоило включить отладочный режим, а также отключить все
ненужные излишества: magic_quotes_gpc – это зло, отключаем его путем удаления
соответствующих строк из .htaccess, расположенного в корневой директории
web-сервера. Магические кавычки также включены в конфигурационном файле
/netcat/vars.inc.php, поэтому сбрасываем его значение в ноль и в этом файле. Там
же переопределяем переменную "$SHOW_MYSQL_ERRORS" в значение "On". Остался еще
файл php.ini, в котором переопределяем значения "display_errors" и
"display_startup_errors" в значение "On", и заодно меняем "error_reporting" в
"E_ALL & ~E_NOTICE". Перезапускаем демон apache. Вроде бы все, однако существует
возможность еще больше упростить поиск ошибок методом "серого ящика" –
отобразить в браузере все запросы, поступающие к БД MySQL. В нашем случае этого
можно добиться путем вставки "echo "$query<br>";" в файл sql_mysql.php в функцию
"query{}". Тогда все запросы, поступающие к БД, будут отображаться в браузере.
Отлично, можно перейти непосредственно к поиску багов в NetCat!
Пробежавшись по ссылкам тестового сайта и подставив одинарную кавычку в
произвольный запрос, NetCat сдался до начала боя. На запрос вида "/about/=1'"
браузер выплюнул заветную "You have an error in your SQL syntax". Это была
уязвимость типа "Слепое выполнение произвольных SQL-запросов" (Blind
SQL Injection). Техника эксплуатации подобных уязвимостей давно отработана и
заключается в том, что на основе логического выражения нужно определить
истинность какого-либо запроса, передаваемого в БД. Например, на запрос:
/about/=1'/**/OR/**/EnglishName='profile'/**/AND/**/1=1
web-сервер в данном случае ответит "HTTP 302 Found", и это будет означать
TRUE, а на запрос
/about/=1'/**/OR/**/EnglishName='profile'/**/AND/**/1=2
web-сервер ответит: "HTTP 404 Not Found", что будет означать FALSE. Используя
конструкции вида if(), ascii(), substring((SELECT...)) или LIKE, становится
возможным получить любую информацию в пространстве БД, к которой есть доступ в
соответствии с ACL. Можно даже читать произвольные файлы, если у пользователя БД
есть разрешение File_priv, а также заливать web-shell, если не экранируются
кавычки.
На этом, в общем-то, можно было и закончить поиск багов в исследуемой CMS,
эксплуатировав найденную уязвимость, если бы не одно "но". Магические кавычки
(magic_quotes_gpc) в дефолтовой конфигурации NetCat включены – и поэтому нужен
другой вектор проникновения. Побродив по тестовому сайту и убедившись в его
видимом отсутствии (что было найдено, не удовлетворяло условиям поиска), я решил
искать уязвимости посредством анализа исходных текстов приложения.
Анализ исходного кода
Для автоматизированного анализа исходного кода уже давно существует огромное
число инструментов, позволяющих за короткое время выявить потенциальные
уязвимости путем разбора кода. Разделяют два подхода к анализу – динамический и
статический.
Большее распространение получили именно статистические анализаторы (благодаря
простоте реализации). Такой инструментарий можно найти под все распространенные
языки программирования, в том числе под PHP (смотри, rats). Такой анализ в ряде
случаев выдает огромное число false positive либо вообще не находит ни одной
уязвимости в коде, который может быть просто напичкан различными багами. В связи
с этим подход методом статического анализа исходного кода применяется больше как
вспомогательный при ручном анализе кода.
Более эффективны динамические анализаторы. Таких продуктов не так уж и много
в силу их сложности (одну и ту же операцию можно выполнить бесконечным числом
вариаций, поэтому такие анализаторы должны хорошо уметь парсить синтаксис
языка). А цена по причине ограниченного круга потребителей достаточно высока.
Как следствие, в Сети подобные инструменты просто так не валяются. Стоит
отметить, что и динамические анализаторы кода могут не заметить логическую
уязвимость, присутствующую в приложении. Например, уязвимости типа
"Предсказуемое значение идентификатора сессии" (Credential/Session Prediction)
или "Небезопасное восстановление паролей" (Weak Password Recovery Validation)
будут пропущены.
За неимением инструментов динамического анализа исходных текстов приходится
пользоваться статическими анализаторами. Для этих целей необязательно
использовать чужую разработку, сойдет и grep/egrep. Используя могучий язык
регулярных выражений, можно найти ряд уязвимостей разного уровня критичности по
сигнатурному принципу. Конечно, придется на время включить мозг, но, в целом,
способ приемлем для простого ресерчинга. Например, конструкция "grep -R -i
"header[ (]" * | grep -i Location | grep "\$"" покажет потенциальные уязвимости
"Расщепление HTTP-запроса", которые могут существовать при передаче
необработанных данных функции header(). Использование этой уязвимости пригодится
в проведении фишинг-атак и различных атак на браузер пользователя.
Набор сигнатур ("='\"\.\$_", "=\"\./<?=(isset(\$_" и т.д.) позволяет легко
искать уязвимости типа "Межсайтовое выполнение сценариев". Также ищутся и более
интересные баги, например, такие как "Чтение произвольных файлов".
Ручная проверка подтверждает присутствие уязвимостей в ряде случаев. Так,
сформировав запрос вида
"/netcat/modules/netshop/post.php?system=../../../../.htaccess%00", можно
получить содержимое файла .htaccess, расположенного в корневой директории
web-сервера. К сожалению, все выявленные уязвимости сигнатурным поиском сорцов
NetCat попадали либо под client-side уязвимости, либо для их эксплуатации
требовалось использование кавычек. Это противоречило поставленному условию
поиска, и исследование плавно перешло в область ручного анализа исходных
текстов.
В недрах NetCat
В первую очередь анализу подверглись модули, отвечающие за аутентификацию и
авторизацию, а также модуль восстановления пароля. Явных признаков уязвимостей в
них нет, но присутствуют косвенные баги, которые теоретически могут быть
проэксплуатированы.
Я отложил на время модуль восстановления пароля и продолжил исследование.
Следуя по пути наименьшего сопротивления, занялся изучением отдельных модулей
CMS (через обращение к ним напрямую "/netcat/modules/модуль/"). Исследовав таким
образом приложение (особенно при включенном register_globals), порой удается
переопределить какие-либо внутренние переменные и, как следствие, обратиться к
различным функциям типа fopen(), include(), etc без фильтрации передаваемых в
них аргументов. Это, в общем-то, фундаментальная проблема всех web-приложений,
разработчики которых забывают осуществлять проверки того, откуда произошел вызов
серверного сценария.
В нашем случае такие проверки не выполняются. И это позволило выявить еще
одну слепую SQL Injection в сценарии "/netcat/modules/poll/index.php", для
эксплуатации которой не требуется использование одинарной кавычки. Уязвимый код:
list( $ProtectIP, $ProtectUsers ) = $db->get_row( "SELECT ProtectIP,
ProtectUsers FROM Message".$classID." WHERE Message_ID={$PollID}", ARRAY_N );
Не все так просто, как может показаться. Дело в том, что переопределить
переменную $PollID мы можем (register_globals установлен по умолчанию), а вот с
переменной $classID, прямо скажем, вышел косячок, – она определена самим
приложением. А в таблице Message1 нет колонок ProtectIP и ProtectUsers. Поэтому,
какой бы запрос не подставлялся в $PollID, мускуль его не исполнит, до того как
колонки не будут существовать в таблице.
К счастью, разобравшись в логике работы приложения, можно понять, каким
образом повлиять на изменение переменной $classID. Кроме того, имея доступ к
структуре БД, есть шанс подсмотреть, на что требуется переопределение этой
переменной. Потратив немного времени, реально сформировать запрос вида
/netcat/modules/poll/?cc=62&PollID=1, который с точки зрения MySQL будет
корректен. Ну а дальше – дело техники. Стоит только отметить, что тонкость
эксплуатации этой инъекции в том, что, каким бы правильным или неправильным
запрос ни был, для эксплуатации таких инъекций необходимо пользоваться
временными задержками, используя функцию benchmark().
Например, запрос вида:
/netcat/modules/poll/?cc=62&PollID=3/**/AND/**/1=if(1=2,benchmark(1,benchmark(2000000,md5(now()))),0)
логически является FALSE и поэтому браузер молниеносно отобразит страницу. А
такой запрос:
/netcat/modules/poll/?cc=62&PollID=3/**/AND/**/1=if(1=1,benchmark(1,benchmark(2000000,md5(now()))),0)
уже примет значение TRUE, вследствие чего выполнится функция benchmark() и, в
зависимости от производительности web-сервера, браузер отобразит страницу
приблизительно через 5-10 секунд. Становится возможным посимвольный перебор
каких-либо данных.
В результате проведенного исследования был написан POC-код, демонстрирующий
эксплуатацию выявленной уязвимости blind SQL Injection. Эксплоит позволяет
получить логин и хеш-значение от используемого пароля любого пользователя
(читай: администратора) приложения NetCat.
Тест на проникновение сводился к банальному запуску этого эксплойта в
отношении сайта клиента и к последующему восстановлению пароля администратора по
rainbow-tables (там, кстати, применяется MySQL-хеширование, и для восстановления
пароля использовался ресурс
hashcrack.com).
Занавес
Поиск server-side уязвимостей в популярных движках CMS – это крайне полезный
ресерч. Обладая знанием о наличии такой уязвимости, в зависимости от
популярности движки, можно пробить множество web-узлов. Но это нехорошо, поэтому
делать так не стоит :). Лучше использовать свои знания в мирных целях. Удачи!
Danger
Внимание! Информация представлена исключительно с целью ознакомления! Ни
автор, ни редакция за твои действия ответственности не несут!
Info
Используя могучий язык регулярных выражений, можно найти ряд уязвимостей
разного уровня критичности по сигнатурному принципу.
Изучение отдельных модулей CMS путем обращения к ним напрямую, при включенном
register_globals, порой позволяет переопределить какие-либо внутренние
переменные и, как следствие, обратиться к различным функциям типа fopen(),
include(), etc. без фильтрации передаваемых в них аргументов.