Desvelado el bug del trucha

Bushing, al comprobar que Nintendo ya lo arregló en el controvertido IOS37, publicó el bug del firmado. http://wiibrew.org/index.php?title=Signing_bug

Y la verdad, el fallo es una estupidez... los de Nintendo se despistaron mucho para pasarlo por alto [qmparto]

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 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 :Ð )
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.


Vamos, que es un fallo de los gordos, usando un caracter nulo la función deja de comparar y por esto se puede encontrar una colisión en un tiempo corto.

No he usado la función "strncmp" nunca, pero pero supongo que poniendo el segundo carácter a nulo encontrar la combinación seria facilisimo, una posibilidad entre 256.

La solución creo que es facilisima, en el caso del ejemplo que dan en Wiibrew, seria tan fácil como cambiar "strncmp" a "memcmp", que es lo mismo pero que no se para cuando encuentra un carácter nulo.

Me parece increíble que nadie se dedicase a revisar el código de la comprobación, siendo tan importante como es. Supongo que debieron utilizar el método típico del "funciona? pues ya está" y listo [+risas]
GameZelda escribió:Supongo que debieron utilizar el método típico del "funciona? pues ya está" y listo [+risas]


xDDDD ojala xDD tonces seria todo mas facil jaja xD pero con tanto millon de por medio ... [Ooooo]
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í? ein?
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í? ein?


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)
http://debugmo.de/?p=61

edit
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)



no es que pueda estar en cualquiera de las dos, DEBE estar en las dos cadenas y en la misma posicion.
weno yo no entiendo mucho pero imagino k esto no tiene nada k ver con k hayan descubierto como saltarse la ios37 de las narices no???
xt5 escribió:edit



no es que pueda estar en cualquiera de las dos, DEBE estar en las dos cadenas y en la misma posicion.


Gracias, no sabia esto ya que no lo pone (al menos de una forma clara) en cplusplus.com ni nunca había usado esta función (que yo personalmente la veo un poco inútil :? )
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.


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?
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.

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.

EDIT: Como comparacion de metodos:
#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;
}

Deberia imprimir:
resultao strcmp: 0
resultao memcmp: 1

La unica diferencia sustancial (en cuanto a prog con libc), es que con memcmp se debe indicar el tamaño de bytes a comparar.
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?


Segun entiendo yo, el bug es algo así:

#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;
}



Esta aplicación, da como resultado:
Cadenas: Valido!
Memoria: Invalido!


El fallo es que Nintendo esta usando método de las "Cadenas", entonces como se puede ver en este código, se da como valido aunque no es igual.
He estado googleando y...

http://www.cygwin.com/ml/libc-alpha/2004-08/msg00119.html

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.


No, no es normal,no deberia pararse al encontrar NULL...según el standar lo que debe hacer es petar y bien que peta.

Regla de oro en temas de seguridad comprobar siempre la entrada.

Pero por lo visto un null como parámetro esta definido como comportamiento no definido por lo que por eso se devuelve la señal segfault por que es lo que dice el estandar que debe suceder,es decir la funcion simplemente no esta definida para para esa entrada.

O lo que es lo mismo se pasa el marrón al usuario de esa función.


El fallo de los de nintendo esta en suponer que strcmp esta definido para valores null y el fallo de quien ha implementado la función strcmp que usan en nintendo esta en definir un comportamiento para esa entrada en vez de petar.

Supongo que el comportamiento estandar de stcmp sigue siendo asi por compatibilidad con codigo antiguo si no es algo que no tienes ni pies ni cabeza.

A mi me habían enseñado siempre a comprobar lo que le metia a una strcmp pero no sabía (o recordaba) es que la strcmp se lavaba las manos.
Os voy a contar mi metodo XD

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.
[quote="wah_wah_69"][/quote]
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
Ya que ahora se sabe el fallo, no se puede aplicar a los canales wii?
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


Exacto, ha sido un lapsus mio el no acordarme, era exactamente como dices como me lo explicaron,ese area de memoria se supone que esta protegida.

Lo que no entiendo es que no se advierta de eso en la manpage ni en la referencia del opengroup,que luego pasa lo que pasa...


@Waninoko:

Entiendo tu método aunque no se que info se lee y compara al comprobar la firma, ¿Qué es el TMD?
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 XD

Por cierto, he podido probar a ejecutar un juego con el IOS37 y me da un error XD
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.
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.


Exacto.
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.


Si lo de que se usa strcmp es una suposición bien podría estar hecha la comprobación en asm mismo,pero lo que importa es el comportamiento y el comportamiento es que no se comprueba el tamaño de la entrada si no que se compara hasta encontrar un 0 que para el caso es el mismo comportamiento de la strcmp segun dicta el opengroup y esta implementado en la glibc (he mirado el codigo en google code search).

Es por esto por lo que muchas aplicaciones implementan sus propias funciones de manejo de cadenas y gestión de memoria.
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 XD

Por cierto, he podido probar a ejecutar un juego con el IOS37 y me da un error XD

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_:Ð )


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
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


No lo da por valido. Con el nuevo IOS no servira, y con los IOS actuales tampoco.
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.
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.


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.
Waninkoko escribió:
No lo da por valido. Con el nuevo IOS no servira, y con los IOS actuales tampoco.


Entonces mi idea no es viable...

Bueno salu2 espero que ahora que se conoce mucho mas la wii, se pueda sacar algo a prueba de actualizaciones.

Salu2
Waninkoko escribió:Os voy a contar mi metodo XD

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.


Bueno, como programador y "aficionado" a los formatos de archivo (principalmente los del Guitar Hero [looco] ) me gustaría probar esto.

He estado mirando un tmd.bin del Guitar Hero "trucheado" y es como dices tu, el SHA1 desde "issuer" hasta el fin comienza por 0x00.

El tema es la firma. Según tu está cifrada y contiene un SHA1. No entiendo muy bien como funciona el tema, alguien podria explicármelo o dar algun link? (También veo que el trucha pone unas cuantas tonterias allí, pero me imagino que es la primera parte lo que importa)

Lo primero es la encriptación. Que algoritmo y key se usa?
Lo segundo que no me cuadra es que un hash SHA1 es más corto que la firma (cosa bastante evidente). Como va el tema? Supongo que la firma debe ser una estructura o algo...

Y por ultimo, esto que dices tu de "ponerlo todo a cero" significa que funciona con los 256 bytes directamente a cero ya está? ¬_¬
No acabo de entender cómo funciona pero segun he entendido, lo que intentamos buscar es un código que sea el mismo que el que tiene la Wii escondido? Y lo tenemos que hacer probándolos todos?

Y si fuese así, cuando tengamos dicha cadena, qué podríamos llegar a conseguir? Todo?

Gracias
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 :D por mucho parcheo del firmware que hagan.
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?
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?


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.
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 :D por mucho parcheo del firmware que hagan.


mi no entender, que es el boot1, y si acaban de decir en wiibrew que con una proxima actualización del system menu que use el IOS37 (espero haberlo puesto todo bien), se tapara este bug. No entiendo ahora lo del boot1
Off-topic:
A dia de hoy con qué herramienta es posible abrir un canal? He probado el tachtig para los saves y funciona bien pero no he visto nada para los canales.
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.


Entonces el fallo no viene sólo por la función...sino porque la clave que se usa tiene un cero en una determinada posición casi al principio de la cadena... Ha habido suerte entonces, tanto por el fallo en el código como por la clave de Nintendo...
Evil_forces 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???
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.


Con lo explicado hasta ahora eso sólo no vale. Es necesario que la firma con la que comprueba tenga un 0 en esa posición también. Es lo que no termino de entender del bug...Hay algo más que no explican bien y que tiene que ser clave... está claro que la posición donde poner NULL no es aleatoria. Que hayan probado muchas posiciones y en una de ellas el sistema haya dicho que vale, que le gusta ahí...
Me gustaría una explicación más clara, la verdad, no por nada, sino por aprender bien como funciona el invento este... es que me suena demasiado sospechoso. Como dicen en portada, tiene pinta de puerta atrás más que bug.
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???


Es que a posta no lo han hecho, fallo tonto típico al manejar cadenas. Años oyendo, cuidado al manejar cadenas, fgets y demás que se puede comprometer la seguridad..Y yo creyendo que era una leyenda urbana :-p
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 lo comentó con algo más de detalle:

Waninkoko escribió:Os voy a contar mi metodo XD

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.


También lo comentó tmbinc:
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.
Creo que la gente se esta haciendo mucho lio con el tema de la firma, voy a intentar hacer otra explicacion, de lo que yo he entendido de Waninkoko. Vamos a ver.

=============Sistema asimetrico===================
La wii usa un sistema de cifrado asimetrico, especificamente RSA, el cifrado asimetro necesita dos claves, una publica y otra privada, en wii nintendo usa la clave privada para firmar, y la wii tiene alojada la publica para descrifrar. Funciona de la siguiente forma:

Tengo una cadena y las dos claves que llamare clapri (clave privada) y clapu (clave publica) por ejemplo:

cadena= 11111
clapri = 22222
clapu = 33333

yo con cadena y clapri y el algoritmo RSA obtengo cadenacifrada:

cadenacifrada= 444444

ahora la wii con cadenacifrada y clapu y el algoritmo RSA obtengo cadena, este es el fundamento basico, para entender lo que pasa en wii.

===============Proceso en la wii====================
En un juego de wii, se realiza el siguiente proceso:
Tenemos cadena (en este caso seria desde issuer hasta el final del TMD) a esta cadena se le realiza un proceso de hash como el md5 (mas info) asi obtenemos cadenahash.

Ahora codificamos este hash con la clave privada de nintendo. Y obtenemos cadenahashcodificada.

Bien pues en el juego se guarda cadena y cadenahashcodificada.

Hasta ahí lo que hace nintendo para cada juego.

Ahora una vez llega el juego a nuestra casa. cogemos cadenahashcodificada y la desencriptamos con la clave publica obteniendo cadenahash2.
Realizamos sobre cadena el algoritmo de hash, por lo que deberia devolvernos cadenahash si en su momento se uso la clave privada de nintendo, cadenahash y cadenahash2 seran iguales, si no son iguales es un sintoma de que no se ha firmado con la clave privada de nitendo.

El bug es el siguiente si en esta ultima comprobación ambos tienen un valor 0 en el primer byte de cadenahash y cadenahash2 el sistema lo dara como valido.

Espero haber aclarado y no liado mas, si yo entendi bien a Waninkoko


EDITADO, se me envio sin terminar.
Waninkoko escribió:Os voy a contar mi metodo XD

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.

Más claro, agua.

En azúl tenemos la firma.
En rojo el campo "reserved" del TMD.

00000000000000000000000000000000000000000000000000
88888888888888888888888888888888888888888888888888

La Wii calcula la firma sobre el TMD y obtiene 1122334455667788....... no vale, no empieza por 00, por lo tanto modificamos un byte del TMD.

00000000000000000000000000000000000000000000000000
98888888888888888888888888888888888888888888888888

La Wii ahora calcula otra vez la firma y obtiene 0011223344556677...... bingo, firma "válida" conseguida.

Saludos
merol escribió:...
Perfectamente explicado, muchas gracias :)

Pos que triste este método de comprobación ._.U
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
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


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.
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.


gracias kriogen
pos voy a entrar en el canal tienda para ver si pone algo de wiiware...o se trata de un nuevo canal q deberia de aparecer?
(ya se q has dichoq en teoria en als europeas no pasa...pero si no lo tengo m kedo aun mas trankilo)
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
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


Pues un montón de años, a día de hoy es imposible computar una cosa como esta.

Además en el milagroso y casi imposible caso que lo consiguieras solo te serviría para un único disco. Eso si, Nintendo no podría solucionar esto (al menos sin una "chapuza" para prohibir la firma VALIDA que tendrías)

Bueno, pues el tema parece ser baste simple según se pone, simplemente poner toda la firma a cero y modificar el campo reserved hasta que el hash empiece por cero, que es una posibilidad entre 256 (prácticamente instantáneo con un PC actual)
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)...


Yo pensaba que tardaria un tiempo asumible para un pc actual, se que habria que hacerlo para cada disco, pero.... la firma VALIDA seria la misma que la privada de nintendo, es decir si nintendo hiciese el hash a nuestro TMD modificado y lo firmase obtendria lo mismo que nosotros. De forma que seria imposible de tapar. Aunque si tanta combinación es demasiado para un ordenador actual no hay nada que hacer, lo que esta claro es que seria mucho mas sencillo que buscar la propia clave privada de nintendo.


Esperemos que al menos con la nueva aplicacion de Waninkoko tengamos juegos hasta que se descubra el agujero definitivo, o podamos hacer custom firmw, y no nos perdamos ninguna maravilla de nintendo.

Salu2
Creo que tengo una pequeña idea de como solucionar el trucha y obtener la clave original de nintendo para firmar con la clave original.
Pero antes diganme si mis susposiciones son correctas si son asi puede que sea valido...

Hasta lo que he entendido actualmente la consola con los IOS antes del nuevo que hay ahora (37) la comprobacion la hacia hasta encontrarse el final de cadena (0x00) no?
Leia dos cadenas y en ambas tenia que estar el 0x00 en la misma posicion y lo que habia antes de 0x00 era comprobado si era igual no es asi?

2 Dudas en 1 ---> ambas cadenas estan en el disco/canal o una en el disco/canal y la otra en la wii?¿lo que venga despues del 0x00 si lo ponemos por ejemeplo en decimoquito caracter, tieene que se igual tb?

Continuemos con mi suposicion si ponemos todo a 0x00 al no haber caracter que comprobar automaticamente devuelve 0 (validcio ok)
Encambio si ponemos el 0x00 al final hace la validacion compreta y adivinar todos esos numero es muy dificil o imposible de calcular todos de golpe no es asi?

Ahora bien...
Si ponemos el 0x00 a partir del segundo caracter el primero debera coincidir para k devuelva "0" de manera que ahora nuestros palos de ciego son solo de 256 numeros a provar una ver encontremos el numero X que funcione sabemos cual es el primer caracter de la clave ahora repetimos el mismo proceso pero poniendo de caracter 1 el que savemos que va ok y ahora provamos los 256 en el 2 para saber cual es el seguro y asi vas haciendo pruevas uno por uno hasta obtener todos yobtendrias una clave correcta/original sin truchear no es asi? Creen que funcionaria?

Desde luego si tenemo la clave original ya es incapable ... y podriamos firmar lo que quisieramos....

Por contra .... NO ES IMPOSIBLE OBTENERSE PERO SE TARDARIA BASTANTE TIEMPO EN PROVAR TODOS LOS NUMEROS HASTA OBTENRER TODOS... 256 pruebas por cada caracter suponiendo k son 256 (no se cuantos son exactamente) son bastantes pruebas XD


Wanikoko ¿Crees que sirve de algo o se he congeturado algo que no tiene ni pies ni cabeza?
mmmm 256^256:

3231700607131100730071487668866995196044410266971548403213034542752465513886
7890893197201411522913463688717960921898019494119559150490921095088152386448
2831206308773673009960917501977503896521067960576383840675682767922186426197
5616183809433847617047058164585203630504288757589154106580860755239912393038
5521914333389668342420684974786564569494856176035326322058077805659331026192
7084603141502585928641771167259436037184618573575983511523016459044036976132
3328723122712568471082020972515710172693132346967854258065669793504599726835
2998638215525166389437335543602135433229604645318478604952148193555853611059
596230656 combinacines......... [burla3]
72 respuestas
1, 2