
Exploit proof-of-concept per CVE-2023-41993, una confusione di tipo JIT di WebKit in Safari. Fornisce primitive addrof/fakeobj tramite manipolazione dell'heap e confusione GetterSetter, consentendo lettura/scrittura arbitraria nel processo WebContent.
Exploit PoC per CVE-2023-41993. È scritto solo fino a addrof/fakeobj. L'affidabilità non è eccezionale. Se vuoi migliorarlo, prova a fare spray degli structure ID.
https://po6ix.github.io/POC-for-CVE-2023-41993/pwn.html
Ho deciso di ospitarlo su GitHub Pages dopo molteplici richieste.
Auguratemi fortuna che GitHub non mi blocchi...
È perché il valore del fattore definito nella funzione pwn non è corretto per il tuo dispositivo.
In tal caso, l'ho fatto in modo che usi un valore casuale tra 87 e 1088.
Quindi puoi trovare il valore del fattore corretto semplicemente ricaricando qualche volta.
Probabilmente dovrebbe funzionare entro 100 tentativi.
Sarebbe anche gradito se potessi inviarmi le informazioni mostrate dal caso di successo.
Questo ti fornisce una primitiva di lettura/scrittura sul processo webcontent di Safari.
Ma per renderlo effettivamente utile, dovrai concatenarlo con altri componenti.
Potresti desiderare un writeup dettagliato per questo. ma sfortunatamente non ho tempo per scriverlo. Quindi scrivo alcuni appunti qui così puoi capire come funziona.
Se guardi il commit, riguarda la modifica per HeapLocation.
È stato aggiunto un nuovo fattore per sapere se i nodi sono uguali o meno.
Ci dice che nodi come GetByOffset, MultiGetByOffset potrebbero essere confusi.
Ma in realtà riguarda solo l'offset.
Diciamo che ha due nodi GetByOffset con offset diversi.
Uno di questi sarà soggetto a CSE e il rimanente verrà usato invece.
Quindi è fondamentalmente una confusione di offset ma non ti dà accesso a un offset arbitrario.
perché per fare CSE su tali tipi di nodi devono essere sollevati da LICMPhase.
Per i tipi di nodi che eseguono operazioni di scrittura non è consentito il sollevamento in questa fase.
Quindi la stessa confusione non si verifica per i nodi PutByOffset, MultiPutByOffset.
Inoltre, quando GetByOffset viene sollevato, la funzione safeToExecute viene chiamata per verificare che il nodo sia lecito da eseguire e permette di accedere solo all'offset minore della capacità di storage (inline/ool).
Quindi l'idea per sfruttare questo era GetterSetter.
Se chiami Object.__defineGetter__ per definire una proprietà, viene creato un oggetto GetterSetter ma memorizzato nello storage delle proprietà e non è accessibile normalmente.
Ma puoi con questa manipolazione dell'offset che hai.
Poi chiami la funzione Object per innescare una type confusion.
JSObject* JSCell::toObjectSlow(JSGlobalObject* globalObject) const
{
Integrity::auditStructureID(structureID());
ASSERT(!isObject());
if (isString())
return static_cast<const JSString*>(this)->toObject(globalObject);
if (isHeapBigInt())
return static_cast<const JSBigInt*>(this)->toObject(globalObject);
ASSERT(isSymbol());
return static_cast<const Symbol*>(this)->toObject(globalObject);
}
Creerà un SymbolObject che ha il GetterSetter come valore interno. E questo è errato, perché questo valore interno di SymbolObject dovrebbe essere un'istanza di Symbol, non GetterSetter.
let getterSetter = jitme(1);
let symbolObject = Object(getterSetter);
symbolObject.description; // call the getter
String Symbol::description() const
{
auto& uid = m_privateName.uid();
return uid.isNullSymbol() ? String() : uid;
}
Poi quando chiami il getter description, restituirà un'istanza di String. Questa è una confusion di tipo tra Symbol.m_privateName e GetterSetter.m_getter. Ogni volta che chiami questo getter, incrementerà il campo del contatore di riferimenti di m_privateName.m_uid che si trova all'offset 0x0. Questo è molto utile, perché questo offset è dove si trova lo structure ID della funzione getter. Chiamando questa funzione alcune volte, puoi cambiare lo structure ID dell'istanza JSFunction. Ho preparato un altro tipo che ha molte proprietà. Poi se sincronizzi lo structure ID per renderlo uguale a quello, puoi fare scrittura oob nello storage delle proprietà. Questo dà direttamente la primitiva addrof/fakeobj.