Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
SQL (structured query language) — язык структурированных запросов. Применяется для создания, модификации и управления данными в реляционной базе данных, управляемой соответствующей СУБД.
Изначально SQL был основным способом работы пользователя с базой данных и позволял выполнять операции:
• создание, изменение и удаление записей;
• создание таблиц в базе данных и изменение их структуры;
• выборка информации по заданным условиям.
Со временем веб-приложения перестали разрабатываться в формате одностраничных сайтов, а для хранения информации начали активно использоваться базы данных. Логика их работы сводилась к тому, что при обращении к какой-то странице, веб-приложение формировало специальный SQL-запрос к базе данных, например:
SELECT * FROM some_table_name WHERE id='2';
Такой запрос отправляется в базу данных, запрашивая соответствующую запись из таблицы some_table_name. База данных возвращает результат запроса в веб-приложение, которое, в свою очередь, отображает его на странице браузера для пользователя.
Поняв эту логику работы люди задались вопросом: «А что будет, если попробовать видоизменить отправляемый запрос?». Так появились первые SQL-инъекции. Суть их работы заключается во внедрении собственного кода в SQL-запрос к базе данных с целью получить дополнительную информацию.
Пожалуй, наиболее часто встречаются SQLi в SELECT запросах, так как данный тип запросов является самым распространенным, но, все же не ограничивается только им.
SQL-injection встречается:
• в строковом параметре;
• в числовом параметре.
Для числового параметра характерна обработка числовых данных, например, в параметре ID:
http://example.com/index.php?id=1
Если параметр не будет иметь фильтрацию, а код выглядит примерно так:
$id = $_GET['id'];
$query = "SELECT * FROM some_table_name WHERE id=$id";
то при эксплуатации SQL-инъекции веб-приложение направит некорректный запрос в базу данных, например:
SELECT * FROM some_table_name WHERE id='1''
и в ответе от веб-приложения пользователь получит ошибку синтаксиса. Но если этого не произойдет, то здесь 2 варианта:
• SQL-инъекции здесь нет — фильтруются кавычки, или просто стоит преобразование в целочисленный тип int;
• отключен вывод ошибок.
В строковом параметре ситуация аналогичная, только вместо числового параметра будет строка:
http://example.com/index.php?user=admin'
Статья носит информационный характер. Не нарушайте законодательство.
Основные методы эксплуатации SQL-injection
Union Based SQL-injection — применяется, если SQL-injection возникает в SELECT запросе. Благодаря данному методу можно объединить два SELECT запроса в один набор результатов. Особенность этого метода заключается в том, что он будет работать только в том случае, если количество столбцов, возвращаемых первым запросом, будет равно количеству столбцов, возвращаемых во втором запросе.
Для определения количества столбцов можно воспользоваться 3 методами:
• добавление нового столбца при каждой итерации проверки, что не совсем удобно, так как столбцов может быть 20,30,50 и т.д.:
?id=1' union select null --
?id=1' union select null,null --
?id=1' union select null,null,null --
и т.д.
Почему используется значение NULL? Все просто, типы данных в каждом столбце должны быть совместимы между исходным и внедренным запросами. Поскольку NULL может быть преобразован во все часто используемые типы данных, его использование увеличивает вероятность успешного выполнения полезной нагрузки при правильном подсчете столбцов.
• использование команды order by для определение количества столбцов. В этом случае нужно опираться на появление ошибки о несоответствии количества столбцов в запросе. Стоит начать с большого количества столбцов и уменьшать их вдвое при каждой итерации проверки. Если количество столбцов не будет соответствовать фактическому значению, то вернется ошибка
?id=1' order by 20 --
?id=1' order by 10 --
?id=1' order by 5 --
и т.д.
• использование команды group by, который основывается на обратном методе проверки, в отличие от order by.
?id=1' group by 5 --
?id=1' group by 10 --
?id=1' group by 20 --
Boolean Based SQL-injection — метод эксплуатации слепых инъекций. Информация извлекается исходя из реакции на условные выражения. Инъекция называется слепой в тех случаях, если нет никакой видимой реакции от веб-приложения. Например, при подстановке кавычек в потенциально уязвимый параметр, ошибка, связанная с нарушением логики SQL-запроса, не появляется, а страница отображается без изменений. Но тут, как уже говорилось ранее, несколько вариантов: либо входные параметры фильтруются и уязвимости нет, либо на сервере отключен вывод ошибок на странице.
Пример:
?id=1' AND substring(@@version,1,1)=5 --
Вместе с запросом указывается некоторое условие. Условие может быть как истинным, так и ложным. Если оба условия выполняются одновременно, то, запрос отработает корректно, в противном случае запрос не будет выполнен.
Error Based SQL-injection — данный метод позволяет получить информацию из базы данных в тексте ошибки.
Для поиска такого рода инъекций можно воспользоваться следующими примерами:
?id=0X01
?id=9999999999999999999999999999999999999999999
В первом варианте 0X01 будет являться действительным числом, но в языке PHP, а не MySQL, что вызовет ошибку последнего. Во втором варианте число будет преобразовано в INF, что также будет являться действительным числом для PHP, но не для MySQL.
Time Based SQL-injection — используются команды СУБД (например, sleep) , вызывающие задержку ответа от базы данных. Метод также используется для эксплуатации слепых инъекций, когда отсутствует какой-либо вывод информации, в том числе в случаях, описанных в Boolean Based SQL-injection.
Пример:
?id=1' and sleep(20) --
В этом примере добавляется задержка 20 секунд в виде команды sleep(20) для базы данных, которая создаст задержку перед ответом, что соответственно отразится и на времени ответа веб-приложения. Также для этих целей можно использовать и другие команды, например, benchmark или waitfor:
BENCHMARK(5000000,ENCODE('MSG','by 5 seconds'));
id=1' waitfor delay '00:00:10' (MS-SQL);
pg_sleep() (PostgreSQL).
Пример, где по длительному ответу от базы данных можно определить, что первый символ значения user_password для пользователя с id=1 будет равняться «2» т.к. char(50) является цифрой 2:
?id=1' UNION SELECT IF(SUBSTRING(user_password,1,1) = CHAR(50),BENCHMARK(5000000,ENCODE('MSG','by 5 seconds')),null) FROM users WHERE user_id = 1;
Команда benchmark, в случае верного условия, выполнит функцию ENCODE 50000 раз, что вызовет задержку ответа, по которой и определяется наличие SQL-инъекции.
Как искать и эксплуатировать SQLi
1. Ручной поиск. Для начала во все параметры подставляем спецсимволы: кавычки, двойные кавычки и т.д. Если на каком-то варианте вернулась ошибка, то инъекция найдена и можно продолжать. Как правило, используется оператор union select, чтобы объединить сразу 2 запроса, а как мы уже знаем, этот метод требует соответствия в количестве столбцов. С помощью order by определяем количество столбцов. После этого можно формировать запрос для получения информации о самой базе данных. Допустим у нас столбцов будет 4, то команда будет выглядеть так:
?id=1' union select null,null,null,null --
В конце запроса обязательно ставится комментарий, например, в виде двойного дефиса. Это необходимо для того, чтобы лишняя информация не попала в передаваемый базе данных запрос, и не нарушала его структуру.
?id=1' union select version(),user(),@@port,null --
Отправив такой запрос, мы получим версию базы данных, имя пользователя базы данных, и порт, который использует БД (может быть полезно в случаях, когда его не удалось определить при сканировании веб-приложения).
?id=1' union select null,null,table_name,null from information_schema.tables --
Указав table_name и добавив from information_schema.tables мы получим список всех таблиц базы данных, включая системные. Это стало возможным благодаря добавлению таблицы information_schema в MySQL 5.0+ и по ее наличию также можно косвенно определить версию используемой БД. Получив список таблиц ищем среди них нужную и получаем из нее информацию. Например, у нас есть таблица users, где хранятся пользовательские данные — имя пользователя, хэш пароля и прочая информация.
?id=1' union select null,null,concat(user(),0x3a,password('user()'),null --
В результате запроса в одном поле будет выведена информация о пользователях БД (логин) и их пароли в виде хеша, используя функцию concat.
2. Автоматизация. Безусловно, навык ручного поиска и эксплуатации SQL-инъекций очень важен и порой незаменим в тестировании на проникновение, однако и время тоже является крайне ценным ресурсом. Для его экономии, особенно при поиске и эксплуатации слепых инъекций, разработаны вспомогательные инструменты.
Один из них довольно популярен и называется SQLmap. Рассказывать про него особо нечего, так как это, думаю, первая ассоциация при слове SQL-инъекция. Но если вкратце - мощный кроссплатформенный консольный инструмент для автоматизации поиска и эксплуатации SQL-инъекций любого вида и сложности, написанный на языке Python. В основной функционал которого входит:
• полная поддержка для таких систем управления базами данных, как: MySQL, Oracle, PostgreSQL, Microsoft SQL Server, Microsoft Access, IBM DB2, SQLite, Firebird, Sybase, SAP MaxDB и HSQLDB;
• поддержка прямого подключения к базе данных без использования SQL инъекции, посредством введения учётных данных СУБД, IP адреса, порта и имени БД;
• поддержка перечисления пользователей, хешей паролей, привилегий, ролей, БД, таблиц и колонок;
• автоматическое распознавание форматов хешей паролей и предложение их взлома с использованием атаки по словарю;
• поддержка выполнения произвольных команд на ОС сервера БД и получение их стандартного вывода при использовании MySQL, PostgreSQL или Microsoft SQL Server и многое другое.
Основные ключи, которые используются при работе с инструментом:
• --dbs - поиск и вывод списка баз данных;
• -D,T,C - указание конкретной базы данных, таблицы и колонок в таблице для дампа информации из них;
• --level, --risk - параметры для более углубленного тестирования (параметры генерируют больше трафика и могут помочь системам защиты выявить атаку);
• --random-agent - использование произвольного User-Agent.
Инструмент позволяет найти и проэксплуатировать практически любую известную SQL-уязвимость, а за счет постоянных обновлений расширяется функционал, поэтому утилита обязательна к использованию. Ну а мы перейдем к менее популярному, но не менее эффективному инструменту.
JSQL injection
Домашняя страница: https://github.com/ron190/jsql-injection
Инструмент для автоматизации поиска и эксплуатации SQL-уязвимостей. Написан на Java, поэтому является кроссплатформенным, нужно только установить нужную версию Java. Скачать jar-файл можно по ссылке.
В отличие от популярного SQLmap здесь есть графический интерфейс и инструмент в целом может выполнять большинство всех основных действий, необходимых для поиска и эксплуатации SQL-инъекций.
Основные возможности:
• поддержка работы с 33 базами данных, например: Access, Altibase, Firebird, MemSQL, MySQL, Oracle, PostgreSQL, Presto, SQLite, SQL Server и т.д.;
• поддержка различных видов инъекций: нормальные, error-based, stacked-based, blind и time-based;
• список для введения нескольких целей;
• чтение и запись файла с помощью инъекции;
• создание и внедрение веб-шелла и SQL-шелла;
• полный перебор паролей по хешу;
• поиск страниц администратора;
• кодирование и декодирование текста;
• аутентификация с использованием Basic, Digest, NTLM и Kerberos;
• прокси-соединение по HTTP, SOCKS4 и SOCKS5.
Судя по набору функций, инструмент в себе собрал не только средство поиска и эксплуатации SQLi, но и функционал Dirb и Hashcat. Лучше их использовать отдельно, но если такой возможности нет, то приходится использовать то, что есть, но об этом чуть позже.
Интерфейс
Интерфейс легкий, незамысловатый и интуитивно понятный. В главном меню указывается URL для проверки параметров в GET- или POST-запросах, cookie и прочих заголовках. После указания необходимых параметров автоматически начнется поиск уязвимостей. Если нашлись, то они будут проэксплуатированы, а во вкладке Database отобразится содержимое всей базы данных, где можно посмотреть информацию по любой из предоставленных таблиц.
Просмотр базы данных
Кстати, и SQLmap и JSQL injection поддерживают поиск уязвимостей в достаточно экзотических параметрах как, например, cookie. Но из-за того, что в SQLmap база пейлоадов намного больше, то и результата он, вероятнее, будет добиваться чаще. При тестировании инструментов на одном и том же приложении SQLmap смог подобрать нужный пейлоад командой:
# sqlmap -u http://test.site --cookie='wp_sap=[«*»]' --dbs
а у JSQL injection с этим возникли небольшие сложности, вероятно, из-за не такой обширной базы пейлоадов.
Если удалось получить хэш пароля пользователя из БД, то в инструменте предусмотрен встроенный функционал перебора во вкладке Brute force. Это именно чистый bruteforce т.к. перебор по словарю недоступен и нужно указывать набор символов и их количество. Если сравнивать с SQLmap, то в последнем представлен перебор только по словарю, который может и не так эффективен, как полный перебор, но и не требует таких затрат по ресурсам компьютера и времени.
Перебор пароля по хешу
Есть возможность поиска панели администратора по списку. Разумеется, есть готовый список страниц для поиска, но его можно редактировать и дополнять.
Поиск панели администратора
Следующий набор функций позволяет читать файлы, загружать их, создавать и записывать web- и sql-шеллы на сервере. Все эти действия производятся на основе списка директорий, который необходимо либо прочитать, либо в который записать. Список можно редактировать. Но тут небольшая оговорка — чтобы этот функционал работал, у пользователя, от имени которого веб-приложение обращается к базе данных, должны быть соответствующие привилегии на чтение или запись, используя СУБД. То есть, должны быть привилегии на выполнение команд, например, load_file() или into outfile(). Но чаще всего подобные привилегии пользователю не предоставляются.
Чтение, запись и загрузка файлов
Вкладка Encode позволяет в реальном времени закодировать текст в base16, base32, base58, base64, Url-Encode, Hex,Html-Encode и т.д.
Кодирование
Последняя вкладка Scan позволяет установить список URL-адресов для автоматизации поиска SQL-инъекций. Предоставляемый изначально список можно удалить или отредактировать, добавляя собственные URL-адреса.
И еще немного про взаимодействие инструментов с WAF. Изначально не заявлено, что оба инструмента позволяют обойти средство защиты, поэтому и тестирование было довольно коротким. Для тестирования использовался только Nemesida WAF Free и анализ запросов на основе сигнатур. Атаки обоих инструментов были успешно заблокированы и отображены в личном кабинете.
Фиксирование атак в личном кабинете
SQLmap
jSQL Injection
Вывод
Риск SQL-инъекций возникает всякий раз, когда программист создает динамический запрос к базе, содержащий введённые пользователем данные. Это значит, что способов предотвращения SQL-инъекций два:
• не использовать динамические запросы к базе;
• не использовать пользовательские данные.
Поскольку отказаться от этих двух условий довольно проблематично, то SQL-инъекции были и будут оставаться одними из самых распространенных и опасных уязвимостей веб-приложений. И вот небольшой список рекомендаций для защиты веб-приложений от них:
• тщательная проверка данных от пользователя перед использованием их в запросе;
• отключение вывода ошибок на сервере. От SQL-инъекций это не защитит, но затруднит ее поиск и эксплуатацию;
• периодическое проведение аудита веб-приложения как вручную, так и с помощью инструментов автоматизации (SQLmap, jSQL Injection и т.д.). Также можно доверить этот процесс профессионалам с достаточным опытом и уровнем подготовки;
• удаление неиспользуемого функционала. Та или иная функция, которая не была вовремя удалена может сыграть на руку злоумышленникам;
• регулярная установка обновлений;
• использование средств защиты веб-приложений, например WAF.