La console PlayStation 5 riceve la sua prima documentazione per quanto riguarda l’userland exploit scovato sul firmware 4.03, come già anticipatoci da notzecoxao alcuni giorni fa.
La console Sony è stata rilasciata il 12 novembre del 2020, sebbene presenti un’architettura simile a quello della console PlayStation 4, utilizza un modello di sicurezza notevolmente superiore, sia sul fronte kernel, che sul fronte userland.
We've released a small writeup and some code for userland exec on PS5.
DNS redirection to https works.https://t.co/mgmD6JZgPo— Z (@Znullptr) January 27, 2022
Di seguito vengono riportate alcune informazioni di sistema chiave sul software di sistema e alcune modifiche che sono state apportate rispetto all’ultima generazione.
- Utilizza FreeBSD 11.
- Nessun accesso allo sviluppo (ovvero non è possibile eseguire codice non firmato senza exploit).
- Ad oggi non ci sono exploit pubblici.
- Aggiunte mitigazioni in kernel e userland.
- Aggiunto hypervisor che gestisce la sicurezza e i contenitori delle app.
Panoramica Userland
Project Zero aveva pubblicato un primo rapporto a settembre per quello che credevano essere CVE-2021-30858
, questo in realtà si è rivelato sbagliato poiché stavano descrivevano CVE-2021-30889
.
Sleirsgoevy intanto ha scritto un proof of concept per console PlayStation 4, modificato successivamente per ottenere l’esecuzione ROP sul firmware 9.00 per l’exploit del kernel.
La documentazione pubblicata da ChendoChap non descrive la vulnerabilità, ma si concentra sull’acquisizione delle primitive di lettura/scrittura arbitraria e leakobj()
/fakeobj()
fornite dall’exploit per ottenere l’esecuzione del codice sulla PlayStation 5.
A quanto pare i firmware inferiori alla versione 2.00 non sembrano essere vulnerabili, probabilmente perché il relativo codice FontFace
non è presente nelle build precedenti del WebKit (questo vale anche per la console PS4, poiché i firmware inferiori alla 9.00 non possono essere sfruttati con questo bug).
Il browser web della console PlayStation 5 è risultato invece vulnerabile sul firmware 4.03, anche se sfortunatamente la strategia di exploit utilizzata su PS4 non può essere utilizzata su PS5 a causa del CFI basato sul clang.
Su console PS4, viene fatto uso delle primitive leakobj()
e di scrittura arbitraria per perdere una vtable di HTMLTextArea e distruggere una delle varie chiamate virtuali per l’esecuzione del codice. Su console PS5, queste chiamate virtuali vengono invece verificate.
Le chiamate virtuali ora hanno un codice simile a questo, in cui viene imposto il suo indirizzo:
Mitigazioni
Nome | Kernel | User | Descrizione |
SMEP: Supervisor Mode Execution Prevention | x | SMEP impedirà alla modalità supervisor di eseguire il codice user-space. | |
SMAP: Supervisor Mode Access Prevention | x | Integra la prevenzione dell'esecuzione in modalità supervisor (SMEP), estende la protezione a letture e scritture. | |
XOM: eXecute Only Memory (R^X) | x | x | Impedisce la lettura di qualsiasi pagina di memoria contrassegnata come eseguibile. |
Clang-CFI: Control Flow Integrity | x | x | Protegge dal dirottamento del flusso di controllo del bordo di inoltro (chiamate virtuali, ecc..). |
Flag di integrità del flusso di controllo di Clang
-fsanitize=cfi- | Descrizione |
cast-strict | Consente severi controlli sul lancio. |
derived-cast | Cast da base a derivato al tipo dinamico sbagliato. |
unrelated-cast | Trasmetti da void* o da un altro tipo non correlato al tipo dinamico sbagliato. |
nvcall | Chiamata non virtuale tramite un oggetto il cui vptr è del tipo dinamico errato. |
vcal | Chiamata virtuale tramite un oggetto il cui vptr è del tipo dinamico errato. |
icall | Chiamata indiretta di una funzione con tipo dinamico errato. |
mfcall | Chiamata indiretta tramite un puntatore a una funzione membro con tipo dinamico errato. |
Implementazione dell’exploit nel WebKit
Panoramica
Era dunque necessaria un’alternativa per ottenere l’esecuzione del codice nel WebKit. Per fortuna, il CFI della PS5 è solo forward-edge e non utilizza lo shadow stack, quindi gli attacchi all’indietro (come attaccare gli indirizzi di ritorno sullo stack) sono un gioco leale.
Javascript fornisce una funzionalità alquanto interessante chiamata Web Workers. Questi lavoratori sono al loro interno semplici thread che eseguono javascript in un ambiente isolato.
Questi sono stati utili per lo sfruttamento, poiché avevano uno stack affidabile che potevamo perdere e forniscono un thread per ruotare sulla nostra catena ROP.
Perdita di una stack di lavoratori
La libreria libkernel utilizzata dal WebKit (e da molte altre applicazioni) mantiene un elenco di thread per quel processo e include informazioni come l’indirizzo e la dimensione dello stack. Iterando questo elenco usando la lettura/scrittura arbitraria, possiamo trovare l’indirizzo dello stack di un lavoratore.
function find_worker() { const PTHREAD_NEXT_THREAD_OFFSET = 0x38; const PTHREAD_STACK_ADDR_OFFSET = 0xA8; const PTHREAD_STACK_SIZE_OFFSET = 0xB0; for (let thread = p.read8(libKernelBase.add32(OFFSET_lk__thread_list)); thread.low != 0x0 && thread.hi != 0x0; thread = p.read8(thread.add32(PTHREAD_NEXT_THREAD_OFFSET))) { let stack = p.read8(thread.add32(PTHREAD_STACK_ADDR_OFFSET)); let stacksz = p.read8(thread.add32(PTHREAD_STACK_SIZE_OFFSET)); if (stacksz.low == 0x80000) { return stack; } } alert("failed to find worker."); }
Avvio di una catena ROP
Una volta ottenuto uno stack di lavoro, possiamo distruggere un indirizzo di ritorno noto nello stack per impilare il pivot e far funzionare il ROP. Poiché lo stack è deterministico, possiamo configurare un lavoratore fittizio con un gestore postMessage
e sovrascrivere l’indirizzo di ritorno in stack+0x7FB88
.
const OFFSET_WORKER_STACK_OFFSET = set_offset_for_platform(0x0007FB88, 0x0007FB28); // ... let return_address_ptr = worker_stack.add32(OFFSET_WORKER_STACK_OFFSET); let original_return_address = p.read8(return_address_ptr); let stack_pointer_ptr = return_address_ptr.add32(0x8); // ... async function launch_chain(chain) { // ... //overwrite return address p.write8(return_address_ptr, gadgets["pop rsp"]); p.write8(stack_pointer_ptr, chain.stack_entry_point); let p1 = await new Promise((resolve) => { const channel = new MessageChannel(); channel.port1.onmessage = () => { channel.port1.close(); resolve(1); } worker.postMessage(0, [channel.port2]); }); // ... }
Conclusione
Ottenere l’esecuzione del codice userland su PS5 è più complicato che su PS4, ma è comunque possibile. Naturalmente, questo è stato facilitato dal fatto che abbiamo binari* e quindi l’accesso ai gadget ROP.
In caso contrario, ottenere l’esecuzione del codice sarebbe stato molto più difficile a causa di XOM. Questo è un exploit userland. Attaccare il kernel è molto più difficile a causa delle mitigazioni di cui sopra e viene lasciato per un futuro riassunto.
Crediti
ChendoChap && Znullptr
Grazie
- Anonymous*
- Specter
- sleirsgoevy
- Tutti quelli che hanno donato
[stextbox id=’info’]Nota: Vuoi rimanere sempre aggiornato con le ultime notizie? Unisciti al server Discord di SCE Party.[/stextbox]
Fonte: github.com
Quindi ad oghi per noi comuni mortali,non serve a nulla.
Anche perche’ prima bisogna procurarsi una PS5.