
(CVE-2026-43499)Exploit de kernel para o OnePlus 15T com bootloader bloqueado.
Exploração de kernel direcionada a dispositivos OnePlus 15T com bootloader bloqueado. Usa a CVE-2026-43499 para obter acesso root sem desbloquear o bootloader ou modificar o boot.img.
Somente para pesquisa de segurança autorizada e fins educacionais.
Modificado a partir do repositório original GhostLock-for-OnePlus, adaptado para o layout de memória física e temporização de CPU do OnePlus 15T (PLZ110 / SM8850 / Snapdragon 8 Elite).
| Item | Detalhe |
|---|---|
| CVE | CVE-2026-43499 |
| Tipo | Use-After-Free em Futex PI (Priority Inheritance) |
| Escopo | Linux kernel 2.6.39 ~ 7.1 |
| Corrigido em | Mainline 7.1 (commit 3bfdc63936dd) |
| Status no Android | GKI 6.12.x ainda vulnerável |
A syscall pselect6 copia fd_set para a pilha do kernel. Quando combinada com o mecanismo de waiter PI do futex, um quadro de pilha liberado pode ser realocado como uma estrutura rt_mutex_waiter. Durante a travessia da cadeia PI, o rebalanceamento da rb-tree grava dados controlados em endereços arbitrários do kernel.
futex PI UAF (CVE-2026-43499)
├─ Forjar objeto rt_mutex_waiter
├─ Controlar a pilha do kernel via layout de fd_set do pselect/select
├─ Acionar operação PI do rt_mutex para gravação arbitrária
├─ Gravação 1: selinux_state.enforcing = 0
└─ Gravação 2: cred → init_cred (uid=0, capacidades completas)
| Dispositivo | Codinome | SoC | Kernel | Firmware | Status |
|---|---|---|---|---|---|
| OnePlus 15T | PLZ110 | SM8850 (Snapdragon 8 Elite) | 6.12.38-android16-5-g844001fb8721-ab14552068-4k | ColorOS 16.0.9.400 | ✅ Verificado |
Para Ace 6T e OnePlus 15, consulte o repositório original.
O GhostLock lida com a elevação de privilégios. A instalação do KernelSU requer o ksud (incluído com o kernelsu.ko específico da KMI):
| Fonte | Observações |
|---|---|
| APK ReSukiSU (recomendado) | Instale o ReSukiSU; o APK inclui libksud.so |
| Lançamento CI | Baixe de ReSukiSU CI (ksud-aarch64-linux-android.zip) |
Sem o ksud, a exploração ainda obtém shell root com uid=0, mas o KernelSU não será instalado e o
sunão persistirá.
ANDROID_NDK_HOME ou ANDROID_NDK_ROOT# Padrão (API 35)
make
# Especificar nível de API
make API=34
# Especificar caminho do NDK
NDK=/caminho/para/android-ndk make
ghostlock — executável ELF ARM64 estaticamente vinculado.
# 1. Ativar o modo TCP do ADB
adb tcpip 5555
# 2. Enviar a chave ADB (necessária para o modo bootstrap)
adb push ~/.android/adbkey /data/local/tmp/a/adbkey
# 3. Enviar a exploração
adb push ghostlock /data/local/tmp/a/e
adb shell chmod 755 /data/local/tmp/a/e
Após o primeiro sucesso, o
resetpropdefine automaticamentepersist.adb.tcp.port=5555, permitindo execuções totalmente automáticas em reinicializações subsequentes.
/data/local/tmp/a/e
/data/local/tmp/a/e --bootstrap
setprop ativar ADB TCP 5555127.0.0.1:5555/data/local/tmp/a/e --write1
Offsets armazenados na tabela de consulta em src/devices/offsets.h, identificados por uname -r. O programa faz a correspondência automaticamente na inicialização; kernels desconhecidos são rejeitados.
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 } /* sentinela */
};
| Tipo | Quantidade | Extração |
|---|---|---|
| Símbolos globais kallsyms | 28 | tools/extract_target.py |
| Campos de struct BTF | 57 | tools/extract_btf.py |
| Valores derivados | 9 | Calculados automaticamente |
| Constantes fixas | 12 | Codificadas |
| Struct | Campos | Finalidade |
|---|---|---|
task_struct | 17 | Descritor de processo, cred, seccomp |
rt_mutex_waiter | 6 | Alvo de forja do UAF |
cred | 4 | Credenciais, capacidades |
seccomp | 3 | Estado do filtro seccomp |
pipe_inode_info | 11 | Operações de buffer de pipe |
file_operations | 13 | Tabela fops falsa |
mm_struct | 1 | Proprietário do descritor de memória |
Quando os ponteiros do kernel estão restritos (kptr_restrict), vaze o endereço base via boot_id sobrescrito com um endereço do kernel:
Ler /proc/sys/kernel/random/boot_id
└─ UUID contém o endereço de nfulnl_logger
└─ Slide KASLR = endereço vazado - image_offset
└─ kaslr_base
Quando o dispositivo ashmem está acessível, use as primitivas de leitura/gravação do configfs para ler ponteiros de função da tabela fops do ashmem e calcular o offset KASLR.
Forje objetos do kernel em páginas order-3 (32KB):
file_operations falso — sequestre o ponteiro fops do miscdevice ashmemrt_mutex_waiter falso — simule o nó waiter da cadeia PItask_struct falso — referência de tarefa durante a travessia PIrt_mutex (lock) falso — informações corretas de waiter/ownerImplementado via SKB (socket buffer) + KernelSnitch:
mm_structsendmsg para preencher o heap do kernelApós obter a base KASLR, use buffers de pipe para acesso à memória em nível físico:
1. Localizar o buffer de pipe no physmap
2. Forjar a tabela de ops do pipe_buffer apontando para pipe_buf_ops conhecido
3. Sequestrar pipe_buffer.page para o endereço físico alvo
4. Leitura/gravação física arbitrária via operações normais de pipe
Suportado: pipe_read64, pipe_write64, pipe_phys_read_data, pipe_phys_write_data
Alvo: selinux_state.enforcing (offset 0x00)
Método: gravação PI de nó filho → forjar waiter __rb_parent_color
apontando para selinux_enforcing - 8
o rebalanceamento da rb-tree grava 0x00