Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

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

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

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-43499-S26 — Android GKI 6.12 커널 익스플로잇으로, CVE-2026-43499를 대상으로 하며 rt_mutex 롤백 버그와 pselect 스택 덮어쓰기를 연쇄하여 Samsung 및 Pixel 기기에서 root 권한을 획득합니다. | Kitploit
도구/GitHubGitHub/sammyenigma/cve-2026-43499-s26
Android SecurityPrivilege EscalationMemory ForensicsPersistence MechanismsExploitationReverse EngineeringShellcodePost-ExploitationMobile SecurityPayload DevelopmentBinary Exploitation
1441개월 전아직 검토되지 않음

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
GitHub
sammyenigma/cve-2026-43499-s26

CVE-2026-43499-S26

Android GKI 6.12 커널 익스플로잇으로, CVE-2026-43499를 대상으로 하며 rt_mutex 롤백 버그와 pselect 스택 덮어쓰기를 연쇄하여 Samsung 및 Pixel 기기에서 root 권한을 획득합니다.

저장소 보기

CVE-2026-43499 — Android GKI 6.12 pselect / configfs 커널 익스플로잇

Android GKI 6.12 라인(Samsung 및 Pixel 기기)을 대상으로 하는 Linux 커널 익스플로잇으로, CVE-2026-43499를 겨냥합니다: rt_mutex_start_proxy_lock() 내의 버그가 있는 remove_waiter() 롤백이 waiter::task 대신 current를 사용하여, waiter의 pi_blocked_on이 (나중에 pop되는) 커널 스택 rt_mutex_waiter를 가리킨 채로 남게 됩니다. 여기에 pselect() fd_set 스택 덮어쓰기와 consumer의 sched_setattr 기반 가짜 rb_tree 순회를 결합하면 결정론적인 커널 쓰기 프리미티브와 완전한 root를 얻을 수 있습니다.

이 익스플로잇은 LD_PRELOAD 공유 라이브러리(preload.so)로 실행되며, root 획득 후 아티팩트로 root su 데몬과 월페이퍼를 설치합니다.

상태: 활발히 개발 중. m1q (ZF1) 타겟이 bring-up의 초점입니다. pipei tmp_page-uname 부트스트랩이 현재 활성 경로입니다: 순회는 온디바이스에서 깨끗함이 입증되었고(build #33: 자식별 시드된 rt_mutex 영역), 전체 168개 후보 스윕이 진행 중입니다. configfs CFI 경로는 m1q에서 막다른 길이며(Rust ashmem — 주입 가능한 fops 슬롯 없음), C-ashmem 타겟을 위한 경로로 남아 있습니다. 타겟별 오프셋은 기기마다 다르므로 신뢰하기 전에 실제 커널 바이너리와 대조하여 검증하십시오.

취약한 프리미티브 (CVE-2026-43499)

FUTEX_CMP_REQUEUE_PI가 waiter를 requeue하고 requeue의 교착 감지 체인 순회가 -EDEADLK를 반환하면, __rt_mutex_start_proxy_lock()은 remove_waiter()를 통해 롤백합니다(rtmutex.c:1535). 롤백은 waiter를 대기 트리에서 올바르게 디큐하지만, waiter->task->pi_blocked_on 대신 requeue 호출자의 pi_blocked_on을 클리어합니다. WAITER의 pi_blocked_on은 스택 rt_mutex_waiter를 가리킨 채 dangling 상태로 남고, 이는 futex가 타임아웃되면 pop됩니다.

타임아웃 후 waiter의 커널 스택 영역이 재사용됩니다: core_sys_select()가 세 개의 fd_set을 해당 스택 버퍼로 복사합니다(ZF1의 nfds < 344 스택 경로). 조작된 fd_set 워드 배열이 가짜 rt_mutex_waiter / 가짜 task / 가짜 rt_mutex(포인터가 제어되는 rb_tree 루트 포함)를 재구성합니다. 그런 다음 consumer 스레드가 sched_setattr_tid(waiter) → rt_mutex_adjust_pi() → rb_erase_cached를 호출하여 제어된 값의 임의 주소 쓰기를 만들어냅니다.

전체 프리미티브는 PI 체인 사이클을 필수로 요구합니다: owner가 f_pi_target을 보유하면서 동시에 (waiter가 보유한) f_pi_chain에서 블록되므로, 체인 순회가 owner → chain → waiter → target → owner에 도달하여 -EDEADLK로 실패합니다. 사이클을 제거하면 requeue가 성공을 반환하고 커널 효과는 전무합니다.

익스플로잇 체인

  1. Slide (KASLR) — 커널 베이스를 유출합니다. 두 가지 경로:
    • tracefs sched_blocked_reason (m1q 주 경로, 온디바이스 입증): 블록된 kworker의 저장된 반환 PC(stack_trace_save_tsk)를 링 버퍼에서 읽어 컴파일 내장된 worker_thread 오프셋과 비교합니다. 부트_id 경로 워드가 사용되기 전에 실행되므로 데이터-앨리어스 쓰기 타겟(data_addr() = p0 앨리어스 + slide_p0_offset)이 0이 아닌 slide에서도 올바르게 유지됩니다.
    • boot_id pselect 경로 (폴백, slide 독립적): pselect 쓰기가 선형 맵 앨리어스를 통해 SLIDE_LOGGERS_0_1을 boot_id sysctl 데이터에 심고, 유출된 값이 stext를 재구성합니다. m1q에서는 보류됨: W1 타겟 (SLIDE_RANDOM_BOOT_ID_DATA_OFF, 낮은 물리 RAM)은 페이지 의존적 쓰기 가능성을 가지며 — slide가 부팅마다 타겟을 페이지 경계 너머로 이동시키므로 약 6/7 실행이 폴트합니다. SLIDE_FORCE_BOOTID(메커니즘 테스트)로 명시적 실행할 때만 tree_pc/tree_left가 스프레이된 페이지로 리다이렉트됩니다.
  2. KernelSnitch — mm_struct 크기의 객체를 스프레이하고 futex-hash 충돌을 사용하여 힙에서 mm_struct를 찾아내어, 가짜 객체 스프레이 베이스로 사용되는 커널 힙 페이지 주소를 유출합니다. 정리 시 waiter는 (join하지 않고) 분리되어 #26 이전 빌드를 크래시시킨 커널 스택 OOM을 피합니다.
  3. 주 경로 — pipei tmp_page 부트스트랩 (m1q, 현재 초점) — 원래의 configfs CFI 경로는 m1q에서 막다른 길입니다: Rust ashmem에는 주입 가능한 정적 write_iter 슬롯이 없고 ASHMEM_SET_NAME 힙 객체는 레이아웃이 configfs_bin_write_iter의 private_data와 정렬되지 않는 KVec입니다. m1q는 대신 kmalloc 쓰기로 전환합니다: 유출된 mm order-3 블록을 pipe_inode_info 객체로 재점유하고 pselect W1 쓰기(*(tree_left) = tree_pc)를 사용하여 후보의 tmp_page 슬롯(+0x90)을 UTS 네임스페이스 페이지(init_uts_ns)로 덮어씁니다. fanout 쓰기가 sysname 오프셋에 마커 이름을 심고 uname()이 "CatOS"를 보고합니다 — 정적 객체 의존성이 없는 검증 가능한 커널 쓰기입니다. C-ashmem 타겟은 configfs 경로를 유지합니다.
  4. Pipe physrw — 물리적 읽기/쓰기를 위해 스프레이된 커널 페이지에 pipe 버퍼 페이지를 위조합니다: cred 패칭, SELinux 비활성화, 직접 커널 메모리 조작.
  5. Root — root 자식의 cred(uid/gid/caps/SELinux SID)를 패치한 다음, preload.c가 내장된 su 데몬(/apex/com.android.virt/bin에 tmpfs 마운트, plus adbd-namespace 및 로컬 변형)을 설치하고 월페이퍼를 교체합니다.

순회 형태 (m1q, 온디바이스 입증)

pselect fd_set 워드가 waiter의 커널 스택에 가짜 rt_mutex_waiter를 재구성하고, consumer 스레드의 sched_setattr_tid(waiter)가 rt_mutex_adjust_pi()를 통해 이를 순회합니다. ZF1 워드 맵(디스어셈 검증): PSELECT_WAITER_WORD_SHIFT = 0, word 12 = task (@+0x50), word 13 = lock (@+0x58), word 14 = wake_state (@+0x60 = 3). 시드된 가짜 rt_mutex를 사용하면 순회가 깨끗하게 완료됩니다: [7]의 rb_erase W1 *(tree_left)=tree_pc / W2 *(tree_pc&~3+8)=tree_left가 유일한 커널 쓰기이며, [11] (setprio / dequeue_pi)과 [9] wake는 모두 건너뜁니다(prio 100의 로컬 가짜 waiter가 스택 노드를 top-waiter 밖에 유지). build #19 이후 모든 순회 진입 완료가 온디바이스에서 생존합니다; 그 이전의 결정론적 크래시는 순회 본체 결함이 아니라 8바이트 페이로드 배치 오류(SKB_DATA_DELTA)였습니다.

Stage 3 (pgd-swap 브리지, 정적/빌드 전용)

선택적 STAGE3=1 단계로, 브리지 자식을 fork하고 그 mm->pgd를 준비된 가짜 페이지 테이블(3레벨: PGD→L1→L2, RX 루프 리프 + RW 스택 리프)로 교체한 뒤, 자식이 레지스터 전용 어셈블리 블롭을 실행하여 2MB 물리 스캔 윈도우를 통해 자신의 cred를 패치하도록 합니다 — configfs/pipe 프리미티브 없이 전 RAM 물리 R/W. 현재 m1q 타겟에만 연결되어 있으며 온디바이스에서 실행된 적은 없습니다.

지원 타겟

src/targets/<codename>-<build>/에 41개 타겟이 있으며, 각각 최소한 target.h(커널 심볼 오프셋, KIMAGE_TEXT_BASE, direct-map 베이스, 구조체 오프셋)를 필요로 합니다. Pixel 타겟(comet, tokay, tegu, caiman, komodo, frankel, mustang, rango, stallion, blazer)은 공유 소스를 오버라이드하고, Samsung 타겟(m1q-*)은 기기별 로직을 추가합니다.

make list-projects   # full list

커널 구조체 레이아웃은 기기마다 다르므로 — 오프셋은 각 타겟의 실제 커널 바이너리 / kallsyms와 대조하여 검증해야 합니다.

빌드

출력: build/<PROJECT>/bin/preload.so (LD_PRELOAD로 로드되는 공유 라이브러리).

# Default project
CC=clang make

# Specific device target (default: blazer-CP2A.260605.012)
CC=clang make PROJECT=m1q-BP4A.251205.006

# Without CC=clang: uses NDK if found ($NDK_ROOT / $ANDROID_NDK_HOME /
# $ANDROID_NDK_ROOT), otherwise host clang + Android sysroot
make PROJECT=m1q-BP4A.251205.006

# Show build configuration
make info

# Clean
make clean

빌드는 PIE su_daemon 바이너리(src/su_daemon.c, build/embed/su_daemon_aarch64_pie로 빌드됨)와 assets/wallpaper.webp를 src/su_blob.S / src/wallpaper_blob.S를 통해 preload.so에 내장합니다.

기기에서 실행

빌드 출력을 /data/local/tmp로 푸시한 다음, LD_PRELOAD 하에서 익스플로잇을 실행합니다. 라이브 bring-up 타겟에서는 tee 없이 실행하십시오 — tee는 자체 stdio를 버퍼링하여 커널 패닉 시 로그의 꼬리를 잃습니다(익스플로잇 stdout은 언버퍼링이므로 파일로 바로 리다이렉트하면 모든 줄이 보존됩니다):

adb push build/m1q-BP4A.251205.006/bin/preload.so /data/local/tmp/preload.so
adb push build/embed/su_daemon_aarch64_pie /data/local/tmp/su_daemon_aarch64_pie
adb shell "chmod 755 /data/local/tmp/preload.so /data/local/tmp/su_daemon_aarch64_pie"

adb shell "LD_PRELOAD=/data/local/tmp/preload.so \
  /data/local/tmp/su_daemon_aarch64_pie \
  > /data/local/tmp/output.log 2>&1"

성공하면 데몬이 /data/local/tmp/temp_su.sock에서 리스닝하고 su가 /apex/com.android.virt/bin 아래에 설치됩니다.

m1q pipei 스윕 (현재 bring-up)

tools/run_pipei.sh는 바이너리를 푸시하고, 온디바이스에서 sha256 검증한 뒤(오래된 preload.so는 조용히 판독 불가능한 판정을 낳습니다 — ladder가 한때 로그 형식이 다른 build < #22를 실행했습니다), 전체 168개 후보 스윕을 3x56으로 청크하여 패닉 시 최대 한 청크(~10분)만 잃도록 실행합니다. 익스플로잇 stdout은 adb를 통해 직접 스트리밍됩니다(온디바이스 리다이렉트 없음 — 기기 측 tee는 패닉 시 꼬리를 잃습니다); 각 청크의 호스트 측 사본은 /tmp/m1q_pipei_chunk{1..3}_stream.log에 보관됩니다:

sh tools/run_pipei.sh

PASS = 어느 청크든 tmp_page uname changed + after uname='CatOS를 보이는 경우. PIPEI_CHILD_REGIONS는 최소한 청크 크기로 설정되어야 하며, 그렇지 않으면 자식별 rt_mutex 영역이 시드되지 않은 채로 남아 스윕이 후보 0에서 패닉합니다. 전체 커버리지는 또한 TMP_UNAME_PIPEI_SPLIT_ORDER_PAGES=1을 요구합니다 — 이것 없이는 해제된 8페이지 mm 블록 중 한 페이지만 스윕됩니다. run_pipei_slim.sh는 단일 후보 진단 변형이고, run_m1q_ladder.sh는 순회/격리 배터리(B16-2 오라클, slide 메커니즘, 스윕 단계)입니다.

런타임 구성 (환경 변수)

도구 다운로드