CVE-2022-0492导致的容器逃逸无法复现原因分析
2024-2-4
| 2024-2-16
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password

前言

漏洞原理:当容器有 CAP_SYS_ADMIN 权限时,我们可以通过 cgroup v1 的 notify_on_release 机制进行容器逃逸。CVE-2022-0492 则是没有校验当前用户命名空间 Linux Capability 是否为容器创时命名空间,就算启动容器时没有赋予 CAP_SYS_ADMIN 权限,导致我们可以利用 unshare 创建新的新的命名空间时拥有所有 Linux Capability(当然这个和 uid 映射一样,非真正 root 的 Linux Capability),从而利用 CAP_SYS_ADMIN 的逃逸姿势进行容器逃逸。
详情可戳 👇
 
但我在复现的时候,复现不了
容器启动命令(当然在 k8s 下也试过部署Pod了)
利用 exp(这里先声明下,这个 exp 是没问题的)
但会在写 release_agent 的时候出现

问题分析

当然这个cve导致的容器逃逸是有一定限制的,但我验证过了,都满足
  1. root 容器,允许 unprivileged user namespaces
  1. 没有 apparmor selinux seccomp (不然 unshare 不了)
  1. 使用 cgroup v1
  1. Linux内核 < 5.17.3-rc3 (当然有的版本的小版本会修复,具体影响范围可以看 https://nvd.nist.gov/vuln/detail/CVE-2022-0492
 
看网上文章,最近可以复现成功的大多都是通过 --cap-add=SYS_ADMIN docker 启动时加 SYS_ADMIN …. 我寻思,都加 SYS_ADMIN ,这和 CVE-2022-0492 有啥关系….
 
然后我开始尝试更换Linux内核版本,在想会不会是官方内核范围描述不清,然后我尝试了包括,但不局限于
  • 5.8.0-050800rc1-generic
  • 5.15.0-78-generic
  • 4.15.0-213-generic
  • 5.13.0-19-generic (ubuntu21.10 用的cgroupv2)
  • 5.4.0-42-generic(ubuntu20.04.1)
都不行
 
虽然期间学到一种方式可以方便给内核升降级
发现有个方法可以降级内核
 
到这里,如果想通过 GRUB 菜单进去的话
(通常需要在启动时按住 Shift 或 Esc 键),然后从“高级选项”中选择您刚刚安装的内核版本启动
或者是 运行 grep -P 'menuentry ' /boot/grub/grub.cfg | nl -v 0 命令,找到你要的 (注意不选包含 recovery mode),把 /etc/default/grubGRUB_DEFAULT=数字 改成 第一个引号里的内容,然后执行
观察提示,会让我们改,如果 update-grub -v < 2.0 则把 /etc/default/grubGRUB_DEFAULT= 改为
≥2.0 则是
在执行
重启后查看内核就发现改变了
 
试试 降级containerd
这个方法可以升级到想要的内核版本
 
先到 https://kernel.ubuntu.com/mainline/ 挑想要的内核版本,然后
然后根据上面降内核的方法,选择新内核 reboot 重启即可
不知道前我是直接一个个 iso 镜像装的虚拟机…
 
到这里,想到官方给的内核范围应该没问题,我去看我复现几个版本的代码,确实没引入这个 patch
 
然后就搁置了一段时间,直到看到 @h4ckm310n 师傅的文章
 
不过偷懒了,apt 安装没文中 1.5.10-1版本,就apt装了个更低的版本,1.3.3-0ubuntu2。还是复现失败了,后面发邮件请教了下 @h4ckm310n 师傅:看下进入容器之后cat /proc/self/cgroup,看看 rdma 是不是挂载到 /,而不是 /docker/xxxxx。确实确实如 @h4ckm310n 师傅所说。
 
后面不偷懒了,直接找了 containerd 1.5.10-1 一样的版本,然后用,文章开始的利用 EXP,果然可以利用成功了,并且进入容器后 rdma 确实挂载到 / 了。
notion image
按理说文章到这里就应该结束了,毕竟复现成功了。但仔细思考一下,这和 containerd 的版本有啥关系呢?
 
这是两个不同 containerd 版本的目录树,其中 1.5.11 可复现,1.6.4 不行
 
tree containerd.io_1.5.11-1_amd64/
tree containerd.io_1.6.4-1_amd64/
通过 diff 发现 ubuntu 的 containerd 包,主要有几个不同的地方,除了 containerd 的版本,和一些其他配置文件(看了下不是啥关键的东西),包里还有 runc
 
containerd.io_1.5.11 里 runc 的版本
containerd.io_1.6.4 里 runc 的版本
 
这时我继续用 containerd 1.5.11 ,但是把 runc 替换成了 containerd 1.6.4 版本的 runc,因为运行了一下两个 containerd 里的 runc,他们版本不一样。结果,漏洞复现失败了。
 
然后我彻底卸载 containerd 1.5.11,安装 containerd 1.6.4,这时用的是 containerd 1.5.11runc,然后就复现成功了!甚至我安装更新版本的 containerd,把 runc 用旧的,依然复现成功。
 
看了一下 runc 1.1.0-rc.1 干了啥
https://github.com/opencontainers/runc/releases/tag/v1.1.0-rc.1 - Add support for RDMA cgroup added in Linux 4.11.
 
到这里比较清晰了,因为之前 runc 版本不支持 rdma,导致 mount 进去就是直接 mount / 根目录了。这时我们更新内核为非 CVE-2022-0492 影响版本 5.4.180-0504180-generic,虽然漏洞复现失败(且报错和 Linux 层的报错事符合的),但是 rdma 还是 mount / 根目录,这里还是有问题的,但这里还可以怎么利用,有点想不到了。
notion image
 
总结一下,CVE-2022-0492的漏洞利用前提除了一开始提到的前面4点,还有第5点
  1. root 容器,允许 unprivileged user namespaces
  1. 没有 apparmor selinux seccomp (不然 unshare 不了)
  1. 使用 cgroup v1
  1. Linux内核 < 5.17.3-rc3 (当然有的版本的小版本会修复,具体影响范围可以看 https://nvd.nist.gov/vuln/detail/CVE-2022-0492
  1. runc < 1.1.0-rc.1 版本(除了影响版本的runc,各个云厂商自研的系统里还有很多自研的cgroup subsystem可以利用,会使得容器内有 top level cgroup subsystem 可挂载,那就算用高版本runc,漏洞仍存在)
 
同时,这里引发了启发了我一个关于runc的漏洞挖掘思路,即当Linux出现新的cgroup子系统,但runc没有及时适配,那就很有可能存在一些问题。虽然现在cgroup在新内核都上v2了,v2默认都是 cgroup子系统默认ro(只读),所以又不是特别会导致问题,但算一个可以关注的点吧
  • 云安全
  • runc
  • 漏洞复现
  • WIZ CTF | K8S LAN PARTY Walkthrough云原生安全书籍收集
    • GitTalk
    目录