jueves, 31 de enero de 2013

Cómo un "==" puede volverte vulnerable

¡Saludos!

    Hoy recién acabo de terminar los exámenes, con pésimos resultados, y vuelvo a tener tiempo para poder escribir aquí y continuar con los distitnos proyectos que tenía abiertos. Aetsu terminará en breves también sus exámenes... asi que empezaremos las pruebas del podcast en breve. Como ya os dijimos por twitter, sería muy interesante que nos comentarais qué tipo de contenido quereis que incluyamos y sobre qué temás os gustaría que hablasemos.


    En estos días sin escribir por el blog han saltado distintos 0-days gordos, como el de Java, que supuestamente fue parcheado, y volvieron a sacar otro 0-day, y otro, y ya me perdí el culebrón porque era demasiado lío. Recordad: cada vez que instalais un navegador y no desactivais JAVA (ni usais NoScript), Dios mata a un gatito. A parte de JAVA, salieron otras noticias, como la vulne de Ruby on Rails, o las de los foros SMF (ya parcheada). Y es esta última sobre la que vamos a hablar en este post porque me ha resultado muy interesante el disclosure que han hecho, y me parece muy aplicable a otras tantas aplicaciones web :)


   La vulnerabilidad de los foros SMF que han liberado estos días permitía a un atacante poder resetear la contraseña a un administrador. Este es el post original del disclosure.

      El problema base que vuelve a la aplicación vulnerable es que hace una comprobación del token generado para resetear la password que es inadecuada, y que puede dar por bueno un token que no lo es. Recordemos que los token son cadenas de caracteres aleatorios que se incluyen en las peticiones de las aplicaciones web para evitar que los usuarios legítimos caigan en ataques CSRF . Se comprueba el token a través de una comparación, usando "==" , entre el supuesto valor del token que se ha generado y el valor que nosotros hemos incluido en la petición (en realidad en el caso de SMF se hace con los diez primeros caracteres de un hash MD5, pero estoy extrapolando la vulnerabilidad para cualquier otra aplicación). En el caso de que el token que nosotros hemos enviado no coincida con el que la aplicación espera, no se permite el reseteo del password, y viceversa, si ambos coinciden te permite cambiar el password.

      En teoría no hay nada extraño, es lo correcto. Compruebo la cadena generada con la que me da el usuario para ver si es la misma. El problema está en cómo se hace dicha comprobación. Resulta que al comprobar con "==" una cadena que empiece con dígitos, ésta se convierte automáticamente en una variable tipo integer. Y esto conlleva una segunda consecuencia, y es que se aplican las mismas reglas que a estas variables. Es decir, podemos usar notación exponencial, colocando una "e" entre la base y el exponente.

      ¿Qué ocurre cuando 0 o 1 es elevado a cualquier número? Que se quedan iguales. 0e123 es igual a 0, 0e523452345234523452345 es igual a 0, y  por lo tanto también igual a 0e123. Y lo mismo ocurre con el 1: 1e124 es igual a 1, y 1e5555 es igual a 1e124. ¿Veis donde está la vulnerabilidad? Probemos el siguiente PoC:

<?php
$key1 = "0e12345";
$key2 = $_GET['k'];
if ($key2 == $key1){

echo $key1 . ' es igual a ' . $key2;
} else {
echo $key1 . ' es diferente a ' . $key2;
}
?>



 Si probamos a pasarle ?k=0  nos dirá que son iguales. Pero ambos sabemos que ambas cadenas de caracteres son diferentes. Si probamos con 0e[cualquiercadena de nuemros] nos seguirá diciendo que los dos strings son iguales.  ¿A qué nos lleva esto?

  Una aplicación que genere unos tokens alfanuméricos y que no bloquee el número de intentos para hacer una determinaada petición, en alguno de esos tokens va a generar una cadena que será 0e[numeros] o 1e[numeros], por lo que su valor será 0 o 1. Si nosotros mandamos peticiones de forma continuada, alternando entre un string que empiece con 0e y otro con 1e, cuyo valor por lo tanto también será 0 o 1, llegarán a coincidir en algún momento y la petición será legitima.


  Me parece que esta vulnerabilidad es bastante intersante, y que es muy común encontrarla. Espero que reviseis vuestros códigos y a partir de ahora programeis teniendo en cuenta estas premisas.



Byt3z
5 0verl0ad Labs: Cómo un "==" puede volverte vulnerable ¡Saludos!     Hoy recién acabo de terminar los exámenes, con pésimos resultados, y vuelvo a tener tiempo para poder escribir aquí y contin...

5 comentarios:

Sinkmanu dijo...

Para comparar cadenas de caracteres se usa strncmp (o strcmp). :)

http://php.net/manual/es/function.strncmp.php

Saludos.

seth dijo...

y el exploit para cuando?

The X-C3LL dijo...

@Seth

La vulnerabilidad está parcheada en SMF desde hace muy poco (pero afecta a todas las versiones, creo recordar, por lo que seguirá habiendo foros vulnerables).

En el caso concreto de SMF la comparación se hacía únicamente con los 10 primeros caracteres del token en MD5, por lo que sólo tienes que calcular los dos primeros hashes que fuesen 0e[ocho numerso] y 1e[ocho numerso] (en el disclosure los muestran), y enviar múltiples peticiones hasta que alguna coincida.

Este finde subiré un exploit de ejemplo, si lo deseas.

Kory dijo...

La verdad que es muy interesante esta vulnerabilidad, muy inteligente.

Pero para que su explotación sea muy eficaz, lo correcto es que se encuentre un XSS en el sitio (no necesariamente en el foro SMF) y realizar peticiones desde javascript para cambiar el password, hasta que alguna coincida.

Saludos.

The X-C3LL dijo...

Si tienes un XSS, no hace falta complicarse tanto la vida. Puedes leer los tokens del código fuente y a partir de ahí hacer cualquier cosa. Subes un usuario a admin con el XSS, o directamente robas la cookie, y de ahí shell y hasta la cocina.

PD: voy a 18kbps por lo que el podcast se está retrasando hasta que consiga una antena wifi USB. Se admiten sugerencias :P

< >