3.1.4 容器管理程序接口存在的风险
Socket是Docker守护进程接收请求及返回响应的应用接口。在图3-1中可以看到,Docker守护进程主要监听两种形式的Socket:UNIX socket和TCP socket[1]。安装完成并启动后,Docker守护进程默认只监听UNIX socket。
1.UNIX socket
为什么UNIX socket也可能存在风险呢?它的问题主要与Docker守护进程的高权限有关:Docker守护进程默认以宿主机root权限运行。只要能够与该UNIX socket进行交互,就可以借助Docker守护进程以root权限在宿主机上执行任意命令。相关的风险利用场景主要有两个:
1)许多用户为了方便,不想每次输入密码时使用sudo或su,就将普通用户也加入了docker用户组,这使得普通用户有权限直接访问UNIX socket。那么一旦攻击者获得了这个普通用户的权限,他就能够借助Docker UNIX socket在宿主机上提升为root权限。
2)为了实现在容器内管理容器,用户可能会将Docker UNIX socket挂载到容器内部。如果该容器被入侵,攻击者就能借助这个socket实现容器逃逸,获得宿主机的root权限。
如何利用UNIX socket提升权限、逃逸出容器呢?我们将在3.4.1节曝光。
2.TCP socket
在版本较新的Docker中,Docker守护进程默认不会监听TCP socket。用户可以通过配置文件[2]来设置Docker守护进程开启对TCP socket的监听,默认监听端口一般是2375。
然而,默认情况下对Docker守护进程TCP socket的访问是无加密且无认证的。因此,任何网络可达的访问者都可以通过该TCP socket来对Docker守护进程下发命令。例如,以下命令能够列出IP为192.168.1.101的主机上的所有活动容器:
docker -H tcp://192.168.1.101:2375 ps
显而易见,攻击者也能够通过这样的TCP socket对目标主机上的Docker守护进程下发命令,从而实现对目标主机的控制。控制方式与通过UNIX socket的控制类似,只是需要通过-H tcp://参数来设置目标地址和端口。
[1] 事实上还有fd socket,但日常使用很少。
[2] 可参考样例:https://gist.github.com/styblope/dc55e0ad2a9848f2cc3307d4819d819f。