Home News Il team Fail0verflow rilascia pubblicamente il kernel exploit per il firmware 4.05...

Il team Fail0verflow rilascia pubblicamente il kernel exploit per il firmware 4.05 della Playstation 4

264
4

Il team Fail0verflow ha pubblicato uno dei più interessanti articoli sul kernel exploit namedobj per Playstation 4, la vulnerabilità scovata dalla Chaitin Tech è stato corretto sul firmware 4.06.

Sono passati dieci mesi dall’ultimo articolo pubblicato dal team, e oggi la squadra intende spiegare le procedure e i processi adottati per implementare una chiamata di sistema kexec() per il kernel PS4 Orbis (derivato FreeBSD) progettato per poter avviare un kernel Linux direttamente da FreeBSD.

Come spiegato in precedenza, siamo stati in grado di ottenere un dump del kernel firmware 1.04 su Playstation 4 tramite un attacco PCIe man-in-the-middle.

Come tutti i kernel FreeBSD, questa immagine includeva “export symbols” – simboli necessari per eseguire processi di inizializzazione del kernel e dei moduli.

Tuttavia, il kernel ps4 1.01 includeva anche i simboli ELF completi (ovviamente un controllo visto che sono stati rimossi nelle versioni successive del firmware).

Questa vigilanza è stata vantaggiosa per il processo di ingegneria inversa, anche se, naturalmente, non è un vero requisito preliminare. Infatti abbiamo iniziato ad esplorare il kernel esaminando i metadati incorporati sotto forma di tabella del gestore syscall – concentrandosi sulle voci specifiche di ps4.

Dopo un certo recupero di strutture, abbiamo scoperto che una grande parte delle syscall specifiche su PS4 è poco più che i wrapper di ciò che è essenzialmente un’API della tabella hash. L’API contiene la seguente interfaccia:

enum IDT_TYPE : u16 {
IDT_TYPE_EPORT = 0x30,
IDT_TYPE_SBLOCK = 0x40,
IDT_TYPE_EVF = 0x110,
IDT_TYPE_OSEM = 0x120,
IDT_TYPE_BUDGET = 0x2000,
IDT_TYPE_NAMEDOBJ_DBG = 0x5000,
};
struct id_entry {
struct sx *sxlock;
char *name;
void *ptr;
u64 tid;
IDT_TYPE kind;
u16 is_open;
u16 handle;
u16 state;
};
struct idt_bucket {
struct id_entry entries[128];
};
struct id_table {
struct idt_bucket[64];
struct mtx mutex;
u32 num_buckets;
u32 cur_handle;
u32 max_entries;
};
id_table *id_table_create(int max_entries);
void id_table_destroy(id_table *idt);
int id_alloc(id_table *idt, id_entry **ide);
void id_set(id_entry *ide, IDT_TYPE kind, void *data, char *name);
void id_set_open(id_entry *ide, IDT_TYPE kind, void *data, char *name);
int id_is_opened(id_entry *ide);
void id_free(id_table *idt, int handle, id_entry *ide);
void id_unlock(id_entry *ide);
void *id_rlock(id_table *idt, signed int index, IDT_TYPE kind, id_entry **ide);
void *id_rlock_name(id_table *idt, IDT_TYPE kind, char *name, id_entry *

Ogni oggetto di processo nel kernel contiene un proprio oggetto “idt” (ID Table). Come si può dedurre dallo snippet sopra, la tabella hash essenzialmente memorizza semplicemente i puntatori in un blob di dati opachi, insieme a un dato kind e name. Le entrate possono essere accessibili (e quindi “bloccate”) con l’intento di lettura o di scrittura.

Si noti che IDT_TYPE non è un bitfield costituito da solo potenze uniche di 2. Ciò significa che se possiamo controllare il kind di id_entry, possiamo provocare una certa confusione (si presume che possiamo controllare il name ). Certamente, il kind può essere impostato da usermode tramite il namedobj_create syscall:

struct namedobj_usr_t {
char *name;
void *object;
u64 field_10;
};
int sys_namedobj_create(struct thread *td, void *args) {
MACRO_EPERM rv; // ebx
int kind; // er14
id_table *idt; // r12
char *name; // r13
namedobj_usr_t *no; // rbx
int handle; // er15
id_entry *ide; // [rsp+8h] [rbp-38h]
__int64 v10; // [rsp+10h] [rbp-30h]

rv = EINVAL;
if ( *(_QWORD *)args ) {
// Note this is almost completely usermode-controlled!
kind = *((_DWORD *)args + 4) | 0x1000;
idt = td->td_proc->sce_idt;
name = (char *)malloc(0x20uLL, &M_NAME, 2);
rv = copyinstr(*(const void **)args, name, 0x20uLL, 0LL);
if ( rv ) {
free(name, &M_NAME);
} else {
no = (namedobj_usr_t *)malloc(0x18uLL, &M_NAME, 2);
no->name = name;
no->object = *((_QWORD *)args + 1);
handle = id_alloc(idt, &ide);
if ( handle == -1 ) {
free(name, &M_NAME);
free(no, &M_NAME);
rv = EAGAIN;
} else {
id_set(ide, (IDT_TYPE)kind, no, name);
id_unlock(ide);
td->td_retval[0] = handle;

Ora dobbiamo trovare un modo per accedere al kernel e utilizzare impropriamente un oggetto dal nostro processo (cioè il processo del browser) idt che ha una kind di 0x1000 e qualsiasi altro numero di bit impostato. Questo è stato trovato nel seguente codice:

struct namedobj_dbg_t {
u32 field_0;
u32 _pad_4; // compiler-inserted alignment
u64 field_8;
u64 field_10;
u64 field_18;
u64 field_20;
};
int namedobj_create_ex(id_table *idt, char *name, u32 a3, u64 a4, u64 a5, u64 a6, u64 a7) {
namedobj_dbg_t *no_exists; // rax
int rv; // er13
id_entry *ide_existing; // [rsp+20h] [rbp-40h]

rv = EAGAIN;
no_exists = (namedobj_dbg_t *)id_rlock_name(idt, IDT_TYPE_NAMEDOBJ_DBG, name, &ide_existing);
if ( no_exists )
{
no_exists->field_0 = a3;
no_exists->field_8 = a4;
no_exists->field_10 = a5;
no_exists->field_18 = a6;
no_exists->field_20 = a7;
id_unlock(ide_existing);
rv = 0;
}
// ... unrelated code removed
return rv;
}

… accessibile dalle syscall mdbg_service:

struct mdbg_service_arg1 {
u32 field_0;
u64 field_4;
u64 field_8;
u64 field_10;
u64 field_18;
u64 field_20;
char name[32];
};
int sys_mdbg_service(struct thread *td, void *args) {
signed int rv; // ebx
void *uptr; // r14
mdbg_service_arg1 cmd_1; // [rsp+18h] [rbp-68h]

rv = 78;
uptr = (void *)*((_QWORD *)args + 1);
switch ( (unsigned __int64)*(unsigned int *)args ) {
// ... unrelated code removed
case 1uLL:
rv = copyin(uptr, &cmd_1, 0x48uLL);
if ( rv )
break;
cmd_1.name[31] = 0;
rv = namedobj_create_ex(
td->td_proc->sce_idt,
cmd_1.name,
cmd_1.field_4,
cmd_1.field_8,
cmd_1.field_10,
cmd_1.field_18,
cmd_1.field_20);
break;
// ... unrelated code removed
}
return rv;
}

L’articolo non include alcun collegamento al progetto ultimato, e si riferisce principalmente a sviluppatori e hacker di talento. Se siete interessati al resto dell’articolo seguite il collegamento alla pagina ufficiale del team Fail0verflow

4 Commenti

  1. scusa allora perche scrivi rilasciato l’exploit? se non è vero in parte….non ho capito se il codice è stato rilasciato tutto oppure no?

    • Molti illudevano al rilascio dell’exploit vero e proprio, non solo noi, appare comunque interessante anche se si tratta solo di documentazione, potrebbe incentivare gran parte degli sviluppatori che potrebbero pubblicare l’exploit grazie al codice rilasciato oggi

LASCIA UN COMMENTO

Per favore inserisci il tuo commento!
Per favore inserisci il tuo nome qui

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.