В прошлой статье мы уже рассматривали тему SQL-инъекций.

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

SQL-инъекция - это попытка злоумышленника изменить запрос к базе данных для ее компрометации.

Возможные SQLi:

  • Соблюдение условия WHERE к истинному результату при любых значениях параметров.

  • Объединение запросов через оператор UNION.

  • Комментирование части запроса.

Для того, чтобы обнаружить SQL-инъекции, тестировщику необходимо понимать функциональные требования, триггеры, бизнес-логику, основной сценарий веб-приложения и т. д.

Как выявлять SQL-инъекции

Статья носит информационный характер. Не нарушайте законодательство.

Ручной поиск

Шаг 1.

Во все параметры подставляем спецсимволы (кавычки, двойные кавычки и т.д. ). В первую очередь проверяются параметры, принимающие в качестве аргументов пользовательский ввод. Если при передаче сервер вернул ошибку, то есть подозрение на наличие инъекции. Когда веб-приложение не отреагировало на спецсимволы, то возможны 2 причины:

  • SQL-инъекции нет.

  • Отключен вывод ошибок на веб-сервере.

Пример:

http://example.com/?id=1’

http://example.com/?id=1”

http://example.com/?id=1’)

и т. д.

Шаг 2.

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

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

    Пример:

    ?id=1' union select null -- ?id=1' union select null,null -- ?id=1' union select null,null,null --

и т. д.

Поиск количества столбцов

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

2. Использование оператора ORDER BY для определения количества столбцов. В данном случае нужно опираться на появление ошибки о несоответствии количества столбцов в запросе. Стоит начать с большого количества столбцов и уменьшать их вдвое при каждой итерации проверки. Если количество не будет соответствовать фактическому значению, то вернется ошибка:

?id=1' order by 20 -- ?id=1' order by 10 -- ?id=1' order by 5 --

и т.д.

Проверка с помощью order by

3. Применение оператора GROUP BY, который основывается на обратном методе проверки, в отличие от ORDER BY.

Пример:

?id=1' group by 5 -- ?id=1' group by 10 -- ?id=1' group by 20 --

и т. д.

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

Пример:

?id=1’ union select 1,2,3,4 --

Когда уязвимый столбец найден, вместо его названия можем указать полезные команды для сбора информации о СУБД и получения данных из интересующих таблиц:

?id=1’ union select 1,null,version(),null - версия СУБД
?id=1’ union select 1,null,database(),null - текущая база данных
?id=1’ union select 1,null,@@port,null - порт, используемый СУБД
?id=1’ union select 1,null,user(),null - пользователь СУБД
?id=1’ union select 1,null,table_name,null from information_schema.tables – список таблиц с применением information_schema.

Шаг 3.

Если наличие инъекции при подстановке спецсимволов не подтвердилось, то воспользуемся одной из техник поиска слепых инъекций:

  • Boolean Based SQLi

Такой метод эксплуатации слепых SQL-инъекций, при котором информация извлекается исходя из реакции на условные выражения. Атака называется «слепой» в тех случаях, когда нет видимой реакции от веб-приложения. Например, при подстановке кавычек в потенциально уязвимый параметр, ошибка, связанная с нарушением логики SQL-запроса, не появляется, а страница отображается без изменений.


Пример:

?id=1 and 1=1

В этом случае содержимое страницы останется неизменным, потому что оба условия в операторе SQL истинные. Если изменить условие на 1 = 2, то ничего не возвращается, так как 1 не равно 2, а должны выполняться оба условия.

?id=1 and 1=2
  • Time Based SQL-injection 

Существует метод, при котором используются функции СУБД (например, SLEEP), вызывающие задержку ответа от базы данных. Такой способ также применяется для эксплуатации слепых инъекций, когда отсутствует какой-либо вывод информации, в том числе в случаях, описанных в Boolean Based SQL-injection.

Пример:

?id=1 and sleep(10)

Функция sleep() выполнится на стороне СУБД при условии обращения к записи с id=1 соответствующей таблицы. Возможно использование функций BENCHMARK или WAITFOR.

Пример:

BENCHMARK(5000000,ENCODE('MSG','by 5 seconds'));

id=1' waitfor delay '00:00:10' (MS-SQL);

pg_sleep() (PostgreSQL).

  • Stacked Query Based SQL-injections

В SQL точка с запятой указывает на конец запроса, после которого можно начать новый. Это позволяет выполнять несколько операторов в одном вызове сервера базы данных. В отличие от UNION-Based, который ограничен операторами SELECT, составные запросы могут использоваться для выполнения любой процедуры SQL. Стоит также отметить, что не все БД поддерживают эту функцию. Например, при использовании MySQL и SQLite3, нельзя воспользоваться этими операторами запросов, но в PostrgeSQL такая возможность есть.

Пример:

?id=1; delete from table_name

Автоматизированный анализ

SQLmap - мощный кроссплатформенный консольный инструмент для поиска, эксплуатации SQL-инъекций любого вида и сложности, написанный на языке Python.

Основные функции SQLmap:

  • полная поддержка системы управления базами данных (MySQL, Oracle, PostgreSQL, Microsoft SQL Server, Microsoft Access, IBM DB2, SQLite, Firebird, Sybase, SAP MaxDB и HSQLDB) и прямое подключение к ним;

  • автоматическое распознавание форматов хешей паролей и предложение их подбора с использованием атаки по словарю;

  • поддержка выполнения произвольных команд на ОС сервера БД, получение их стандартного вывода при использовании MySQL, PostgreSQL или Microsoft SQL Server и многое другое.

Основные ключи, которые используют при работе с MySQL : --dbs, -D,T,C, --level,--risk, --random-agent.

Пример:

# sqlmap -u http://example.com/?id=1 --dbs

# sqlmap -u http://example.com/?id=1 -D test_db -T test_tables –dump

Дамп пользовательской таблицы

JSQ injection - еще один кроссплатформенный инструмент для выявления SQL-уязвимостей, написанный на языке Java и имеющий графический интерфейс. Этот инструмент поддерживает работу с 33 базами данных (Access, Altibase, Firebird, MemSQL, MySQL, Oracle, PostgreSQL, Presto, SQLite, SQL Server и т.д). По набору функций jSQL injection собрал в себе средство поиска и эксплуатации SQLi, функционал Dirb и Hashcat:

  • поддержка различных видов инъекций (стандартные, error-based, stacked-based, blind и time-based);

  • создание и внедрение веб-шелла и SQL-шелла;

  • аутентификация с использованием Basic, Digest, NTLM и Kerberos;

  • прокси-соединение по HTTP, SOCKS4 и SOCKS5;

  • кодирование и декодирование текста;

  • перебор паролей по хешу и др.

Пример:

Просмотр содержимого таблиц

SQLmap и jSQL injection поддерживают поиск уязвимостей в cookie. За счет более обширной базы пейлоадов, использование SQLmap при выявлении уязвимостей будет приносить положительный результат намного чаще.

Защита от SQL-инъекций

Встречаются SQL-инъекции в числовом и строковом параметрах в запросах, использующих оператор SELECT, которые являются самыми распространенными. Поэтому проверять нужно всё: числа, строки, даты и другие данные в специальных форматах.

1) Числа

Функция is_numeric(n) используется для проверки переменной на числовое значение, которая вернёт true, если параметр n - число, а в противном случае - false. Также переопределить тип возможно вручную.

Пример:

if (isset($_GET['id'])){ $id = $_GET['id']; if ( is_numeric($id) == true){ … }

2) Строки

Компрометации через SQL-конструкции происходят и по причине нахождения в строках небезопасных кавычек и других специальных символов. Для предотвращения такой угрозы необходимо использовать функцию addslashes($str), которая возвращает строку $str с добавленным обратным слешем (\) перед каждым специальным символом. Данный процесс называется экранированием. Для этого в PHP используют две функции:

mysqli($str) и mysqli_real_escape_string($str).

3) Параметризированные запросы (PDO)

PDO заставляют разработчика сначала определить весь код SQL, а затем передать каждый параметр в запрос. Это позволяет БД различать код и данные независимо от того, что вводится пользователем. Подготовленные операторы гарантируют, что злоумышленник не сможет изменить логику запроса, даже, если атакующий вставляет команды SQL. Правильно параметризированный запрос не позволит базе данных обработать информацию о пользователе, как часть SQL-запроса. Для обхода аутентификации злоумышленник может использовать конструкцию:

аdmin’ or ‘1’=’1

При использовании PDO сначала передается запрос в БД, а потом в него подставляются данные из переменных. Таким образом, за имя пользователя будет приниматься вся строка admin’ or ‘1’=’1, введенная им, что не позволит хакеру проэксплуатировать SQL-инъекцию.

Пример кода:

if (isset($_GET['id'])){

$id = $_GET['id'];

if ( is_numeric($id) == true){ 

try{

$dbh = new PDO('mysql:host=localhost;dbname=sql_injection_example', 'dbuser', 'dbpasswd');

 $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 

$q = "SELECT username FROM users WHERE id = :id"; 

$sth = $dbh->prepare($q); $sth->bindParam(':id', $id); 

$sth->execute(); $sth->setFetchMode(PDO::FETCH_ASSOC); 

$result = $sth->fetchColumn(); print( htmlentities($result) ); … 

4) Хранимые процедуры

Объекты базы данных требуют, чтобы разработчик сгруппировал один или несколько операторов SQL в логическую единицу для создания плана выполнения. Последующие исполнения позволяют автоматически параметризовать операторы. То есть, это тип кода, который можно сохранить и многократно использовать в последующем. Когда необходимо выполнить запрос, вместо того, чтобы писать его, можно будет вызвать хранимую процедуру.

5) Использование WAF

Nemesida WAF - универсальное решение, позволяющее блокировать попытки эксплуатации различных типов уязвимостей, в том числе и SQL-инъекции. В основе своей работы Nemesida WAF использует машинное обучение, способное более точно и с минимальным количеством ложных срабатываний, противодействовать атакам на веб-приложение вне зависимости от языка разработки и используемых фреймворков. Также доступна бесплатная версия Nemesida WAF Free

В одной из статей мы рассматривали способы тестирования Nemesida WAF различными инструментами.

6) Принцип наименьших привилегий

Нельзя подключать веб-приложения к базе данных, используя учетную запись с привилегированным доступом (только в случае крайней необходимости), так как злоумышленники могут получить доступ ко всей системе. Это позволит минимизировать ущерб от проэксплуатированной уязвимости при ее наличии.

Резюмируя написанное выше, приведем несколько рекомендаций по защите веб-приложений от SQL-инъекций:

  • обрабатывайте ввод отдельно и формируйте запрос из безопасных значений;

  • создавайте «белые» списки;

  • регулярно устанавливайте обновления;

  • удаляйте неиспользуемый функционал;

  • задавайте конкретные значения названиям таблиц, полей и базам;

  • периодически проводите анализ защищенности веб-приложений вручную и с помощью инструментов автоматизации (например, Wapiti)

  • используйте средства защиты веб-приложений (WAF).

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