Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

FeedsContatoPrivacidade© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
ghostlock-pfem10 — GhostLock (CVE-2026-43499) para OPPO Find X5 Pro (PFEM10) — engenharia reversa do watchdog OPlus e do detector de heap-spray | Kitploit
Ferramentas/GitHubGitHub/imeiplus/ghostlock-pfem10
Segurança AndroidEscalada de PrivilégiosForensia de MemóriaAnálise de VulnerabilidadesExploraçãoEngenharia ReversaSegurança MóvelDesenvolvimento de PayloadsExploração de Binários
GitHubimeiplus/ghostlock-pfem10

ghostlock-pfem10

GhostLock (CVE-2026-43499) para OPPO Find X5 Pro (PFEM10) — engenharia reversa do watchdog OPlus e do detector de heap-spray

45há 22 diasAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar
Ver Repositório

GhostLock — OPPO Find X5 Pro (PFEM10)

English · 中文

build

Port do GhostLock (CVE-2026-43499) para o OPPO Find X5 Pro no ColorOS 16. Alcança um processo filho com uid=0 e um kernelsu.ko carregado; o processo root é interceptado.

Vulnerabilidade

CVE-2026-43499 — use-after-free no futex PI. remove_waiter() limpa current->pi_blocked_on quando current é o requeuer, no caminho de rollback -EDEADLK de rt_mutex_start_proxy_lock().

remove_waiter @ 0xffffffc0081ed254 — forma pré-correção.

Dispositivo

DispositivoOPPO Find X5 Pro (PFEM10)
SoCSM8450 / Adreno 730
SOColorOS 16.0.3.520 (CN01)
Kernel5.10.236-android12-9-o-gaf2075ad2c06
Bootloaderbloqueado, verde
VA_BITS39 — KIMAGE_TEXT_BASE = 0xffffffc008000000

Estado

Etapa
Disparo do waiter compacto (CMP_REQUEUE_PI → EDEADLK)funciona
Vazamento de task_struct (perf)funciona
Escrita PI (8 bytes; valor = 0 ou um endereço de kernel válido)funciona
task+0x778 ou task+0x780 sozinho → Uid=rootfunciona — mas um pouso de campo único deixa a task divergente, e isso é um BUG_ON rígido latente. Ver o risco de divergência
Ambos os campos escritos com UM valor (um par consistente)❌ nunca produzido com uma página pulverizada. Só foi observado com o alias global init_cred (09-14, CONTROL=1). O runner agora impõe isso (SAME_VALUE=1); não executado no dispositivo
Lavagem de credenciais (setresgid + setresuid)implementado atrás de V12_LAUNDER=1; não executado no dispositivo
kernelsu.ko carregadofunciona
Processo root sobrevive⚠ não estabelecido — ver abaixo
Mecanismo de reboot❌ não estabelecido. Um candidato (a divergência) agora está excluído; ver abaixo
probe_state como critério de pouso❌ errado — não usar. Três contraexemplos; ver a tabela abaixo
Canal de pânico pstore/ramoops⚠ instrumento existe; canal nunca validado (ainda sem teste nulo)
"A vítima gira em userspace puro"⚠ ainda sem leitura — uid.stream agora registra utime/stime/nvcsw para que possa ser verificado
escrita dupla de passagem única do lado pi⚠ não estabelecido; pi.pc/pi.left estão fixados em 0 em fdset_map.h
Caminho A (UMH / modprobe_path)STATIC_USERMODEHELPER_PATH=""

Sobre "processo root sobrevive": as execuções em evidence/kill.log alcançam uid=0 e carregam kernelsu.ko, e na execução que de fato fez polling o processo do gerenciador KernelSU sobreviveu 120 s com kernelsu ainda Live em /proc/modules. Em uma execução posterior, a mesma cadeia deixou os serviços do framework Android inacessíveis (Can't find service: package/power/input/phone/wifi) enquanto o módulo ainda estava Live. Nenhuma linha de kernel [ROOTCHECK-*] e nenhum payload $$sys_call_number@@ jamais foi capturado, então a causa do estado da execução posterior não é atribuída. Ver evidence/notes.md §2.3, §2.4 e §7.

Offsets

task_struct

CampoOffset
real_cred / cred0x778 / 0x780
syscallno em cache0xdf8
uid / euid / gid / egid em cache0xe00 / 0xe08 / 0xe10 / 0xe18

thread_info

CampoOffset
flags0x0
addr_limit0x8
ttbr00x10
preempt_count0x18

cred

CampoOffsetCampoOffset
uid0x4cap_inheritable0x28
gid0x8cap_permitted0x30
suid0xccap_effective0x38
sgid0x10cap_bset0x40
euid0x14cap_ambient0x48
egid0x18
fsuid / fsgid0x1c / 0x20

Fluxo do Exploit```

LT perf leak target task_struct → file W7 stage 1 task+0x778 = V (real_cred → private sprayed page; V observed) W7 stage 2 task+0x780 = V (cred) ★ V12_W7_VALUE=V — THE SAME VALUE, not a new page W7 stage 3 V+8 = 0 (LOCAL repair of the page that was installed, ZERO shape) LT child fexecve(memfd of loader) — no execve of a /data path loader ksud late-load → kernelsu ... Live

**O Estágio 2 deve receber explicitamente o valor do estágio 1.** Os Estágios 1 e 2 são dois
processos independentes, cada um com seu próprio spray, então "escrever a página de credenciais em ambos
os slots" é uma armadilha: lida ingenuamente, produz `(pageA, pageB)`, e porque
`commit_creds` compara **ponteiros**, esse par é divergente mesmo quando ambas as escritas
ocorrem. Isso não é hipotético — é exatamente o que as execuções 3 e 9 fizeram:```
run 9   0x778 shot  write value = 0xffffff88679bade0
        0x780 shot  write value = 0xffffff8785d6ade0     <- a different page
run 3   0x778 shot  write value = 0xffffff8787b5ade0
        0x780 shot  write value = 0xffffff881bad2de0     <- a different page

run_bootA.sh portanto dispara o estágio 2 com V12_W7_VALUE=<valor observado pelo estágio 1> e recusa-se a dispará-lo de todo se esse valor não puder ser recuperado. HOLD deve sobreviver ao estágio 2, ou a página do estágio 1 é liberada e realocada e "o mesmo valor" torna-se um ponteiro pendente. Veja a regra do mesmo valor.

Uma página por boot é reparada. O estágio 3 zera V+8. Com duas páginas diferentes, zerar ambas apagaria o carimbo gid/suid (abaixo) e faria uma divergência parecer concordância, então o runner repara apenas a página que foi realmente instalada e para se os dois valores discordarem.

A página de cred é construída por payload.c: todos os oito campos de id zerados, todos os cinco conjuntos de capacidades completos, e user / user_ns / group_info apontando para root_user / init_user_ns / init_groups. O estágio 3 existe porque o efeito colateral da escrita sempre sobrescreve cred+8 (gid/suid) de qualquer cred que ele instale.

Sobre init_cred — uma dicotomia explícita

Duas seções aqui costumavam se contradizer ("nunca o init_cred global" vs "CONTROL=1 reproduz a célula 2", e a célula 2 é init_cred). Ambas as afirmações são verdadeiras para papéis diferentes:

  • Proibido como alvo. Escrever o ponteiro init_cred faz o efeito colateral corromper init_cred+8 globalmente — init_cred é compartilhado por toda thread do kernel, e Uid: 0 0 4294967176 0 é precisamente essa corrupção. O código recusa esse caminho a menos que V12_ALLOW_INIT_CRED=1 seja definido deliberadamente.
  • Mantido como o único par consistente PROVADO. A cadeia 09-14 que alcançou ksud escreveu um endereço fixo (0xffffff802a7e0be0) em ambos os slots, então real_cred == cred por construção — é por isso que sobreviveu até execve. CONTROL=1 o reproduz. É um controle, não uma configuração para se basear.

vazamento de perf: PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_CLOCK, PERF_SAMPLE_REGS_INTR, exclude_user=1. Aceitar [0xffffff8400000000, 0xffffff90000000), votos ≥ 15%.

A primitiva de escrita, e seu efeito colateral

Baixar ferramenta