HackIt! Nivel 3: solución

El primer paso por tanto, será realizar ingeniería inversa sobre el binario .class. Para ello, tras buscar un buen descompilador de clases Java, nos encontramos con Jad, una aplicación gratuita (no-libre) multiplataforma.

Descargaremos la versión 1.5.8e compilada estáticamente para no tener problemas de dependencias con ninguna librería.
A continuación, descargaremos el fichero secApplet.class en el que se basa el reto 3.

$ wget http://hackit2.diariolinux.com/secApplet.class

Y procedemos a la descompilación:

./jad secApplet.class

Tras algunos warnings, obtendremos el fichero secApplet.jad, que al abrirlo, comprobaremos que se trata del
código fuente Java original de la clase secApplet. También veremos que la calidad del trabajo de descompilación realizado por Jad
es muy buena (probablemente debido también a que el autor del .class original no se preocupó de esconder su código).

Entre las funciones de interés del fichero .jad se encuentra el código del método decrypt()

String decrypt(String s)
{
String s1 = "";
StringBuffer stringbuffer = new StringBuffer(s);
for(int i = 0; i < stringbuffer.length(); i++)
switch(stringbuffer.charAt(i))
{
case 65: // 'A'
s1 = s1 + "L";
break;
case 66: // 'B'
s1 = s1 + "M";
break;
...

Si analizamos el flujo del programa veremos que se llama a ese método decrypt pasándole el parámetro basename (del código HTML del applet Java):

String s = getParameter("basename");
if(s != null)
s = decrypt(s);

Bien, preparemos una clase Java a la que daremos el nombre Hack, y que incluirá un método main() de prueba del método decrypt():


public class Hack {
public static void main(String[] args){
System.out.println( decrypt(args[0]) );
}
public static String decrypt(String s)
{
[incluír aquí el código de decrypt]
}
}
Compilamos nuestra clase de prueba:

$ javac Hack.java

Y la ejecutamos, pasándole como parámetro el valor de la variable «basename» que encontramos en el código HTML de la página:

$ java Hack jhtgh.spi
users.dat

Bueno, nos devuelve el nombre users.dat. Leyendo el código Java descompilado anteriormente, vemos que users.dat es el nombre del ficheroque se descarga desde getDocumentBase()+users.dat, es decir, desde http://hackit2.diariolinux.com/users.dat :

URL url = new URL(getDocumentBase(), s);
DataInputStream datainputstream = new DataInputStream(url.openStream());
String s1;
while((s1 = datainputstream.readLine()) != null){

Bien, vamos a ver qué se esconde en ese fichero:

$ wget http://hackit2.diariolinux.com/users.dat

Si hacemos un cat de users.dat vemos que es un string cifrado. Según el código Java descompilado, hay que descifrarlo, usando decrypt() otra vez:

$ java Hack `cat users.dat`
euskal|j4v4t0s|./level4-j4v4t0s.html|_self

Con lo que ya tenemos la clave del nivel 4.

Conclusiones: basar la seguridad de un procedimiento de autenticación en esconder el método de descifrado en un fichero binario es bastante ingenuo. Cualquier atacante con unos mínimos conocimientos de ingeniería inversa podrá saltarse cualquier método de seguridad por ocultación. Le costará más o menos tiempo hacerlo, pero podemos estar seguros de que podrá conseguirlo si se esfuerza lo suficiente…

HackIt! Nivel 3: seguridad por ocultación

Lo primero que vemos al entrar en el nivel 3 es un applet Java (que en Firefox, le cuesta cargar lo suyo…). En dicho applet se nos pide que introduzcamos login y password. Si acertamos, pasamos de nivel. Ok, analicemos el código fuente de la página para ver qué podemos averiguar. Lo primero que veremos será información sobre la clase Java principal que usa este applet: secApplet.class. Esta clase usa también clases internas que podemos encontrar compiladas en secapplet.jar. Todo esto lo podemos saber tras analizar el código HTML del reto:

 <applet code="secApplet.class" archive="secapplet.jar" codebase="." WIDTH=343 HEIGHT=152>
			<param name=numusers value="1">
			<param name=basename value="jhtgh.spi">
			<param name=style value="1">
			<param name=numtries value="3">
			<param name=width value="343">
			<param name=height value="152">
			<param name=l2 value="8|38|53|13|">
			<param name=l3 value="10|76|49|13">
			<param name=t1 value="74|38|245|21">
			<param name=t2 value="74|76|245|21">
			<param name=b1 value="74|108|245|20">
			<param name=bkcolor value="1118566">
			<param name=txcolor value="16777215">
			<param name=alturl value="./level3-3m3d35.html">
			<param name=ltitle value="Enter your Username and Password">
			<param name=mtarget value="_self">
		 </applet>

Parece por tanto que todo lo que tenemos que hacer es descompilar el fichero .class  y analizar el código fuente del applet Java, para ver qué es lo que está ocurriendo internamente (y esperemos que: 1) se pueda descompilar  y 2) el código fuente que genere no sea complicado de entender)

HackIt! Nivel 2: resumen criptográfico

Seguimos con la prueba 2 del HackIt!, donde lo dejamos ayer. Algunos lectores me comentan que mejor no dé la solución directamente sino que vaya dando pistas progresivas. Me parece bien.

Lo primero que haremos, en este y otros niveles, será mirar el código fuente de la página en busca de…. bueno, !pistas! 🙂

La página del nivel 2 incluye una función Javascript llamada Login() que tiene el siguiente aspecto:


function Login() {
var user = document.login.username.value;
var pass = document.login.password.value;
if (user=="euskal" && hex_cypher(pass)=="c79cc1714419a4aaf3c4c53360843294") {
location.href = 'level3-' + pass + '.html';
} else {
alert("ACCESS DENIED!");
};
}

Es decir, está claro que el nombre de usuario es ‘euskal’, pero del password sólo sabemos que al pasarlo por una función llamada hex_cypher devuelve como resultado la cadena «c79cc1714419a4aaf3c4c53360843294». Podemos hacer dos cosas, analizar la función hex_cypher(),
que según el código fuente de esa misma página :

< script type="text/javascript" src="cypher.js" > </script>

se encuentra en el fichero cypher.js o bien usar «pensamiento lateral» 🙂 La primera opción siempre es viable dado el código fuente, por ingeniería inversa, pero nos llevará mucho (MUCHO) tiempo. La segunda opción, es más interesante. Pensemos que estamos en la segunda fase, la solución por tanto no debe de ser muy difícil… el algoritmo usado debe de ser conocido, y el resultado de aplicar ese algoritmo a una cadena de texto devuelve otra cadena de 32 caracteres de longitud… no hay muchas funciones de uso común en seguridad informática con esas características… Dada esa pista, tal vez se os ocurra qué función implementa hex_cypher(). Cuando la conozcáis, habrá que pensar en cómo romperla, es decir, ¿es posible a partir de la cadena resultado (32 caracteres) obtener el passwordoriginal sabiendo la función que se aplicó? (o dicho de otra forma, si la función es f, existe la inversa de f?

UPDATE: bueno, pues ya tenemos respuestas al reto 🙂 Efectivamente, se trata de la función md5, que según la Wikipedia:

«En criptografía, MD5 (Message-Digest algorithm 5) es una función criptográfica de dispersión, ampliamente utilizada e insegura [1] [2] , que dado un texto, devuelve un valor hash de 128 bits (32 caracteres). MD5 es un estándar de Internet, documentado en el RFC 1321, y ha sido utilizado en una gran variedad de aplicaciones de seguridad, así como para comprobar la integridad de archivos. Un hash MD5 se expresa típicamente como una cadena de 32 números hexadecimales.»

Una función hash, o función de dispersión como MD5, NO TIENE INVERSA. Es decir existe f(x) pero no f-1 (x). Sin embargo, se puede atacar el problema por fuerza bruta… de hecho, existen en Internet diversas webs con enormes bases de datos precalculadas («al password x, le corresponde el hash y»). Por ejemplo, plain-text.info, una web que añade además la posibilidad de unirse a una red distribuída de obtención de hash md5 (nuestro ordenador puede participar, generando miles y miles de hashes cada día y añadiéndolos a la enorme base de datos de esa web… por cierto, no sólo de md5, sino también lm o ntlm, algoritmos usados en el cifrado de claves en Windows.

Si pasamos el hash c79cc1714419a4aaf3c4c53360843294 por esa web, nos da la clave de acceso al siguiente nivel : 3m3d35.

Nota: existe un método más elaborado que permite conocer todas (hasta cierto tamaño de clave ) las posibles combinaciones de x (y sus hash) sin tener que guardar explícitamente cada una de ellas (estoy hablando de las Rainbow Tables).

HackIt! 2007 : un repaso a las pruebas

Ayer, los miembros de diariolinux.com nos apuntamos a la Euskal Encounter 2008. Como ya comenté, este año iremos con más experiencia y ganas si cabe a participar en el HackIt! . No nos hacemos demasiadas ilusiones porque hay grupos muy, muy buenos compitiendo. El caso es que me interesaba repasar la solución a las pruebas del HackIt2007, por varias razones: para ir desempolvando mis conocimientos de ensamblador (muy oxidados ya :-), de GDB, OllyDBG…, para ahorrarle trabajo al organizador ( txipi ), y para que queden por escrito algunos apuntes sobre el tema, que usaré más adelante en mis clases de seguridad informática.

He colgado de http://hackit2.diariolinux.com el concurso del año pasado, que analizaré a lo largo de estos días, al menos hasta llegar a la prueba 11, donde nos atascamos (así, si algún lector la superó en su día o la supera ahora que está colgada en DL, pues mejor que mejor, porque podrá explicarnos al resto cómo lo hizo 🙂

Sin más dilación, pasamos con la primera prueba, que como toda «primera» , su resolución es bastante sencilla. Lo primero que se nos ocurre es analizar el código fuente de la página, centrándonos en el ćodigo Javascript que recoge los datos (login y password) y los envía al servidor:

<script src="JavaScript">
        function Login() {
          var user = document.login.username.value;
          var pass = document.login.password.value;
          if (user=="euskal" & pass=="p4rt7") {
	    location.href = 'level2-' + pass + '.html';
	  } else {
	    alert("ACCESS DENIED!");
	  };
        }
  </script>

A primera vista parece que el login(username) debería de ser euskal y el password p4rt7, pero si probamos esos datos en el formulario veremos que son incorrectos (!). ¿Dónde está el truco? En la primera línea del código anterior:

<script src="JavaScript">

Esto que a primera vista podría parecer una línea que dice «el código fuente que viene a continuación está escrito en JavaScript», resulta que no dice eso, sino «insertar aquí el código fuente de un script almacenado en un fichero que se llama… tachán, tachán, ‘JavaScript’ «. El dichoso archivo podría haber tenido otro nombre, como funcion.js o algo similar, pero no, le han llamado JavaScript, para hacerlo un poco menos trivial 😉

Si abrimos ese fichero, veremos la clave que nos lleva al nivel 2.

Euskal y Gipuzkoa Encounter: nos vemos en Tolosa y Barakaldo

Hoy miércoles 20 de Febrero se abre el período de inscripción a las partys que en Euskadi esperamos a lo largo del año, la Euskal Encounter 16 (en Barakaldo, 24-27 de Julio) y la Gipuzkoa Encounter 2 (Tolosa, del 25 al 27 de Abril) . DiarioLinux.com estará en ambas, cómo no, como cada año. En cuanto tengamos el sitio cogido, informaremos en este mismo post de los número de asiento, para que los lectores que quieran acercarse a charlar, sepan dónde encontrarnos. En la Euskal, por supuesto, competiremos de nuevo día y noche para ganar el concurso de HackIt! 😉