SQL Injection

В этом разделе мы узнаем, что такое SQL Injection и как находить и эксплуатировать разные типы уязвимостей SQLi, а также как предотвращать SQL Injection.

sql-injection.svg

Что такое SQL Injection (SQLi)?

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

В некоторых ситуациях атакующий может эскалировать атаку SQL Injection (SQLi) до компрометации базового сервера или другой внутренней инфраструктуры. Это также может позволить ему проводить атаки отказа в обслуживании.

Каков эффект успешной атаки SQL Injection (SQLi)?

Успешная атака SQL Injection (SQLi) может привести к несанкционированному доступу к конфиденциальным данным, таким как:

  • Пароли.

  • Данные банковских карт.

  • Персональная информация пользователей.

Атаки SQL Injection (SQLi) использовались во многих громких утечках данных на протяжении лет. Они приводили к репутационному ущербу и регуляторным штрафам. В некоторых случаях атакующий может получить постоянный «бэкдор» в системы организации, что приводит к долгосрочной компрометации, остающейся незамеченной в течение длительного времени.

Как обнаруживать уязвимости SQL Injection (SQLi)

Вы можете обнаруживать SQL Injection (SQLi) вручную, систематически тестируя каждую точку ввода в приложении. Для этого обычно отправляют:

  • Символ одинарной кавычки ' и отслеживают ошибки или другие аномалии.

  • Некоторый специфичный для SQL синтаксис, который вычисляется в базовое (исходное) значение точки ввода и в отличающееся значение, и ищут систематические различия в ответах приложения.

  • Булевы условия, такие как OR 1=1 и OR 1=2, и ищут различия в ответах приложения.

  • Полезные нагрузки, предназначенные для вызова временных задержек при выполнении внутри SQL-запроса, и отслеживают различия по времени ответа.

  • OAST-полезные нагрузки, предназначенные для инициирования внеполосного (out-of-band) сетевого взаимодействия при выполнении внутри SQL-запроса, и мониторят итоговые взаимодействия.

SQL Injection (SQLi) в разных частях запроса

Большинство уязвимостей SQL Injection (SQLi) возникает внутри предложения WHERE запроса SELECT.

Однако уязвимости SQL Injection (SQLi) могут возникать в любом месте запроса и в разных типах запросов. Другие распространённые места возникновения SQL Injection (SQLi):

  • В операторах UPDATE — в обновляемых значениях или в WHEREусловии.

  • В операторах INSERT — во вставляемых значениях.

  • В операторах SELECT — в имени таблицы или столбца.

  • В операторах SELECT — в разделе ORDER BY.

Примеры SQL Injection (SQLi)

Существует множество уязвимостей, атак и техник SQL Injection (SQLi), которые возникают в разных ситуациях. Некоторые распространённые примеры SQL Injection (SQLi):

Получение скрытых данных

Представьте приложение-магазин, которое отображает товары по категориям. Когда пользователь нажимает на категорию Gifts, его браузер запрашивает URL:

Это заставляет приложение выполнить SQL-запрос для получения сведений о соответствующих товарах из базы данных:

Этот SQL-запрос просит базу данных вернуть:

  • все детали ()

  • из таблицы products

  • где category равна Gifts

  • и released равно 1.

Ограничение released = 1 используется для скрытия не выпущенных товаров. Можно предположить, что для невыпущенных товаров released = 0.

Приложение не реализует никаких защит от атак SQL Injection. Это означает, что атакующий может, например, сконструировать следующую атаку:

Это приводит к SQL-запросу:

Критически важно отметить, что -- — это индикатор комментария в SQL. Это означает, что остальная часть запроса интерпретируется как комментарий и по сути удаляется. В данном примере это означает, что запрос больше не включает AND released = 1. В результате отображаются все товары, включая те, которые ещё не выпущены.

Вы можете использовать похожую атаку, чтобы заставить приложение отображать все товары в любой категории, включая категории, о которых пользователи не знают:

Это приводит к SQL-запросу:

Модифицированный запрос возвращает все элементы, где либо category равно Gifts, либо 1 равно 1. Поскольку 1=1 всегда истинно, запрос возвращает все элементы.

Предупреждение

Будьте осторожны при внедрении условия OR 1=1 в SQL-запрос. Даже если оно кажется безопасным в контексте, куда вы его внедряете, приложения часто используют данные из одного запроса в нескольких разных запросах. Если ваше условие попадёт в оператор UPDATE или DELETE, это, например, может привести к компрометации данных.

Подрыв логики приложения

Представьте приложение, которое позволяет пользователям входить по имени пользователя и паролю. Если пользователь отправляет имя wiener и пароль bluecheese, приложение проверяет учётные данные, выполняя следующий SQL-запрос:

Если запрос возвращает сведения о пользователе, вход успешен. В противном случае — отклоняется.

В этом случае атакующий может войти под любым пользователем без пароля. Он может сделать это, используя последовательность комментария SQL --, чтобы удалить проверку пароля из WHERE-условия запроса. Например, отправка имени пользователя administrator'-- и пустого пароля приведёт к следующему запросу:

Этот запрос возвращает пользователя, у которого usernameadministrator, и успешно авторизует атакующего под этим пользователем.

Получение данных из других таблиц базы данных

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

Например, если приложение выполняет следующий запрос с пользовательским вводом Gifts:

Атакующий может отправить ввод:

Это заставит приложение вернуть все имена пользователей и пароли вместе с именами и описаниями товаров.

Blind SQL Injection

Многие случаи SQL Injection являются «Blind». Это означает, что приложение не возвращает результаты SQL-запроса или подробности ошибок базы в своих ответах. Слепые уязвимости тоже можно эксплуатировать для доступа к несанкционированным данным, но задействованные техники обычно более сложны и трудновыполнимы.

В зависимости от характера уязвимости и используемой базы данных могут применяться следующие приёмы эксплуатации слепых SQL-инъекций:

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

  • Вы можете условно инициировать задержку во время обработки запроса. Это позволяет сделать вывод об истинности условия по времени ответа приложения.

  • Вы можете инициировать внеполосное сетевое взаимодействие с использованием OAST-техник. Эта техника чрезвычайно мощная и работает там, где другие не срабатывают. Часто вы можете напрямую эксфильтровать данные через внеполосный канал. Например, вы можете поместить данные в DNS-запрос к домену, который вы контролируете.

Подробнее

Blind SQL Injection

Second-order SQL injection

Первичная SQL Injection возникает, когда приложение обрабатывает пользовательский ввод из HTTP-запроса и в небезопасной форме включает его в SQL-запрос.

Second-order SQL Injection возникает, когда приложение принимает пользовательский ввод из HTTP-запроса и сохраняет его для будущего использования. Обычно это делается путём помещения ввода в базу данных, но на этапе сохранения уязвимости нет. Позже, при обработке другого HTTP-запроса, приложение извлекает сохранённые данные и небезопасно включает их в SQL-запрос. По этой причине Second-order SQL Injection также известна как «Stored SQL Injection».

second-order-sql-injection.svg

Second-order SQL Injection часто возникает в ситуациях, когда разработчики осведомлены об уязвимостях SQL-инъекции и безопасно обрабатывают изначальное помещение ввода в базу. Когда данные обрабатываются позже, их считают безопасными, поскольку ранее они были помещены в базу безопасно. На этом этапе данные могут обрабатываться небезопасно, потому что разработчик ошибочно считает их доверенными.

Изучение базы данных

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

Однако между распространёнными СУБД также много различий. Это означает, что некоторые техники обнаружения и эксплуатации SQL Injection работают по-разному на разных платформах. Например:

  • Синтаксис конкатенации строк.

  • Комментарии.

  • Пакетные (stacked) запросы.

  • Платформенно-специфичные API.

  • Сообщения об ошибках.

После того как вы определили уязвимость SQL Injection, часто полезно получить информацию о базе данных. Эта информация поможет вам эксплуатировать уязвимость. Вы можете запросить сведения о версии базы. Разные методы работают для разных типов баз. Это означает, что если вы нашли конкретный метод, который сработал, вы можете вывести тип базы. Например, в Oracle вы можете выполнить:

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

SQL Injection в разных контекстах

В предыдущих лабораторных вы могли использовать строку запроса (query string), чтобы внедрить вредоносную SQL-полезную нагрузку. Однако атаки SQL-инъекции можно проводить через любой контролируемый ввод, который приложение обрабатывает как SQL-запрос. Например, некоторые сайты принимают ввод в формате JSON или XML и используют его для запросов к базе.

Эти различные форматы могут предоставлять разные способы обфускации атак, которые иначе блокируются WAF и другими механизмами защиты. Слабые реализации часто ищут в запросе общие ключевые слова SQL Injection, поэтому вы можете обходить такие фильтры, кодируя или экранируя символы в запрещённых ключевых словах. Например, следующая SQL Injection на основе XML использует последовательность экранирования XML, чтобы закодировать символ S в SELECT:

Это будет декодировано на стороне сервера до передачи в SQL-интерпретатор.

Как предотвратить SQL Injection

Большинство случаев SQL Injection можно предотвратить, используя параметризованные запросы вместо конкатенации строк внутри запроса. Эти параметризованные запросы также известны как «подготовленные выражения» (prepared statements).

Следующий код уязвим к SQL Injection, потому что пользовательский ввод конкатенируется прямо в запрос:

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

Вы можете использовать параметризованные запросы в любой ситуации, когда недоверенный ввод появляется как данные внутри запроса, включая WHERE-условие и значения в операторах INSERT или UPDATE. Их нельзя использовать для обработки недоверенного ввода в других частях запроса, таких как имена таблиц или столбцов, или раздел ORDER BY. Функциональность приложения, которая помещает недоверенные данные в эти части запроса, должна использовать другой подход, например:

  • Белые списки допустимых значений ввода.

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

Чтобы параметризованный запрос был эффективен в предотвращении SQL Injection, строка, используемая в запросе, всегда должна быть жёстко заданной константой. Она никогда не должна содержать никаких переменных данных из какого-либо источника. Не поддавайтесь искушению решать от случая к случаю, доверены ли данные, и продолжать конкатенировать строки для случаев, считающихся безопасными. Легко ошибиться с возможным источником данных или же изменения в другом коде могут «загрязнить» доверенные данные.

Last updated