Введение в практическую безопасность (2019)/Эксплуатация SQL injection: различия между версиями

Материал из SecSem Wiki
Перейти к навигации Перейти к поиску
(UNION SELECT)
Строка 14: Строка 14:
  
 
Для такого кода
 
Для такого кода
 +
 
[[Файл:Sqli-code.png|650px]]
 
[[Файл:Sqli-code.png|650px]]
если параметр <code>login</code> будет иметь значение <code>admin' UNION SELECT * FROM users WHERE login = 'Kobzon'</code>
+
 
 +
если параметр <code>login</code> будет иметь значение <code>admin' UNION SELECT * FROM users WHERE login = 'Kobzon' #</code> результирующий запрос примет вид
 +
[[Файл:Union-triv.png|770px]]
 +
 
 +
Этот запрос "достанет" из базы данных две записи - соответствующие пользователям "admin" и "Kobzon". Это можно попробовать на стенде: http://sql1.stands.course.secsem.ru/by-login?login=admin'+UNION+SELECT+*+FROM+users+WHERE+login+=+'Kobzon'+%23
 +
Обратите внимание что решетка закодирована '''URL-кодированием''' ([https://en.wikipedia.org/wiki/Percent-encoding вики]) и выглядит как <code>%23</code>. В данном случае это необходимо, т. к. решетка в URL имеет специальное значение - отделяет '''хеш урла''' ([https://en.wikipedia.org/wiki/Fragment_identifier вики]), который не посылается на сервер вообще (как и сама решетка). То есть если её не закодировать то по неё URL просто обрежется.
 +
 
 +
Конечно, пример тривиальный, так как мы получаем те же колонки из той же таблицы, это можно было бы сделать и без <code>UNION</code>. Вот более интересный пример: если значение <code>login</code> будет <code>admin' UNION SELECT id,password,NULL,NULL,NULL FROM p4ssww0rdz WHERE id >= 2 #</code> то результирующий SQL-запрос примет вид
 +
 
 +
[[Файл:Union-p4ssww0rdz.png|900px]]
 +
 
 +
И в его результат попадут пароли всех пользователей с <code>id</code> начиная с 2. На стенде: http://sql1.stands.course.secsem.ru/by-login?login=admin'+UNION+SELECT+id,password,NULL,NULL,NULL+FROM+p4ssww0rdz+WHERE+id+%3e%3d+2+%23 (символ <code>></code> здесь также URL-закодирован).
 +
Здесь <code>NULL</code> "забивает" лишние колонки, то что их нужно было именно 3 можно понять из схемы данных ([https://course.secsem.ru/task-src/sql1.tgz код стенда выложен], там в таблице <code>users</code> 5 колонок, также это можно было получить подбором.

Версия 13:13, 15 марта 2019

Эксплуатация SQL injection

Краткое введение в то что такое SQL injection было в предыдущей статье, теперь о некоторых вещах которые может делать атакующий.

SQL-комментарий

Супер простой трюк. В конце своей инъекции можно добавить символы однострочного SQL-комментария, тогда всё что идет дальше (как правило, остаток исходного SQL-запроса) будет считаться комментарием и проигнорируется. В разных БД символы комментария могут разными, см. документацию, чаще всего это двойной минус -- и/или решетка #, также бывает классический двойной слеш //. Фактически, этот трюк уже был использован в примере в предыдущей статье, двойной минус в конце там заставил базу данных проигнорировать оставшуюся от исходного запроса одинарную кавычку в конце.

UNION SELECT

Очень полезным может быть UNION (вики,доки postgres,курс "Основы современных БД"), который позволяет присоединить к результу одного SELECT запроса результат еще одного. Если инъекция в операторе SELECT (что в реальности довольно часто), с помощью UNION можно добавить в его результат вывод нового, полностью написанного атакующим SELECT - запроса из друой таблицы, с другими колонками, условиями и т. д.

Чтобы UNION сработал, требуется чтобы количество и типы колонок совпадали. Помочь с этим может то что в SQL можно писать на месте колонок просто константы (и тогда они просто проставятся на эти места в каждой из строк результата запроса) и то что чаще всего можно использовать вместо любого значения NULL. Если количество колонок в исходном запросе неизвестно, можно просто подбирать его.

Для такого кода

Sqli-code.png

если параметр login будет иметь значение admin' UNION SELECT * FROM users WHERE login = 'Kobzon' # результирующий запрос примет вид Union-triv.png

Этот запрос "достанет" из базы данных две записи - соответствующие пользователям "admin" и "Kobzon". Это можно попробовать на стенде: http://sql1.stands.course.secsem.ru/by-login?login=admin'+UNION+SELECT+*+FROM+users+WHERE+login+=+'Kobzon'+%23 Обратите внимание что решетка закодирована URL-кодированием (вики) и выглядит как %23. В данном случае это необходимо, т. к. решетка в URL имеет специальное значение - отделяет хеш урла (вики), который не посылается на сервер вообще (как и сама решетка). То есть если её не закодировать то по неё URL просто обрежется.

Конечно, пример тривиальный, так как мы получаем те же колонки из той же таблицы, это можно было бы сделать и без UNION. Вот более интересный пример: если значение login будет admin' UNION SELECT id,password,NULL,NULL,NULL FROM p4ssww0rdz WHERE id >= 2 # то результирующий SQL-запрос примет вид

Union-p4ssww0rdz.png

И в его результат попадут пароли всех пользователей с id начиная с 2. На стенде: http://sql1.stands.course.secsem.ru/by-login?login=admin'+UNION+SELECT+id,password,NULL,NULL,NULL+FROM+p4ssww0rdz+WHERE+id+%3e%3d+2+%23 (символ > здесь также URL-закодирован). Здесь NULL "забивает" лишние колонки, то что их нужно было именно 3 можно понять из схемы данных (код стенда выложен, там в таблице users 5 колонок, также это можно было получить подбором.