wiibrew escribió:The bug here is that the hash can (and very likely does) contain a NULL byte, (chr)0 that is. To quote from the first google hit for strncmp:
"Compares up to num characters of the C string str1 to those of the C string str2. This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ, until a terminating null-character is reached, or until num characters match in both strings, whichever happens first."
This last part means that if it finds a NULL byte, it stops comparing, even if there is more data after the NULL.
This reduces the effective length of the hash to the number of bytes before the NULL byte. This means that the difficulty of finding a hash collision is reduced from 2^(HASHLENGTH*8) to 2^(bytes before the null). That is a big change if the NULL is early in the hash. Assuming the NULL is at the 5th byte, that means that there is a one in 2^(4*8) chance that the hash matches, or one in 4 294 967 296, fairly computable within a reasonable time frame on a current computer that can try a few million hash inputs each sec.
El bug es que el hash puede contener un byte nulo (NULL), 0. La cita de el primer resultado de Google para "strncmp":
"Compara hasta num caracteres de la cadena str1 a estos en la cadena str2. La función empieza a comparar el primer carácter de cada cadena. Si son iguales, continua con los pares de caracteres siguientes, hasta que se llegue a un carácter nulo o hasta que se llega a num caracteres a ambas cadenas, lo que ocurra primero"
Esta ultima parte significa que si encuentra un carácter nulo, para de leer, aunque haya más información detrás del carácter nulo.
Esto reduce la longitud efectiva del hash a el numero de bytes antes del byte nulo. Esto significa que la dificultad de encontrar una colisión de hash se reduce de 2^(LONGITUDDELHASH*8) a 2^(bytes antes del carácter nulo). Esto es un gran cambio si el caracter nulo se encuentra en el hash. Suponiendo que el carácter nulo es el quinto byte, esto significa que hay una posibilidad entre 2^(4*8) de que el hash coincida, o una posibilidad entre 4.294.967.296, bastante computable en un tiempo razonable en un ordenador actual que puede probar unos pocos millones de hash cada segundo.
GameZelda escribió:Supongo que debieron utilizar el método típico del "funciona? pues ya está" y listo
pepone1234 escribió:A ver si lo he entendido bien. Lo que hace este método es comparar dos cadenas para ver si son iguales. Si las dos son iguales, salta y si en la primera hay un byte nulo no continúa la comprobación, con lo que las posibilidades de éxito aumentan a medida que el byte nulo se encuentre más cerca del principio debido a las características de los números exponenciales y un poco de probabilidad ¿no es así?
GameZelda escribió:Exacto (excepto que el byte nulo puede estar en cualquiera de las dos cadenas y no solo en la primera)
(Que no son cadenas, este es el problema, que son datos binarios y usaron funciones para cadenas)
xt5 escribió:edit
no es que pueda estar en cualquiera de las dos, DEBE estar en las dos cadenas y en la misma posicion.
xt5 escribió:http://debugmo.de/?p=61
edit
no es que pueda estar en cualquiera de las dos, DEBE estar en las dos cadenas y en la misma posicion.
wah_wah_69 escribió:Es más la manpage de mi maquina no dice nada de "Bytes following a null byte are not compared." que si se menciona en otros sitios que he leido.
Ni en la referencia de the Open group ni en el manual de la glibc se menciona nada.
[font=verdana, arial][size=90] #include <stdio.h>
int main(){
printf("resultao: %d", strcmp("gate\0te","gate\0miabuela"));
return 0;
}[/size][/font]
#include <stdio.h>
int main(){
char *cadena1 = "gate\0te";
char *cadena2 = "gate\0la";
printf("resultao strcmp: %d
", strcmp(cadena1, cadena2));
printf("resultao memcmp: %d
", memcmp(cadena1, cadena2, 7));
system("PAUSE");
return 0;
}
wah_wah_69 escribió:
GameZelda se refiere al codigo de la implementacion de strcmp y tu te refieres a la llamada que hicieron en nintendo.
De todas formas si se hubiera comprobado correctamente el valor de entrada en strcmp no hubiera dado un resultado erroneo.
strcmp("gatete",NULL);
Debería devolver un entero mayor que 0 ,"gatete" es mayor que,por lo que no serian considerados iguales.
Igual se trata de un error en la iniciacion de una variable de resultado
Edit:
Acabo de probar un c un simple código:
#include
int main(){
printf("resultao: d%", strcmp("gatete",NULL));
return 0;
}
Y recibo un segfault,no sabía que era responsabilidad del programador comprobar que no se le pasara un null como argumento.
Es más la manpage de mi maquina no dice nada de "Bytes following a null byte are not compared." que si se menciona en otros sitios que he leido.
Ni en la referencia de the Open group ni en el manual de la glibc se menciona nada.
¿Y esto por que es asi por ahorrarse una comparación?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char contenido1[10] = { 0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0xAD, 0xCD, 0x12, 0x23, 0x45 };
char contenido2[10] = { 0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x99, 0xF1, 0x98, 0x12, 0x09 };
if (strncmp(contenido1, contenido2, 10) == 0)
{
printf("Cadenas: Valido!\n");
}
else
{
printf("Cadenas: Invalido!\n");
}
if (memcmp(contenido1, contenido2, 10) == 0)
{
printf("Memoria: Valido!\n");
}
else
{
printf("Memoria: Invalido!\n");
}
system("PAUSE");
return 0;
}
Cadenas: Valido!
Memoria: Invalido!
torito21 escribió:Basicamente el NULL o 0x00 en una cadena indica el fin de cadena, por lo tanto, en una funcion de comparacion de cadenas, es normal que se pare en cuanto se encuentre un NULL.
Prueba:[font=verdana, arial][size=90] #include <stdio.h>
int main(){
printf("resultao: %d", strcmp("gate\0te","gate\0miabuela"));
return 0;
}[/size][/font]
Deberia imprimir "resultao: 0" (iguales)
Saludos.
[font=verdana, arial][size=90] strcmp("gatete",NULL);[/size][/font]
torito21 escribió:Hombre, esuqe haciendo:[font=verdana, arial][size=90] strcmp("gatete",NULL);[/size][/font]
Le estas diciendo que compare la cadena "gatete" con la cadena que comienza en la direccion de memoria 0 (NULL == (void *)0), entonces da la excepcion SIGSEGV porque esa direccion esta reservada por el kernel, no es accesible a nivel de usuario, peligro tendria si no.
El tema que comente anteriormente se refiere a que el puntero pasado a strcmp SÍ tiene memoria reservada en espacio de usuario y que contiene un NULL como contenido, no como puntero; usease 4 bytes a 0x00 (en SO de 32bit), por lo que la funcion strcmp en cuanto ve un byte (caracter, al ser de comparacion de cadenas) a 0x00, para. Y solo compara hasta ahi.
Y no es que la funcion strcmp pete al pasarle un NULL como argumento por referencia, si que cualquier programa es espacio de usuario que intende acceder a la direccion 0 de memoria ((void *)0) va a petar si o si; cosa del kernel.
Saludos
clinisbut escribió:2.- Si realmente se esta usando una función de cadenas para tratar datos binarios, y sabemos que la función no trabaja correctamente en cuanto se encuentra un 0x00... que ocurre con aquellas firmas legales que contengan un 0x00 en alguno de sus bytes? Se aceptan sin llegar a comprobarse del todo tal como pasa con el trucha.
clinisbut escribió:Al final lo del IOS 37 no era una broma?
Podria ser esto la continuación de la broma???
Porque hay dos cosas que no me cuadran:
1.- De donde se ha sacado que se usa el strcmp?? Supongo que es una suposición no? Que yo sepa hace falta tener el codigo fuente para conocer este tipo de detalles.
2.- Si realmente se esta usando una función de cadenas para tratar datos binarios, y sabemos que la función no trabaja correctamente en cuanto se encuentra un 0x00... que ocurre con aquellas firmas legales que contengan un 0x00 en alguno de sus bytes? Se aceptan sin llegar a comprobarse del todo tal como pasa con el trucha.
Waninkoko escribió:El TMD es el title metadata que contiene informacion sobre el juego.
http://wiibrew.org/index.php?title=Tmd_file_structure
Aqui te viene los diferentes campos que tiene el TMD.
La firma (u8 sig[256]) contiene un codigo hash SHA1 encriptado (el mismo hash del que voy a hablar un poco mas abajo) con la clave privada de Nintendo.
El hash del que yo hablo es aquel que se obtiene aplicando el algoritmo SHA1 desde el byte donde comienza el campo "issuer" hasta el final del TMD.
Si el hash sacado de la firma y el que calculamos sobre esos datos del TMD empiezan por 0x00, adios al chequeo de la Wii
Por cierto, he podido probar a ejecutar un juego con el IOS37 y me da un error
Waninkoko escribió:El TMD es el title metadata que contiene informacion sobre el juego.
http://wiibrew.org/index.php?title=Tmd_file_structure
Aqui te viene los diferentes campos que tiene el TMD.
La firma (u8 sig[256]) contiene un codigo hash SHA1 encriptado (el mismo hash del que voy a hablar un poco mas abajo) con la clave privada de Nintendo.
El hash del que yo hablo es aquel que se obtiene aplicando el algoritmo SHA1 desde el byte donde comienza el campo "issuer" hasta el final del TMD.
Si el hash sacado de la firma y el que calculamos sobre esos datos del TMD empiezan por 0x00, adios al chequeo de la Wii smile_XD
Por cierto, he podido probar a ejecutar un juego con el IOS37 y me da un error smile_XD
iacaca escribió:El método que utilizan los IOS antes del 37 para comparar las firmas se "detiene" cuando en la firma se encuentra un byte NULL, aunque la firma continue. De esta forma se puede firmar el disco con una firma muy corta rápidamente calculada. Por ejemplo, si en la firma pones un NULL en el quinto carácter, simplemente tienes que calcular 4 bytes válidos de la firma, y eso un PC actual lo calcula en nada (eso se comprueba en la rapidez con la que firma el Trucha Signer smile_:Ð )
merol escribió:Con vuestros mensajes se me ha venido una idea a la cabeza para conseguir un hash firmado original, pero una pregunta sino seria imposible. Si un TMD devuelve un hash que no tiene ningun NULL y el hash firmado (u8 sig[256]) lo pones todo a null lo da por valido o no??? si no lo da por valido mi idea se va al garete, sino a lo mejor sirve de algo.
Salu2
keridito escribió:Hay una cosa que no me termina de quedar clara en la explicación del bug que hay en wiibrew... No sé si se me escapa algo, creo que no, y que los de wiibrew no han explicado completamente el bug...
El fallo viene en la utilización de strncmp y que una de las cadenas contenga el caracter terminador antes de tiempo. Esto provocará que la función parará la comprobación...con lo que vamos a poner este caracter en el quinto byte, que calcular los cuatro primeros es algo rápido...
Lo que no me termina de quedar claro, es que asumen, por lo que veo en el seudocódigo este que muestran que strncmp devolverá cero...ya que los cuatro primeros bytes son iguales. Pero al ser el quinto el caracter terminador en una y en la otra la cadena no terminar todavía, la función no va a devolver 0 sino que devolverá -1 o 1.
Por lo que el bug no me termina de quedar muy claro, salvo que la implementación que haya sea tan tremendamente mala que cuando encuentra el fin de cadena devuelva 0 directamente, sin comprobar que las cadenas tuviesen la misma longitud...no me puedo creer que sea así, vamos.
Waninkoko escribió:
No lo da por valido. Con el nuevo IOS no servira, y con los IOS actuales tampoco.
Waninkoko escribió:Os voy a contar mi metodo
La Wii desencripta un hash SHA1 contenido en la firma y calcula otro hash SHA1 desde el campo "issuer" del TMD hasta el final del TMD.
Si ambos hashes coinciden, el disco esta bien firmado.
El caso es conseguir que ambos hashes comienzen por 0x00
El método mas sencillo es cambiar los 256 bytes de la firma por ceros, y modificar el campo "reserved" del TMD hasta que el hash SHA1 que se hace sobre el TMD comience por 0x00.
Tengo todo medio claro salvo una duda.Según entiendo, hay que realizar un calculo enorme para calcular una firma de "tamaño normal" así que se aprovecha el fallo (el del null) del strcmp para solo tener que calcular una pequeña parte (reduciendo drásticamente el numero de datos a calcular). Sin embargo, esta firma habrá que comprobarla con otra que esté "preparada" para que también sea más pequeña de lo normal, y aquí aparece mi duda: A partir de qué se calcula la otra y como puede modificarse para que también obtenga el null en el mismo byte?
ddf escribió:Lo importante aqui, es que como ya dijerón, este bug esta también en el boot1 de todas las wii actuales, y no se puede modificar el boot1 por mucho parcheo del firmware que hagan.
Waninkoko escribió:
Ambas cadenas deben de tener el caracter 0x00 en la misma posicion y los caracteres anteriores deben de ser iguales.
Si una cadena termina y la otra no, strncmp no devuelve 0.
Evil_forces escribió:...
Evil_forces escribió:
A ver, creo que no es asi como tu dices. Voy a ver si con un ejemplo se aclara un poco.
La firma del disco Wii es:
12345678
Esta firma es mas dificil de calcular por su longitud, pero gracias a la funcion que utilizan para comprobar poniendo solamente:
1234(Null)
Con esto ya lo daria por valido, ya que al detectar el valor Null para de comprobar.
Sacar solo los 4 primeros digitos es mas facil que sacar 8.
La firma Buena sigue siendo 12345678, pero solo con sacar el 1234 y ponerle el NULL bastaria para darla como valida.
Tambien serviria poner 1(Null), ya que conicide el primer digito con el primero de la firma real, y al estar el NULL para de comprobar.
Asi es como entiendo yo que funciona este bug.
Saludos.
Markuf escribió:
Bien, creo que lo he entendido, pero mi duda ahora es: No es muy cutre ese sistema de chequeo??? Descubres sólo la primera parte del "serial ese" y ya tienes todo???
keridito escribió:Me gustaría una explicación más clara, la verdad, no por nada, sino por aprender bien como funciona el invento este...
Waninkoko escribió:Os voy a contar mi metodo
La Wii desencripta un hash SHA1 contenido en la firma y calcula otro hash SHA1 desde el campo "issuer" del TMD hasta el final del TMD.
Si ambos hashes coinciden, el disco esta bien firmado.
El caso es conseguir que ambos hashes comienzen por 0x00
El metodo mas sencillo es cambiar los 256 bytes de la firma por ceros, y modificar el campo "reserved" del TMD hasta que el hash SHA1 que se hace sobre el TMD comienze por 0x00.
Basically, Nintendo screwed up the RSA signature verification badly. RSA is a well-known algorithm, hasn’t been broken yet, and basically there is just one thing you can do wrong: Not comparing the complete result (after a RSA public decrypt). And Nintendo did both things wrong. They screwed this up so hard that you need to count it twice. Here is the deal: Of the 4k or 2k result of the RSA decrypted hash block, they don’t check the padding at all. They just compare the SHA1-hash. Now, C is a hard language, especially when dealing with strings and blocks of memory, and there are so many functions with different names, so it’s almost impossible to not get confused. (This was a joke, if you haven’t got it.) Even more a joke is to compare binary blocks of data using a string compare (namely strncmp) instead of a binary compare (like memcmp). Yes, you have read correctly: For verifiying the hash (which is the only thing they verify in the signature), they have chosen to use a function which stops on the first nullbyte - with a positive result. Out of the 160 bits of the SHA1-hash, up to 152 bits are thrown away. Hooray.
Exploiting that hole, once found, is easy: just modify your content until it’s hash matches with the hash stored in the signature. Instead of a 160bit brute force attack, things get considerably easier, depending on what the decrypted hash look like it - the sooner it has a zero, the less you need to brute force in your data’s hash.
But given the other problem (not comparing any other properties of the resulting hash block, like the ASN.1-padding, which is actually present), it’s even easier: You can change the encrypted signature until it’s decrypted version results into a hash which has a zero byte somewhere at the beginning. Then you don’t rely on any real signature. And it’s even easier: Thanks to RSA’s mathematical structure, an input of all-zero produce an output of all-zero. So, by just overwriting the complete signature with zeros, you gain a hash value which is also all-zero. Then it’s just a matter of modifying your payload until that hash starts with a zero, which is a 8bit (slightly more, as segher explained me once - probability calculus FTW) brute force. Doable, easily. That’s what the hack bushing presented on 24C3 was based on.
Waninkoko escribió:Os voy a contar mi metodo
La Wii desencripta un hash SHA1 contenido en la firma y calcula otro hash SHA1 desde el campo "issuer" del TMD hasta el final del TMD.
Si ambos hashes coinciden, el disco esta bien firmado.
El caso es conseguir que ambos hashes comienzen por 0x00
El metodo mas sencillo es cambiar los 256 bytes de la firma por ceros, y modificar el campo "reserved" del TMD hasta que el hash SHA1 que se hace sobre el TMD comienze por 0x00.
Perfectamente explicado, muchas graciasmerol escribió:...
Elhaym escribió:hola
a ver...cuanto mas leo mas m lio(esto es como una madeja)
este bug q jode el trucha esta en una actualizacion de las nuevas?
lo digo pa saber si he actualizado y la he jodido...
la penultima actualizacion q puse es la q t avisa si un disco tiene actualizacion en el canal disco y la ultima la q m venia en el juego "fire emblem"
alguien me podria decir?
gracias y un saludo
kriogeN escribió:
La ultima actualización para la consola es la del Canal Tienda para poder comprar en WiiWare.
Esta actualización PREPARA la consola para tapar el bug del trucha, y por lo visto solo en las japonesas y americanas, las europeas no les pasa (al menos eso dicen en WiiBrew).
Ahora bien, como ya he dicho, solo prepara la consola. La ultima actualización NO ACTIVA EL PARCHEO, para eso hace falta una actualización del menú de la Wii, que muy probablemente será lo proximo que actualizen.
merol escribió:Segun he leido de la cita de tmbinc se podría una vez modificado un TMD ir cambiando el campo signed, es decir el hash firmado hasta que este campo desencriptado coincida con el hash del TMD que hemos modificado. De forma que parezca que se firmo con la clave privada de nintendo.
Este poblema tendria 256^256 combinaciones, no se cuanto tardaria este sistema, si alguien tiene alguna idea del tiempo que lo diga.
Salu2
GameZelda escribió:...Pues un montón de años, a día de hoy es imposible computar una cosa como esta.
...
(al menos sin una "chapuza" para prohibir la firma VALIDA que tendrías)...