登录

在这个站点登录

保存我的登录记录

<<忘记密码?

还没有账号?点此注册>>

Jerry

骚操作:在Docker容器内重启宿主机

分享到:

本文已被浏览10614

新冠疫情期间,受困在家远程办公。连接上VPN后,能够正常连接并操作服务器,由于网络连接不稳定,在服务器上留下了一些异常的连接,表现为htop中能够看到一些sshd子进程,其下包含了一些诸如htop,bwm-ng之类不会自动结束的监控进程,于是开始作死。

使用sudo取得了管理员权限后,进入htop,按F5进入树形模式。最开始还是比较保守地结束sshd下的bash子进程,使sshd连接对应的父进程自动结束。后来也不知道怎么想的,退出htop直接killall sshd。于是问题出现,瞬间ssh断开连接,使用ssh工具重新连接远程主机发现提示connection refuse。至此,发现出事了。

在作死killall sshd的同时,把sshd最根上的那个爷爷辈的守护进程给一起杀了,相当于把ssh服务给停了,因此无法访问服务器。

万幸的是服务器并没有跑什么业务,只是为我开发做一个带GPU的调试环境。为了开发方便,开启了Docker的远程访问端口。于是着手从Docker看看有没有可能访问到宿主机,执行一些命令或者重启sshd。

首先为了操作方便,配置了一下本地WSL(Windows Subsystem Linux,Ubuntu)中的docker-ce-cli:

#与正常安装Docker引擎相同,先添加docker官方的源
curl -fsSLhttps://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
#与正常安装Docker引擎不同的是,只安装docker-ce-cli
sudo apt install docker-ce-cli

至此,本地WSL中的docker命令安装完成。因为本地WSL中并没有安装dockerd,所以此时的docker命令是无法使用的,通过在.bashrc中添加环境变量DOCKER_HOST使其默认使用远程主机开放的接口。此时,已经能够使用docker命令看到远程主机的一些信息:

docker info

期初,希望能够不重启宿主机,只是重启其上的sshd。在搜索引擎中找了一下关于docker容器内逃逸在宿主机上执行命令的内容,发现了V2EX上的一篇讨论(https://www.v2ex.com/t/417477),其中有个大佬提出了一种利用chroot和–privileged将docker内文件系统环境切换为宿主机文件系统的方案:

V2EX大佬

但是在我尝试后发现,除了一句Failed to connect to bus: No data available,并没有什么效果(现在来看可能当时是生效了,但是我没有继续尝试连接ssh),于是认为可能执行个简单的命令不太可能了,考虑直接触发宿主机重启。

后来在Github上找到一篇issue(https://github.com/moby/moby/issues/6401),提到了一个可能意外发现的在docker内执行reboot会触发宿主机系统重启的问题:

GitHub issue

其中提到即使没有使用–privileged参数给予docker内真正的root权限,使用–net host将host的网络环境直接放在docker内,执行reboot会触发宿主机重启,删除–net host参数后则不会。

抱着试试看的心态,我尝试了如下命令来启动一个具备绝对权限的docker:

docker run -it --rm --net host --privileged ubuntu /bin/bash

但是官方提供的ubuntu镜像并没有提供reboot这个命令,甚至init命令也没有,导致无法正确触发重启信号。考虑到前面V2EX大佬提供的思路,我重新创建了docker:

docker run -it --rm -v /:/host --net host --privileged ubuntu /bin/bash

随后在位于docker中的ubuntu中使用chroot命令切换根路径:

chroot /host /bin/bash

看似没有什么变化,实际上如果通过ls /会发现,/host目录已经不存在了,即证明已经切换到了宿主机的根文件系统中。随后我执行了reboot命令,虽然和之前一样报了相同的错误:

切换根目录并重启

但是与之前不同的是,docker立即断开了连接,此时宿主机应当是已经在重启了。稍等片刻,等待宿主机重启完成后发现22端口开放,可以使用ssh登录终端。启动htop后发现uptime为2分钟前,可以证明之前确实重启了服务器:

重启过后

这个例子中可以看出:

1.对外开放无认证的Docker API是非常危险的行为,生产环境应当禁止对外开放

2.–privilege能不用尽量不要用

3.–net host下可能触发重启的bug貌似还没有解决

4.reboot信号是通过网络发送给内核的?(有待考证)

 手机扫描左边的二维码,立刻将文章收入手机!
 微信扫描左边二维码,点击右上角即可分享到朋友圈!
严禁任何非授权的采集与转载,转载须经站长同意并在文章显著位置标注本文连接,站长保留追究法律责任的权利.

评论

 您需要 先登录 才可以回复.