Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
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.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
empty_list — empty_list - exploit per p0 issue 1564 (CVE-2018-4243) iOS 11.0 - 11.3.1 kernel r/w | Kitploit
Strumenti/GitHubGitHub/jailbreaks/empty_list
Sicurezza iOSMemory ForensicsAnalisi delle VulnerabilitàExploitPost-ExploitBinary Exploitation
GitHubjailbreaks/empty_list

empty_list

empty_list - exploit per p0 issue 1564 (CVE-2018-4243) iOS 11.0 - 11.3.1 kernel r/w

Vedi Repository
1848 anni 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
Sito web

empty_list - exploit per p0 issue 1564 (CVE-2018-4243) kernel r/w iOS 11.0 - 11.3.1 @i41nbeer

BUG: getvolattrlist accetta un argomento bufferSize controllato dall'utente tramite la syscall fgetattrlist.

Quando si alloca un buffer del kernel per serializzare l'elenco degli attributi, c'è il seguente commento:

/*

  • Allocate a target buffer for attribute results.
  • Note that since we won't ever copy out more than the caller requested,
  • we never need to allocate more than they offer. */ ab.allocated = ulmin(bufferSize, fixedsize + varsize); if (ab.allocated > ATTR_MAX_BUFFER) { error = ENOMEM; VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab.allocated, ATTR_MAX_BUFFER); goto out; } MALLOC(ab.base, char *, ab.allocated, M_TEMP, M_ZERO | M_WAITOK);

Il problema è che il codice non gestisce correttamente il caso in cui la dimensione del buffer fornita dall'utente è inferiore alla dimensione dell'header richiesta. Se passiamo ATTR_CMN_RETURNED_ATTRS, ci imbattiamo nel seguente codice:

/* Return attribute set output if requested. / if (return_valid) { ab.actual.commonattr |= ATTR_CMN_RETURNED_ATTRS; if (pack_invalid) { / Only report the attributes that are valid */ ab.actual.commonattr &= ab.valid.commonattr; ab.actual.volattr &= ab.valid.volattr; } bcopy(&ab.actual, ab.base + sizeof(uint32_t), sizeof (ab.actual)); }

Non c'è alcun controllo che il buffer allocato sia abbastanza grande da contenere almeno questo.

Sfruttamento: Spero di pubblicare un write-up più esteso su questo; queste sono alcune note grezze su come funziona l'exploit:

Il bug offre la possibilità di scrivere 8 byte zero oltre la fine di un'allocazione kalloc.16. Anche se sembra che si possano controllare alcuni bit in quei byte, non sono sicuro che in realtà si possa, quindi mi sono concentrato sullo sfruttamento come se si scrivesse un puntatore NULL oltre la fine.

Questa è una primitiva piuttosto limitata, quindi il primo passo è provare a elencare le possibili cose da fare:

  • puntare a un reference count, cercando di trasformare l'overflow in un bug UaF
  • puntare a un lock, cercando di trasformare l'overflow in un bug di race condition
  • puntare a un puntatore, cercando di far trapelare un reference count
  • puntare a una struttura dati validata in cui 0 è un valore interessante in cui cambiare qualcosa

Alla fine ho scelto la prima opzione. Ci sono quindi altri due requisiti:

  • il target deve avere un reference count nei primi 8 byte
  • il target deve poter essere raggiunto da un overflow da kalloc.16

Ho scelto di puntare alla struct ipc_port, che ha un campo reference count come seconda dword, soddisfacendo così il primo requisito. Tuttavia non viene allocata in kalloc.16; vive invece nella sua zona (ipc_ports).

Questo significa che dobbiamo allineare un blocco della zona kalloc.16 subito prima di uno di ipc_ports, poi fare overflow dall'ultima allocazione kalloc.16 nel blocco kalloc.16 verso la prima in ipc_ports.

Ci sono due trucchi che possiamo usare per semplificare il tutto:

  1. inversione della freelist
  2. allocazioni overflowabili in sicurezza

Inversione della freelist: Le allocazioni di zona provengono prima dalle pagine intermedie (parzialmente piene). Questo significa che se iniziamo a liberare e allocare oggetti k.16 da qualche parte nel mezzo del groom, non verranno riutilizzati finché la pagina intermedia corrente non sarà piena o vuota.

questo rappresenta una sfida perché le freelist delle pagine nuove vengono riempite in modo semi-casuale, così che le loro allocazioni vadano dall'interno verso l'esterno:

| 9 8 6 5 2 1 3 4 7 10 | <-- example "randomized" allocation order from a fresh all-free page

questo significa che le nostre pagine intermedie finali di k.16 e di port saranno più o meno così:

| - - - 5 2 1 3 4 - - | - - - 4 1 2 3 5 - - | kalloc.16 ipc_ports

se usiamo l'overflow per corrompere una voce della freelist, andremo in panic se viene allocata, quindi dobbiamo evitarlo

il trucco è che controllando l'ordine di allocazione e liberazione possiamo invertire le freelist così che le pagine intermedie finali assomiglino più a questo: | 1 4 - - - - - 5 3 2 | 2 5 - - - - - 4 3 1 | kalloc.16 ipc_ports

a questo punto è molto più probabile riuscire a liberare una kalloc.16 e riallocarla per l'overflow, in modo da colpire la prima qword di una ipc_port.

Allocazioni overflowabili in sicurezza: poiché è probabile che ci siano molte allocazioni candidate da cui dovremo fare overflow prima di colpire quella target (che si trova proprio alla fine, appena prima della ipc_port), dobbiamo assicurarci che gli oggetti allocati sulla pagina kalloc.16 siano sicuri da corrompere con un puntatore NULL.

Per questo uso i descrittori ool_port dei messaggi mach, dato che NULL è un valore valido.

Flusso dell'exploit: Eseguiamo il groom per invertire le freelist di kalloc.16 e iniziamo a cercare di fare overflow in una ipc_port.

Conosciamo l'intervallo approssimativo dei nomi dei mach port che contengono il port da corrompere; dopo ogni tentativo di overflow controlliamo ciascuno di questi port per vedere se è stato corrotto. Un effetto collaterale della corruzione riuscita è che il flag io_active del port verrà azzerato. Possiamo rilevarlo senza causare effetti collaterali usando il metodo MIG mach_port_kobject.

Una volta trovato il port corrotto, dobbiamo far sì che venga acquisito e rilasciato un riferimento su di esso; e soprattutto abbiamo bisogno che il percorso di codice che lo fa non controlli il flag io_active. mach_port_set_attributes farà questo per noi.

Ora abbiamo trasformato la scrittura di un puntatore NULL oltre la fine di una kalloc.16 in un mach port dangling :)

Provochiamo una zone gc, con l'obiettivo di far riutilizzare la memoria del port come pagina kalloc.4096. Per prima cosa la facciamo riutilizzare come descrittore ool_ports, in cui il campo ip_context si sovrappone a un send right che inviamo a noi stessi verso un canary port. Questo ci permette di conoscere l'indirizzo approssimativo dei nostri oggetti nel kernel. Poi sostituiamo il descrittore ool_desc con un pipe buffer e, con un po' di pazienza, riusciamo a capire dove si trova in memoria il mach port dangling.

Creiamo un fake kernel task port lì dentro e poi ripuliamo.

Affidabilità: L'exploit funziona davvero, che era il mio obiettivo :) L'affidabilità è circa del 30%, forse; tutto dipende da quanto velocemente riesci a fare l'overflow iniziale e il loop di test. Se qualcos'altro interviene e alloca o libera in kalloc.16, aumenti la probabilità di corrompere una voce della freelist o qualcos'altro e di andare in panic.

Sono sicuro che l'exploit possa essere reso più affidabile; l'ho portato solo al punto in cui ho dimostrato che questo bug è sfruttabile. Se vuoi usare questo come punto di partenza e dimostrare come migliorarne l'affidabilità, mi piacerebbe leggere un blog post! Immagino che comporterebbe monitorare davvero le allocazioni kalloc.16 e capire quali sono i casi di fallimento e come prevenirli.

I tassi di successo sembrano essere più alti quando il dispositivo è stato riavviato e lasciato inattivo per un po'.

Pulizia: Se l'exploit funziona, dovrebbe pulire da sé e non mandare in panic il dispositivo. Il fake kernel task port rimarrà vivo.

Usa le funzioni in kmem.h per leggere e scrivere la memoria del kernel. Persisti un send right per tfp0 lì dentro se vuoi mantenere l'accesso alla memoria del kernel dopo l'uscita di questo processo.

Ho testato su: iPod Touch 6G, iPhone 6S, iPhone SE, iPhone 7, iPhone 8 Dovrebbe funzionare da iOS 11 a iOS 11.3.1

Scarica lo strumento