SQL-инъекции для самых маленьких
Мы переходим к технической части статей про тестирование на проникновение. И начнем как всегда с внешнего пути – с эксплуатации веб уязвимостей. И стартанем мы с SQL – инъекций.
SQL-инъекция (SQLi) — это уязвимость веб-безопасности, которая позволяет злоумышленнику вмешиваться в запросы, которые приложение делает к своей базе данных. Как правило, это позволяет просматривать данные, которые он обычно не может получить. Это могут быть других пользователей, или любые другие данные, доступ к которым имеет само приложение. Во многих случаях злоумышленник может изменять или удалять эти данные, вызывая постоянные изменения в содержимом или поведении приложения.
В некоторых ситуациях злоумышленник может усилить атаку SQL-инъекции, чтобы скомпрометировать базовый сервер или другую внутреннюю инфраструктуру, или осуществить атаку типа «отказ в обслуживании».
Каковы последствия успешной атаки SQL-инъекции?
Успешная атака SQL-инъекции может привести к несанкционированному доступу к конфиденциальным данным, таким как пароли, данные кредитных карт или личная информация пользователей. Многие громкие утечки данных в последние годы стали результатом атак с использованием SQL-инъекций, что привело к ухудшению репутации и штрафам со стороны регулирующих органов. В некоторых случаях злоумышленник может получить постоянный черный ход в системы организации, что приводит к долгосрочной угрозе, которая может оставаться незамеченной в течение длительного периода времени.
Примеры SQL-инъекций
Существует широкий спектр уязвимостей, атак и методов SQL-инъекций, которые возникают в различных ситуациях. Некоторые распространенные примеры инъекций SQL включают:
- Получение скрытых данных, когда вы можете изменить SQL-запрос, чтобы вернуть дополнительные результаты.
- Подрыв логики приложения, когда можно изменить запрос, чтобы вмешаться в логику приложения.
- Атаки UNION, когда можно получить данные из разных таблиц базы данных.
- Изучение базы данных, когда можно получить информацию о версии и структуре базы данных.
- Слепая SQL-инъекция, когда результаты контролируемого вами запроса не возвращаются в ответах приложения.
Извлечение скрытых данных
Рассмотрим приложение для покупок, которое отображает товары в различных категориях. Когда пользователь нажимает на категорию «Подарки», его браузер запрашивает URL-адрес:
Это заставляет приложение выполнить SQL-запрос для получения информации о соответствующих товарах из базы данных:
SELECT * FROM products WHERE category = ‘Gifts’ AND released = 1
Этот SQL-запрос просит базу данных вернуть:
все данные (*) из таблицы продуктов где категория — «Подаркии» released = 1.
Ограничение released = 1 используется для скрытия продуктов, которые не выпущены. Для невыпущенных продуктов, предположительно, released = 0.
В приложении не реализована защита от атак SQL-инъекций, поэтому злоумышленник может построить атаку типа:
В результате получится SQL-запрос:
SELECT * FROM products WHERE category = ‘Gifts’—‘ AND released = 1
Ключевым моментом здесь является то, что последовательность двойных тире — является индикатором комментария в SQL и означает, что остальная часть запроса интерпретируется как комментарий. Это эффективно удаляет остаток запроса, так что он больше не включает AND released = 1. Это означает, что отображаются все продукты, включая еще не выпущенные.
Если пойти дальше, злоумышленник может заставить приложение отобразить все продукты в любой категории, включая категории, о которых он не знает:
В результате получается SQL-запрос:
SELECT * FROM products WHERE category = ‘Gifts’ OR 1=1—‘ AND released = 1
Модифицированный запрос вернет все товары, где
либо категория — Gifts, либо 1 равна 1. Поскольку 1=1 всегда истинно, запрос
вернет все товары.

Подрыв логики приложения
Рассмотрим приложение, которое позволяет пользователям входить в систему с помощью имени пользователя и пароля. Если пользователь вводит имя пользователя wiener и пароль bluecheese, приложение проверяет учетные данные, выполняя следующий SQL-запрос:
SELECT * FROM users WHERE username = ‘wiener’ AND password = ‘bluecheese’
Если запрос возвращает данные пользователя, то вход в систему будет успешным. В противном случае он будет отклонен.
Здесь злоумышленник может войти в систему как любой пользователь без пароля, просто используя последовательность комментариев SQL — для удаления проверки пароля из пункта WHERE запроса. Например, если ввести имя пользователя administrator’— и пустой пароль, то получится следующий запрос:
SELECT * FROM users WHERE username = ‘administrator’—‘ AND password = »
Этот запрос возвращает пользователя, чье имя пользователя — administrator, и успешно регистрирует атакующего как этого пользователя.
Получение данных из других таблиц базы данных
В случаях, когда результаты SQL-запроса возвращаются в ответах приложения, злоумышленник может использовать уязвимость SQL-инъекции для получения данных из других таблиц базы данных. Для этого используется ключевое слово UNION, которое позволяет выполнить дополнительный запрос SELECT и добавить его результаты к исходному запросу.
Например, если приложение выполняет следующий запрос, содержащий пользовательский ввод «Gifts»:
SELECT name, description FROM products WHERE category = ‘Gifts’
то злоумышленник может отправить ввод:
‘ UNION SELECT username, password FROM users—.
Это заставит приложение вернуть все имена пользователей и пароли вместе с названиями и описаниями товаров.

Изучение базы данных, ну или определение версии и т. д.
После первоначальной идентификации уязвимости SQL-инъекции обычно полезно получить некоторую информацию о самой базе данных. Эта информация часто может проложить путь для дальнейшей эксплуатации.
Вы можете запросить информацию о версии базы данных. Способ, которым это делается, зависит от типа базы данных, поэтому вы можете определить тип базы данных по тому, какая техника работает. Например, в Oracle вы можете выполнить:
SELECT * FROM v$version
Вы также можете определить, какие таблицы базы данных существуют, и какие столбцы они содержат. Например, для большинства баз данных вы можете выполнить следующий запрос, чтобы получить список таблиц:
SELECT * FROM information_schema.tables
Слепые уязвимости SQL-инъекции
Многие случаи SQL-инъекций являются слепыми уязвимостями. Это означает, что приложение не возвращает результаты SQL-запроса или сведения об ошибках базы данных в своих ответах. Слепые уязвимости все еще могут быть использованы для несанкционированного доступа к данным, но соответствующие техники обычно более сложны и трудновыполнимы.
В зависимости от характера уязвимости и используемой базы данных, для эксплуатации слепых уязвимостей SQL-инъекций можно использовать следующие техники:
- Можно изменить логику запроса, чтобы вызвать заметную разницу в реакции приложения в зависимости от истинности одного условия. Это может включать в себя введение нового условия в некоторую булеву логику или условное срабатывание ошибки, такой как деление на ноль.
- Можно условно вызвать временную задержку в обработке запроса, что позволяет сделать вывод об истинности условия на основе времени, которое требуется приложению для ответа.
- Можно вызвать внеполосное сетевое взаимодействие, используя технику OAST. Эта техника является чрезвычайно мощной и работает в ситуациях, когда другие техники не работают. Часто вы можете напрямую передать данные по внеполосному каналу, например, поместив данные в DNS-поиск для домена, который вы контролируете.
В следующих статьях мы подробно разберем каждый вид SQL –инъекции.
SQL-инъекция
SQL-инъекциями называют атаки, позволяющие злоумышленнику производить различные несанкционированные действия над базой данных. Они могут затрагивать как сами данные, так и структуру базы. Для этого в качестве входных данных передаются специальные строки, содержащие вредоносные команды. Приложение, уязвимое к SQL-инъекциям, производит вставку этих строк в шаблон запроса без проведения необходимых проверок. В результате формируется запрос, выполняющий действия, определённые злоумышленником. При этом запрос будет являться корректным с точки зрения синтаксиса SQL.
Уязвимости данного типа представляют серьёзную угрозу. В OWASP ASVS они принадлежат категориям 5.3.4 и 5.3.5, а в списке OWASP Top Ten 2017 их можно отнести к категории A1 (Injection). Также в Common Weakness Enumeration SQL-инъекциям соответствует позиция CWE-89.
Пример уязвимости
Для наглядной демонстрации возможностей SQLI рассмотрим следующий пример:
void ProcessRequest(HttpRequest request) < string name = request.Form["name"]; string sql = $"SELECT * FROM Users WHERE name=''"; ExecuteReaderCommand(sql); . > void ExecuteReaderCommand(string sql) < using (var command = new SqlCommand(sql, _connection)) < using (var reader = command.ExecuteReader()) < . >> . >
Предполагается, что в параметре ‘name’ будет записано имя пользователя, данные которого будут получены из базы и в последствии обработаны. При этом модификация значений в базе не производится – приведённый фрагмент должен лишь считывать их.
Данный код уязвим к SQL-инъекциям, так как в нём непроверенные внешние данные используются для формирования запроса к базе. Вследствие этого злоумышленник имеет возможность передать в приложение строку, которая приведёт к выполнению различных несанкционированных операций.
К примеру, в параметре ‘name’ может быть записано следующее значение:
'; DELETE FROM Users WHERE name != '
При подстановке этой строки в шаблон запроса получится следующая SQL-команда:
SELECT * FROM Users WHERE name=''; DELETE FROM Users WHERE name != ''
Выполнение такого запроса приведёт к удалению всех записей из таблицы ‘Users’ (при условии, что для каждого пользователя задано значение столбца ‘name’).
Поиск потенциальных уязвимостей
Одной из важнейших задач при обеспечении устойчивости приложения к SQL-инъекциям является поиск фрагментов кода, которые могут быть уязвимы к данному виду атак. Для этого необходимо найти и изучить все места, в которых производится формирование и выполнение запросов к базе данных. Многие разработчики используют для этих целей различные инструменты, производящие taint-анализ. Одним из таких инструментов является статический анализатор PVS-Studio.
Вернёмся к ранее приведённому примеру:
void ProcessRequest(HttpRequest request) < string name = request.Form["name"]; string sql = $"SELECT * FROM Users WHERE name=''"; ExecuteReaderCommand(sql); . > void ExecuteReaderCommand(string sql) < using (var command = new SqlCommand(sql, _connection)) < using (var reader = command.ExecuteReader()) < . >> . >
Производя taint-анализ, PVS-Studio обнаружит здесь потенциальную уязвимость и сформирует следующее сообщение: V5608 Possible SQL injection inside method. Potentially tainted data in the first argument ‘sql’ is used to create SQL command.
Таким образом, статический анализатор позволяет автоматически определять наличие в коде потенциальных уязвимостей.
Борьба с SQL-инъекциями
Рекомендуемым способом борьбы с SQL-инъекциями считаются параметризованные запросы. Суть их использования состоит в том, что подстановка внешних данных в шаблон запроса производится не напрямую, а через специализированное API. Сформированный таким образом запрос будет безопасным, так как внешние данные перед фактической подстановкой будут преобразованы.
Способы работы с параметризованными запросами в различных языках программирования могут отличаться, однако основная идея остаётся неизменной. К примеру, в C# формирование запроса с параметрами может производиться следующим образом:
String userName = Request.Form["name"]; using (var command = new SqlCommand() < Connection = _connection, CommandText = "SELECT * FROM Users WHERE UserName = @userName", CommandType = System.Data.CommandType.Text >) < var userNameParam = new SqlParameter("@userName", userName); command.Parameters.Add(userNameParam); using (var reader = command.ExecuteReader()) < . >>
Такой подход обеспечивает безопасность использования внешних данных при формировании запросов к базе. Тем не менее, существуют и другие методы борьбы с SQL-инъекциями. К примеру, можно использовать специальную систему валидации внешних данных, которая позволит обнаруживать в них фрагменты SQL-команд, либо преобразовывать данные в безопасный вид с помощью различных функций. В отдельных случаях могут подойти и более простые подходы, такие как проверка типов переданных значений.
Дополнительные ссылки
- OWASP, OWASP Топ-10
- Описание SQL Injection на сайте Microsoft
- Классификация предупреждений PVS-Studio согласно OWASP Top 10 Web Application Security Risks
- Классификация предупреждений PVS-Studio согласно OWASP Application Security Verification Standard (ASVS)
- OWASP, уязвимости и taint анализ в PVS-Studio C#. Смешать, но не взбалтывать
- Диагностическое правило V5608 (SQL Injection)
- Статья о SQL Injection на официальном сайте OWASP
Как работают sql инъекции
# Занятие 1. SQL injection. ###### tags: `Intro to Web Security`  #### Материалы и описание для самостоятельного изучения: — язык SQL — [Что такое SQL и как он работает](https://gb.ru/posts/chto-takoe-sql-i-kak-on-rabotaet) — [w3schools](https://www.w3schools.com/sql/default.asp) — [sql-ex](https://sql-ex.ru) — инъекции SQL — [PortSwigger academy](https://portswigger.net/web-security/sql-injection) — [sqlinjection.net](https://www.sqlinjection.net/tutorial/) — [hacksplaining.com](https://www.hacksplaining.com/lessons) ## Подготовка к занятию. Настройка Burp Suite и FoxyProxy(браузер Firefox) #### [Видео настройки Burp Suite и FoxyProxy](https://www.youtube.com/watch?v=kqw3DlJDmx4) ## Что такое SQL Википедия гласит, что SQL — это декларативный язык программирования, применяемый для создания, модификации и управления данными в реляционной базе данных, управляемой соответствующей системой управления базами данных. Не самое удобоваримое определение. Чтобы понять, о чём вообще речь, разберём его. Декларативный язык программирования говорит, что должно быть сделано, а не как это необходимо сделать. Ещё один пример декларативного языка — HTML. Рассмотрим такой код: «`htmlmixed=
