5.3. Тестирование SQL Injection

 

Что такое SQLi

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

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

SELECT * FROM example_table WHERE login=’admin’ AND password=’Passw0rd!’

Если логин и пароль верны, то мы успешно авторизуемся на сайте.

Однако, что, если в POST запрос мы введем совершенно другие данные?

Например, в форме авторизации введем выражение ‘OR 1=1 #. Если на сервере нет никакой фильтрации и проверки введенных данных, то приложение сформирует такой SQL запрос:

SELECT * FROM example_table WHERE login=’admin’ OR 1=1 # ‘ AND password=’blablabla’

Знак # в некоторых СУБД используется в качестве комментария, то есть все, что следует после него интерпретатором игнорируется. В итоге, системой будет выполнен запрос SELECT * FROM example_table WHERE login=’admin’ OR 1=1.

Что у нас получится после выполнения такого выражения?

Возможны 2 варианта. Обратите внимание, что у нас 2 условия, причем требуется выполнение хотя бы одного из них, а не сразу обоих. Если логин admin существует, то мы сможем войти на сайт в качестве данного пользователя, не зная его пароль.  То есть в данном случае срабатывает первое условие.

Если же учетной записи нет, то сработает второе условие и база данных выдаст нам список всех пользователей. Условие 1=1 всегда означает ИСТИНУ. Если вам нужно получить ложное выражение, то достаточно использовать 1=2 или любое подобное выражение.

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

Следует также учитывать, что существуют 2 разновидности SQLi. Это обычная SQLi и Blind SQLi (слепая инъекция).

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

Где следует искать SQL уязвимости:

  • URL с GET/POST/PUT запросы.
  • HTML формы (обычно используются для POST и PUT запросов, в редких случаях для GET запросов)
  • Ссылки в HTML документе. Обычно они представляют собой URL с GET параметрами.
  • HTTP заголовки, например Cookies. Также это могут быть нестандартные заголовки, в которых передается служебная информация.
  • Выпадающие списки (HTML элементы Select/Option). Обычно они являются частью HTML элемента Form.
  • JavaScript – с помощью него на сервер передаются параметры через POST/PUT запросы. Обычно эти запросы передаются в форме JSON, иногда

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

 

Тестирование на SQLi – методы поиска уязвимостей

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

String Delimiter – ввод одиночной или двойной кавычки

Самым первым и простым способом является ввод одиночной или двойной кавычки. Делается это для вызова ошибки или изменения поведения приложения. Например, представим, что у нас имеется URL вида https://example.com?name=John. На сервер формируется запрос SELECT * FROM users WHERE name=’John’;, который работает без проблем. Однако, если в параметр ввести кавычку, то SQL запрос будет выглядеть так:

SELECT * FROM users WHERE name=’John’’;

или

SELECT * FROM users WHERE name=’John’”; (введена двойная кавычка).

Синтаксис запроса неверный, а потому поведение БД изменится. Именно это нам и нужно. Заметив любые отклонения от нормы после ввода кавычек, мы можем полагать, что введенный символ все-таки попал в БД и запрос был выполнен. Заметьте, что мы можем только полагать, а не быть уверенными на все 100%. Возможна ситуация, когда сервер фильтрует поступающие значения параметров и, если что-то не так, то он их просто удаляет. В данном случае приложение тоже поведет себя по-другому в зависимости от того, как оно запрограммировано.

Теперь попробуем протестировать данный метод на некоторых приложениях.

В качестве первого приложения воспользуемся Muttilidae. В левом боковом меню переходим по OWASP 2013 --> A1 – Injection (SQL) --> SQLi Extract Data --> User Info (SQL). Откроется страница с формой входа на сайт. Если ввести в качестве логина и пароля admin/admin, то отобразится следующая информация:

Тестирование SQL Inujection и Mutillidae

 

Однако, если мы добавим кавычку в поле Name или Password (admin’/admin или admin/admin’), то у нас отобразится сообщение об ошибке:

Сообщение об ошибке в MySQL

Сообщение содержит много информации, однако самое главное – это SQL запрос. Зная его, мы можем создать свой запрос, который сработает на сервере. Подобные сообщения об ошибках не редкость. Иногда разработчики забывают выключить отображение подобных сообщений.

Рассмотрим другое приложение, например WackoPicko. Откройте страницу входа на сайт и введите admin’/admin:

Тестирование на SQLi WackoPicko

Отобразится следующая ошибка:

SQL ошибка в WackoPicko

Здесь не отображается весь SQL запрос, а лишь некоторые подсказки, которые могут нам помочь в отгадывании SQL запроса.

 

Сортировка

С помощью операторов сортировки ORDER BY мы можем не только сортировать выходные данные, но и определять количество столбцов в запросе и вызывать ошибку исполнения.

Предположим, у нас имеется запрос вида SELECT name, surname FROM table.  Запрос выведет данные в 2 колонки (столбца). Если мы добавим ORDER BY 1 или ORDER BY 2 в конец запроса, то это не вызовет ошибки. Однако ORDER BY 3 или любое другое число, отличное от 1 и 2, вызовет ошибки исполнения.

Откроем Muttilidae и введем запрос admin’ ORDER BY 10 #. В качестве номера столбца я ввел 10, так как у меня не сведений о точном количестве столбцов, поэтому лучше ввести любое большое число.  В конце необходимо указать символ комментирования, так как SQL запрос должен быть синтаксически правильным, иначе он не будет выполнен. Все остальные операторы и символы запроса будут игнорированы после символа комментирования. Данное выражение можно использовать в поле Name или Password. Результат выглядит так:

Столбец не существует - ошибка MySQL

Сервер сгенерировал ошибку, указав, что столбец под номер 10 не существует. Ниже следует сам запрос. Как видите сразу после символа # следует одиночная кавычка и часть выражения. Если бы мы не использовали символ комментирования, то запрос не был бы выполнен.

Подобную ошибку мы можем наблюдать и в другом приложении:

Отображение ошибку о неправильном столбце в WackoPicko

Что это означает?

Если вы видите подобную ошибку, то значит сервер не фильтрует введенные символы и передает их на исполнение, то есть это явное доказательство присутствия уязвимости SQLi.

 

Boundary testing – ввод параметров различных значений и типов

SQL запросы могут принимать определенные типы данных, например, только числовые значения, текстовые или все подряд. Среди числовых значений также существуют дробные, целочисленные, положительные и отрицательные значения. В базе данных для хранения этих значений выделяется определенное место (память). Именно на этом и основана следующая техника тестирования. Поясню на простом примере. Представим, что у нас имеется URL вида https://example.con?id=1, нас сервере формируется запрос SELECT * FROM table WHERE id=1. То есть параметр id принимает только целочисленные и положительные значения.

Что, если в качестве значения параметра мы введем текстовые, отрицательные и дробные данные? Мы также можем ввести целые числа, но очень большого диапазона, например, 1000000 и выше.

Неправильный тип данных может вызвать ошибку в БД, что указывает на то, что введенные данные никак не проверяются на сервере на соответствие требуемого типа. Однако не всегда несовпадающий тип данных вызывает ошибку. Система может попытаться преобразовать полученные данные в соответствующий тип. 

 

Fuzzing – автоматизация тестирования

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

Фаззинг можно провести с помощью программ, как Burp Suite, ZAP, Wfuzz и многих других. В качестве словаря можно использовать установленный Seclist либо любые другие файлы, найденные в интернете или составленные вручную.

Рассмотрим фаззинг на примере OWASP Juice Shop и Burp Suite. В Kali установлена бесплатная версия Burp Suite, которая содержит немного ограниченные возможности для фаззинга. Однако для проведения теста нам этого достаточно.

Откройте Burp Suite и перейдите во вкладку Proxy. Во вкладке кликнете на Open Browser, после этого откроется встроенный браузер Chrome. В адресной строке браузера введите адрес Juice Shop http://127.0.0.1:3000/#/login:

Страница входа в JuiceShop

В открывшейся странице введите любые email и пароль. После этого перейдите в Burp Suite во вкладку Target. Здесь будут отображаться все перехваченные запросы и ответы между браузером и сервером. Для начала настроим фильтр. Кликнете на фильтр и установите галочку, как указано на рисунке:

настройка фильтров в Burp Suite

Пролистайте список перехваченных запросов и найдите следующий POST запрос:

Перехваченные данные в POST запросе

Внизу отображаются запрос вместе с введенными логином и паролем, а также сам ответ сервера. Кликнете на иконку гамбургера, чтобы открыть контекстное меню и выберете опцию Send to Intruder либо просто наберите Ctr+I:

Отправка запроса в Intruder

Откройте вкладку Intruder. Intruder служит для фаззинга, поэтому в POST запросе мы будем подставлять различные SQL комбинации из словаря вместо логина/email. Для этого установите курсор мыши в значении поля “email”, удалите данное значение и дважды кликнете на кнопку Add:

Вкладка Intruder Burp Suite с перехваченным запросом

Тем самым мы устанавливаем маркер, на место которого будут подставляться различные комбинации. Далее перейдите во вкладку Payloads и кликнете на кнопку Load, чтобы загрузить комбинации из словаря. В качестве словаря выберете файл /usr/share/wordlists/wfuzz/Injections/SQL.txt:

Выбор и загрузка словаря для SQLi

У нас все готово, нажимайте на кнопку Start attack.

После этого откроется новое окно, в котором вы можете следить за ходом атаки. Обратите внимание на длину ответного сообщения и код ответа. Нас больше интересует код 500 (Internal Server Error) и само содержимое ответа:

Найденная уязвимость в JuiceShop

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