Skip to content

Latest commit

 

History

History
67 lines (42 loc) · 3.47 KB

File metadata and controls

67 lines (42 loc) · 3.47 KB

Exploit

This submission targets mitigation-v4-6.12 as a novelty-only follow-up for CVE-2025-40019. The regular vulnerability slot for this CVE and target was already taken; the relevant new part is the page-table adaptation described in docs/novel-techniques.md.

High-Level Flow

The exploit turns the ESSIV scatterwalk offset underflow into a 16-byte write through a reclaimed scatterlist entry.

  1. Create a sacrificial AF_ALG AEAD request that builds a chained receive scatterlist.
  2. Free that request so the inline first receive SGL, a second receive SGL, and the tag SGL remain as residual slab contents.
  3. Reclaim the second receive SGL slab slot with a Unix socket control-buffer allocation containing a crafted scatterlist entry.
  4. Reclaim the freed anonymous pipe pages as user page-table pages.
  5. Trigger the ESSIV decryption path with assoclen == 0 and an output length of zero, causing scatterwalk_ffwd() to walk the residual SGL chain and write the encrypted IV into a page-table page.
  6. Use a two-pass flow: pass 1 leaks the physical base needed for the target mapping, and pass 2 writes a coredump helper into core_pattern.

The exploit does not use user namespaces, io_uring, BPF, or a separate KASLR leak service.

Scatterlist Shaping

The trigger sends exactly 32 bytes to essiv(authenc(hmac(sha256),cbc(aes)),sha256). For this transform, the authentication tag size is 32 bytes. During decrypt, _aead_recvmsg() computes:

outlen = used - authsize = 0x20 - 0x20 = 0

Because outlen is zero, af_alg_get_rsgl() does not initialize the receive SGL. The request nevertheless passes the receive SGL to ESSIV as both source and destination. The vulnerable ESSIV offset calculation wraps to 0xfffffff0, so scatterwalk_ffwd() walks past the inline SGL and follows stale chain entries.

The sacrificial request constructs the stale chain before the trigger request:

first_rsgl[0..15] -> second_rsgl -> tsgl -> anonymous pipe pages

After the sacrificial request is freed, the exploit reclaims the second_rsgl allocation with a Unix socket msg_control buffer. The crafted entry supplies a large length value that steers the final scatterwalk_ffwd() position into the stale tsgl entries. The tsgl entries still encode pages that were freed after pipe closure; those pages are then reclaimed as page-table pages by a controlled mmap() spray.

IV Encoding

ESSIV encrypts the IV before copying it back. The exploit embeds AES code so it can precompute an IV that decrypts to the desired 16-byte page-table write for the selected pass.

In pass 1, the write maps a physical window that contains a known kernel trampoline page. Reading through the resulting huge mapping reveals enough physical address information to derive the _stext physical base used by pass 2.

In pass 2, the write maps the 1 GB physical window containing core_pattern and writes the helper payload through the corrupted user mapping.

Privilege Escalation

The payload written into core_pattern is:

|/proc/%P/root/tmp/ex %P

The /proc/%P/root prefix is required because the coredump helper path is resolved outside the process's jail-local mount namespace. The helper reopens the crashing process's standard file descriptors with pidfd_open() and pidfd_getfd(), then reads the flag from the target VM as root.

Reproduction

Build and run on mitigation-v4-6.12:

make
./exploit

For the vulnerability-only KASAN check:

./exploit --vuln-trigger