Anatomía de un exploit kernel no publicado - PSNeo.com
>

Anatomía de un exploit kernel no publicado

¿Cuantas veces habéis oído «¡los exploit kernel son difíciles de encontrar, los desarrolladores simplemente no pueden publicarlos!»? Bueno, eso no es del todo cierto, y para probarlo, estoy publicando un bug muy guay que se encontró algunos años atras.

Por supuesto, este exploit esta parcheado ahora, no tendría sentido malgastar un exploit kernel perfectamente funcional ahora mismo (incluso cuando aún hay algunos…), pero creo que estaría bien enseñaros este.

Pero primero, un poco de historia.

En 2011, mientras investigaba el registry.prx, noté que Sony había hecho un error mudo (si, otro mas…), y empecé a trabajar con some1 a exploitear esto. Nos tomó solo unos pocos días para tener un POC ejecutándose, probablemente es uno de los exploits mas sencillos nunca hechos, un simple, mudo, desbordamiento de memoria.

Y ahora, el exploit.

Básicamente, exploiteamos una vulnerabilidad en sceRegRemoveCategory. Básicamente, esta syscall elimina una categoría del registro del sistema (obviamente). Toma dos argumentos, un REGHANDLE y una cadena. El REGHANDLE es un valor dado por sceRegOpenRegistry cuando abrimos un registro válido, totalmente legítimo, pero echemosle un vistazo a esa cadena…

kernel

La cadena es tan solo el nombre de la categoría que quieres eliminar. En el registro del sistema de PSP, todos los nombres empiezan con un «/», y sceRegRemoveCategory comprueba únicamente eso. El primer carácter de la cadena.

Realmente, también comprueba si la cadena que está se encuentra en el espacio kernel, pero no nos preocupamos por eso en este caso.

RemoveCategory aloja 0x1B (27) bytes en la pila, y entonces llama una subrutina que básicamente copia nuestra cadena en ese espacio… ¡Pero no comprueba la longitud de nuestra cadena!

¿Veis el problema aquí? Podemos desbordar fácilmente ese buffer dando una cadena que se parezca a esto `/<27+ caracteres aleatorios>´. La dirección devuelta está almacenada 0x54 (90) bytes después en la pila, así que podemos simplemente reescribirlo y esperar a sceRegRemoveCategory a que lo regrese, incluso con un error, no nos importa.

tl;dr, aquí hay un retazo de código, callback_addr es la dirección de la función que quieres ejecutar con permisos 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); //;)
 }

Como ya he dicho, esto está parcheado hoy día (creo que fue parcheado en la última actualización de PSV, no estoy seguro), pero esto no significa que no puedas crear un kernel exploit, quizá en otro firmware mas viejo, como ejercicio.

Estoy honestamente sorprendido de que le tomara tanto tiempo a Sony para parchear esto, especialmente cuando hicieron el mismo error en loadexec, atras en 2.50 (iirc).

Esto muestra cómo de fácil es romper la seguridad del pspemu, quizá es hora de poner nuestros conocimientos en algo mas interesante

Fuente: wololo

 


Publicado por para PSNeo.com el a las 15:58

Comentarios