Skip to content
KitploitKITPLOIT
StrumentiExploitsBlog
Log in
Invia
StrumentiExploitsBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

FeedContattoPrivacy© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
ghostlock-pfem10 — GhostLock (CVE-2026-43499) per OPPO Find X5 Pro (PFEM10) — reverse engineering del watchdog OPlus e del rilevatore di heap-spray | Kitploit
Strumenti/GitHubGitHub/imeiplus/ghostlock-pfem10
Sicurezza AndroidEscalation di PrivilegiMemory ForensicsAnalisi delle VulnerabilitàExploitReverse EngineeringSicurezza MobileSviluppo PayloadBinary Exploitation
GitHubimeiplus/ghostlock-pfem10

ghostlock-pfem10

GhostLock (CVE-2026-43499) per OPPO Find X5 Pro (PFEM10) — reverse engineering del watchdog OPlus e del rilevatore di heap-spray

4522 giorni faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi
Vedi Repository

GhostLock — OPPO Find X5 Pro (PFEM10)

English · 中文

build

Port di GhostLock (CVE-2026-43499) per OPPO Find X5 Pro su ColorOS 16. Raggiunge un processo figlio con uid=0 e un kernelsu.ko caricato; il processo root viene intercettato.

Vulnerabilità

CVE-2026-43499 — futex PI use-after-free. remove_waiter() azzera current->pi_blocked_on quando current è il requeuer, sul percorso di rollback -EDEADLK di rt_mutex_start_proxy_lock().

remove_waiter @ 0xffffffc0081ed254 — forma pre-fix.

Dispositivo

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

Stato

Fase
Trigger compact waiter (CMP_REQUEUE_PI → EDEADLK)funziona
Leak di task_struct (perf)funziona
Scrittura PI (8 byte; valore = 0 o un indirizzo kernel valido)funziona
task+0x778 oppure task+0x780 da solo → Uid=rootfunziona — ma un atterraggio su un singolo campo lascia il task divergente, e questo è un latente hard BUG_ON. Vedi il rischio di divergenza
Entrambi i campi scritti con UN SOLO valore (una coppia coerente)❌ mai prodotto con una pagina sprayata. Osservato solo con l'alias globale init_cred (09-14, CONTROL=1). Il runner ora lo impone (SAME_VALUE=1); non eseguito sul dispositivo
Laundering delle credenziali (setresgid + setresuid)implementato dietro V12_LAUNDER=1; non eseguito sul dispositivo
kernelsu.ko caricatofunziona
Il processo root sopravvive⚠ non stabilito — vedi sotto
Meccanismo di reboot❌ non stabilito. Un candidato (la divergenza) è ora escluso; vedi sotto
probe_state come criterio di atterraggio❌ errato — non usare. Tre controesempi; vedi la tabella sotto
Canale di panic pstore/ramoops⚠ lo strumento esiste; canale mai validato (nessun null test ancora)
"La vittima gira in puro userspace"⚠ nessuna lettura ancora — uid.stream ora registra utime/stime/nvcsw così può essere verificato
doppia scrittura single-pass lato pi⚠ non stabilito; pi.pc/pi.left sono hard-coded a 0 in fdset_map.h
Path A (UMH / modprobe_path)STATIC_USERMODEHELPER_PATH=""

Su "il processo root sopravvive": le esecuzioni in evidence/kill.log raggiungono uid=0 e caricano kernelsu.ko, e nell'esecuzione che effettivamente lo ha interrogato il processo del manager KernelSU è sopravvissuto 120 s con kernelsu ancora Live in /proc/modules. In un'esecuzione successiva la stessa catena ha reso irraggiungibili i servizi del framework Android (Can't find service: package/power/input/phone/wifi) mentre il modulo era ancora Live. Nessuna riga kernel [ROOTCHECK-*] e nessun payload $$sys_call_number@@ è mai stato catturato, quindi la causa dello stato dell'esecuzione successiva non è attribuita. Vedi evidence/notes.md §2.3, §2.4 e §7.

Offset

task_struct

CampoOffset
real_cred / cred0x778 / 0x780
syscallno in cache0xdf8
uid / euid / gid / egid in 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

Flusso di 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

**Lo stage 2 deve ricevere esplicitamente il valore dello stage 1.** Gli stage 1 e 2 sono due processi indipendenti, ciascuno con il proprio spray, quindi "scrivi la pagina delle credenziali in entrambi gli slot" è una trappola: letto ingenuamente produce `(pageA, pageB)`, e poiché `commit_creds` confronta i **puntatori**, quella coppia è divergente anche quando entrambe le scritture vanno a buon fine. Questo non è ipotetico — è esattamente ciò che hanno fatto i run 3 e 9:```
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 attiva quindi lo stage 2 con V12_W7_VALUE=<valore osservato dallo stage 1> e rifiuta di attivarlo del tutto se quel valore non può essere recuperato. HOLD deve sopravvivere allo stage 2, altrimenti la pagina dello stage 1 viene liberata e riallocata e "lo stesso valore" diventa un puntatore pendente. Vedi la regola dello stesso valore.

Una pagina per boot viene riparata. Lo stage 3 azzera V+8. Con due pagine diverse, azzerare entrambe cancellerebbe il timbro gid/suid (sotto) e farebbe sembrare una divergenza un accordo, quindi il runner ripara solo la pagina che è stata effettivamente installata e si ferma se i due valori non concordano.

La pagina cred è costruita da payload.c: tutti gli otto campi id a zero, tutti e cinque i set di capability pieni, e user / user_ns / group_info puntati a root_user / init_user_ns / init_groups. Lo stage 3 esiste perché l'effetto collaterale della scrittura sovrascrive sempre cred+8 (gid/suid) di qualunque cred venga installato.

Su init_cred — una dicotomia esplicita

Due sezioni qui si contraddicevano a vicenda ("mai il globale init_cred" contro "CONTROL=1 riproduce la cella 2", e la cella 2 è init_cred). Entrambe le affermazioni sono vere per ruoli diversi:

  • Vietato come target. Scrivere il puntatore init_cred fa sì che l'effetto collaterale corrompa init_cred+8 globalmente — init_cred è condiviso da ogni thread del kernel, e Uid: 0 0 4294967176 0 è precisamente quella corruzione. Il codice rifiuta questo percorso a meno che V12_ALLOW_INIT_CRED=1 non sia impostato deliberatamente.
  • Mantenuto come l'unica coppia PROVATA coerente. La catena 09-14 che ha raggiunto ksud ha scritto un indirizzo fisso (0xffffff802a7e0be0) in entrambi gli slot, quindi real_cred == cred per costruzione — ecco perché è sopravvissuta fino a execve. CONTROL=1 la riproduce. È un controllo, non una configurazione su cui costruire.

perf leak: PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_CLOCK, PERF_SAMPLE_REGS_INTR, exclude_user=1. Accetta [0xffffff8400000000, 0xffffff90000000), voti ≥ 15%.

La primitiva di scrittura, e il suo effetto collaterale

Scarica lo strumento