# How to Generate a Bind Shell Payload with IngressNightmare: CVE-2025-1974 Exploitation Guide

> Learn to generate a bind shell payload using IngressNightmare CVE-2025-1974. Explore the NewBindShellPayload function to patch danger.so and switch execution modes for secure exploitation.

- 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

---

**Generate a bind shell payload with IngressNightmare by using the `NewBindShellPayload` function in [`nginx-ingress/payload.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/payload.go), which patches the embedded `danger.so` binary with your specified port and switches the execution mode from `MODE_CHECK_FLAG` to `MODE_BINDING_SH`.**

The IngressNightmare exploit toolkit targets the Ingress-NGINX controller vulnerability CVE-2025-1974, allowing attackers to execute arbitrary code via the `ValidateAdmission` webhook. When you need to establish a bind shell—where the target pod listens for incoming connections rather than connecting back to you—the toolkit provides a specialized payload generation mechanism. This guide explains how to generate bind shell payload with IngressNightmare using the command-line interface and underlying Go implementation.

## Understanding the Bind Shell Payload Architecture

The bind shell payload is constructed as a malicious shared object (`.so`) file that the vulnerable Ingress-NGINX controller loads into its process space. Unlike a reverse shell that initiates an outbound connection, the bind shell opens a listening socket inside the compromised pod, waiting for the attacker to connect.

### Port Encoding and Byte Replacement

The `NewBindShellPayload` function in [`nginx-ingress/payload.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/payload.go) handles the critical step of port configuration. When you specify a bind shell port (for example, `4444`), the function performs two transformations:

1. **Zero-padding**: The port number is left-padded with zeros to create a fixed 5-character string. Port `4444` becomes `04444`, while port `99999` remains `99999`.

2. **Binary patching**: The function locates the placeholder string `31337` (the default marker) within the embedded `danger.so` binary and replaces it byte-by-byte with the zero-padded port string. This ensures the bind shell listens on your specified port when executed.

### Mode Switching Mechanism

After patching the port, the payload generator switches the execution mode flag inside the binary. The embedded `danger.so` contains multiple execution paths controlled by internal markers:

- `MODE_CHECK_FLAG`: The default verification mode (used for testing if the library loads correctly).
- `MODE_BINDING_SH`: The bind shell mode that executes `/bin/sh` and binds it to the patched port.

The `NewBindShellPayload` function swaps these markers, ensuring that when the Ingress-NGINX controller loads the shared object, it executes the bind shell routine rather than the check routine.

## Step-by-Step: Generate Bind Shell Payload with IngressNightmare

The IngressNightmare repository (`esonhugh/ingressnightmare-cve-2025-1974-exps`) provides a command-line interface that abstracts the payload generation process. You can generate and deploy the bind shell payload using specific flags.

### CLI Flags and Configuration

The relevant flags for bind shell generation are defined in [`main.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/main.go):

- `--mode` (`-m`): Set to `bind-shell` (or `b` for short) to select the bind shell payload type.
- `--bind-shell-port` (`-b`): Specify the port number where the shell will listen (range: 1-65535, though internally formatted as 5 characters).

Additional required flags for the exploit:
- `--ingress-webhook-url` (`-i`): The HTTPS endpoint of the Ingress-NGINX admission controller.
- `--upload-url` (`-u`): The HTTP endpoint of the Ingress-NGINX controller pod used for file upload (the "bad upload" method).

### Dry-Run Verification

Before executing against a live target, verify the payload generation using the `--dry-run` flag. This outputs the raw binary payload to stdout instead of uploading it, allowing you to inspect the size or pipe it to analysis tools.

```bash
./ingress-nightmare \
  --mode bind-shell \
  --bind-shell-port 4444 \
  --ingress-webhook-url https://ingress-nginx-controller-admission.namespace.svc:443 \
  --upload-url http://ingress-nginx-controller.namespace.svc:80 \
  --dry-run

```

When run with `--dry-run`, the tool invokes `NewBindShellPayload(4444)`, which returns the patched `.so` content. You can redirect this output to a file to verify the binary structure: `--dry-run > /tmp/payload.so`.

### Live Exploitation Example

To execute the full exploit chain and establish a bind shell on the target pod:

```bash
./ingress-nightmare \
  -i https://ingress-nginx-controller-admission.default.svc:443 \
  -u http://ingress-nginx-controller.default.svc:80 \
  -m b \
  -b 4444

```

**Parameter breakdown:**
- `-i` points to the admission webhook that triggers the validation logic.
- `-u` specifies the upload endpoint where the malicious `.so` file is placed using the "bad upload" technique.
- `-m b` selects bind-shell mode (short alias for `bind-shell`).
- `-b 4444` configures the payload to listen on TCP port 4444.

Upon successful execution, the tool uploads the payload generated by `NewBindShellPayload`, probes the webhook until the library loads, and the target pod opens `/bin/sh` bound to `0.0.0.0:4444`. You can then connect using `nc <pod-ip> 4444`.

## Technical Implementation Details

The bind shell generation relies on specific source files within the `esonhugh/ingressnightmare-cve-2025-1974-exps` repository.

### Payload Construction Logic

The core function `NewBindShellPayload` resides in [`nginx-ingress/payload.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/payload.go) (lines 74-90). This function:

1. Accepts an integer port parameter.
2. Formats it using `fmt.Sprintf("%05s", port)` to ensure 5-character width.
3. Invokes `bytes.ReplaceAll` to substitute the hardcoded placeholder `31337` with the formatted port.
4. Replaces the mode marker `MODE_CHECK_FLAG` with `MODE_BINDING_SH` to trigger the bind shell execution path.

The function returns a `[]byte` slice containing the complete malicious shared object ready for upload.

### CLI Integration

In [`main.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/main.go), the bind shell configuration is exposed through flag definitions (lines 78-86):

```go
&cli.StringFlag{
    Name:    "mode",
    Aliases: []string{"m"},
    Value:   "check",
    Usage:   "Payload mode: check, bind-shell, reverse-shell, cmd",
},
&cli.IntFlag{
    Name:    "bind-shell-port",
    Aliases: []string{"b"},
    Value:   31337,
    Usage:   "Port for bind shell (used with -m bind-shell)",
}

```

The main execution logic (lines 11-18) switches on the `mode` flag, calling `NewBindShellPayload` when `mode == "bind-shell"` or `"b"`.

### Upload and Trigger Mechanism

The `BadUploader` function in [`nginx-ingress/exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/exploit.go) (lines 52-85) handles the actual delivery:

1. Constructs a multipart form-data request containing the generated `.so` payload.
2. POSTs the request to the `--upload-url` endpoint (exploiting the "bad upload" vulnerability).
3. Returns the path where the file was stored on the target.

The main exploit loop then repeatedly sends validation requests to the `--ingress-webhook-url`, causing the Ingress-NGINX controller to load the uploaded shared object and execute the bind shell.

## Summary

- **IngressNightmare** generates bind shell payloads by patching the embedded `danger.so` binary with a specified port and switching the execution mode from `MODE_CHECK_FLAG` to `MODE_BINDING_SH`.
- Use the **`--mode bind-shell`** (or `-m b`) flag combined with **`--bind-shell-port`** (or `-b`) to configure the payload via the CLI.
- The **`NewBindShellPayload`** function in [`nginx-ingress/payload.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/payload.go) handles zero-padding the port to 5 characters and replacing the placeholder `31337` in the binary.
- The **`BadUploader`** in [`nginx-ingress/exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/exploit.go) delivers the payload to the target pod, after which repeated webhook probes trigger the library load and bind shell execution.

## Frequently Asked Questions

### What port range can I use for the bind shell payload?

IngressNightmare accepts any valid TCP port number from 1 to 65535. The `NewBindShellPayload` function formats your input using `fmt.Sprintf("%05s", port)`, which left-pads the number with zeros to ensure exactly 5 characters (e.g., port 80 becomes `00080`). This fixed-width string then replaces the placeholder `31337` in the embedded `danger.so` binary.

### How does the bind shell mode differ from reverse shell mode?

The bind shell mode configures the malicious `.so` library to execute `/bin/sh` and attach it to a listening socket on the target pod, whereas reverse shell mode causes the pod to initiate an outbound connection to an attacker-controlled listener. In [`nginx-ingress/payload.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/payload.go), bind shell mode sets the internal marker to `MODE_BINDING_SH`, while reverse shell uses `MODE_REVERSE_SH`. Use bind shell when the target pod cannot reach your external IP due to egress filtering, or when you want a persistent listener independent of your network location.

### Can I use a custom compiled shared object instead of the embedded one?

Yes, if you encounter architecture mismatches or "exec format error" messages, you can compile a custom `danger.so` for the target platform and supply it via the `--so` flag. The `NewBindShellPayload` function will still apply the same byte-replacement logic to your custom binary—patching the `31337` placeholder with your zero-padded port and switching the mode marker to `MODE_BINDING_SH`—before the `BadUploader` in [`nginx-ingress/exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/exploit.go) delivers it to the target.

### Why does the exploit require both a webhook URL and an upload URL?

IngressNightmare exploits a two-stage vulnerability in Ingress-NGINX: first, it uploads the malicious `.so` file to a writable directory within the controller pod using the "bad upload" method (targeting the `--upload-url`), and second, it triggers the `ValidateAdmission` webhook (`--ingress-webhook-url`) to load that file as a shared library. The webhook runs with elevated privileges and loads the uploaded path, executing your bind shell payload. Without both endpoints, the library cannot be placed on the filesystem or loaded into memory.