miércoles, 1 de octubre de 2014

Writeup - [NN4ED]



::::::::::::::::::::[WEB 1]:::::::::::::::::::: 

En este reto nos dan una página web, http://ctf.navajanegra.com/WEB%201.php
en la que aparece un boton que pone "Click Here!" dentro y al acercarnos con el cursor este cambia de posición y no nos permite pulsarlo. Si analizamos el código vemos que es imposible pulsarlo y en la linea 41 encontramos la evidencia,
<button id="bt" onmousemove="fun();" onClick="alert('Do not waste time with this button!  
De donde se deduce que si el código es lo interesante, mas interesante será descargar el archivo WEB 1.php que está en el servidor que en ocasiones puede ser distinto al que visualizamos a traves de la web.
wget http://ctf.navajanegra.com/WEB%201.php
Abrimos el archivo con cualquier editor que tengamos a mano y vemos que despues de <body> aparece el flag.
<body>
Password: 6e3e92ebfcec506d0cc56f24a929ac11

::::::::::::::::::::[WEB 2]::::::::::::::::::::

Nos daban una pagina web con el campo usuario y contraseña vulnerable a sql injection. La vulnerabilidad se ha explotado con la herramienta sqlmap.


Flag: 78a2109f8519940bb553

::::::::::::::::::::[STG 1]::::::::::::::::::::

Nos proporcionan una imagen con un mensaje oculto en la que aparece un astronauta tomándose una cerveza en la luna.

Con strings obtenemos las cadenas de caracteres de la imagen
Al final de todo vemos una cadena en base 64, 

:ozy:TXkgc2VjcmV0IGNvZGU6IDFlZjFkODM0NzMzMWFmYjc1YjgyMjgxOWZkNGU2ZDNiIA==

Que descifrada quedaria; My secret code: 1ef1d8347331afb75b822819fd4e6d3b 

Flag: 1ef1d8347331afb75b822819fd4e6d3b

::::::::::::::::::::[STG 2]::::::::::::::::::::
    
::::::::::::::::::::[Phreaking 1]::::::::::::::::::::

En el primer reto de Phreaking nos piden descubrir el número de la tarjeta de un cliente.

Nos dan una pista de audio con una grabación telefónica de un servicio de venta de tickets, en la que el cliente mete los números de su tarjeta de crédito para realizar la compra.

Cuando el cliente pulsa una tecla se genera un tono DTMF (Dual-Tone Multi-Frequency) que viene dado por dos frecuencias determinadas que corresponden a cada tecla segun la siguiente tabla:

Para saber cuales son los pares de frecuencias que generan cada tono seleccionamos el trozo de pista donde se emite el tono y usamos el análisis de espectro de Audacity.


Los dos primeros picos se corresponden con las frecuencias que determinan que número estamos pulsando y sus valores vienen dados por la frecuencia de pico al situarnos con el cursor sobre cada uno de ellos.

Para los cuatro primeros numeros tenemos los siguientes pares de frecuencias, que aunque no son exactas, debemos de aproximarlas a la mas cercana para entrar en la tabla y obtener el número correspondiente:

{774, 1341}Hz ----> 5

{773, 1205}Hz ----> 4

{776, 1468}Hz ----> 6

{698, 1202}Hz ----> 1

Realizando el mismo proceso en el resto de los tonos sacamos el numero:
5461765425671065

 
 ::::::::::::::::::::[Phreaking 2]::::::::::::::::::::

En este reto nos daban una captura de una comunicación voIP en la que se debia obtener la contraseña original de la comunicación e introducirla con el formato: hash:pass

Una vez descargue el archivo SipPHK2.pcapng, lo abrí con whireshark y comprobé que usaba el protocolo SIP.

...
User-Agent: Linksys/PAP2T-3.1.15(LS)
Contact: <sip:nn4ed@94.133.99.2:49156>
Expires: 0
Authorization: Digest username="nn4ed", realm="sip.12voip.com", nonce="720058375", uri="sip:sip.12voip.com", response="3c58ee4488a90ad08d67a24b4c2c9beb", algorithm=MD5
Content-Length:  0
...

Si la analizamos un poco vemos que el usuario es "nn4ed" y el hash MD5: 3c58ee4488a90ad08d67a24b4c2c9beb

Con sipdump se vuelca las sesión capturada a un archivo pass.txt.


A continuación usamos sipcrack para crackear la contraseña haciendo uso de un diccionario.


Luego de probar varios diccionarios sacó la contraseña: passw

Finalmente la flag era:  3c58ee4488a90ad08d67a24b4c2c9beb:passw




::::::::::::::::::::[CRK 1]::::::::::::::::::::

Tras abrir el ejecutable “CrackMe1.exe” nos aparece una pantalla en la que debemos introducir un usuario y contraseña.
 



Introducimos un usuario y contraseña cualesquiera y se nos muestra un mensaje de error

A continuación abrimos este ejecutable con la herramienta Dependency Walker y vemos que está enlazada con MSVBM60.DLL, con esto sabemos que estamos ante un exe compilado con Visual Basic 6

Como el mensaje de error tiene toda la pinta de ser el mostrado por las APIs de Windows “MesageBox” vamos a depurar el ejecutable con OllyDBG y pondremos varios BreakPoints en las funciones que puede mostrar este mensaje: MesageBoxA, MesageBoxW, MesageBoxExA, MesageBoxExW, MesageBoxIndirectA, MesageBoxIndirectW, MesageBoxTimeoutA y MesageBoxTimeoutW. Todas estas funciones están en user32.dll

A continuación lanzamos el programa en el depurador de OllyDBG, ponemos un usuario y clave y vemos como el depurador se nos detiene en la función MesageBoxIndirectA

Ahora vamos a salir paso a paso de cada procedimiento hasta que retornemos al punto de ejecución en el ejecutable principal desde el cual se ha invocado a este MessageBoxIndirectA, pulsamos CTRL + F9 hasta retornar al ejecutable Crackme1.exe.
Tras salir de user32.dll y msvbvm60.dll nos encontramos en el ejecutable, justo tras la llamada que nos ha mostrado el mensaje de error.

Ahora con la ejecución del programa detenida en ese punto, hacemos scroll hacia arriba a ver si vemos alguna cadena de texto con un mensaje del tipo de “clave correcta” o algo similar.

Vemos un “Enhorabuena, has superado el reto.” Y un poco antes vemos dos cadenas de texto sospechosas: “…N….N” y “Albacete”.
Abrimos otro crackme1.exe para probar suerte y….

Segundo intento…

MD5 de “…N….N” ---> 0047c0baeb5faccc8a71319c72fa6af2
Reto superado!!


::::::::::::::::::::[CRK 2]::::::::::::::::::::


Tras ejecutar el archivo crackme2 vemos se nos piden dos números de serie. Introducimos dos números y nos aparece un mensaje: “Bad Hacker!”.

Desensamblamos el ejecutable y comenzamos a analizar su código

En esta primera parte vemos dos llamadas a la función de librería “scanf”, usadas para leer los números que habíamos introducido. Vemos también la existencia de 4 variables numéricas con los valores iniciales: 0x7F06F93, 0xBB, 0x2 y 0x0, la existencia de estos cuatro números nos hace pensar que serán usadas en algún calculo posterior.

En esta segunda parte vemos dos bucles que hacen dos comprobaciones idénticas, una para cada uno de los números que hemos introducido, en estos bucles vemos que se usan dos de las variables que vimos en el punto anterior, el 0x2 y el 0x0. En estos algoritmos se comprueba que ambos números son primos, dividiendo cada uno de los números entre todos los números enteros que van desde el 2 hasta el propio número, si en alguna de esas divisiones el resto de la división es 0 entonces el número no es primo. En caso de que alguno de los números no sea primo se salta al siguiente bloque de código:

Aquí se nos muestra el mensaje “Bad Hacker!” y finaliza la ejecución del programa.
Si ambos números son primos, no se toma el salto y el programa continúa en el siguiente bloque:

En este punto se realiza en primer lugar una división mediante la función __divdiv3, esta función de división la genera automáticamente el compilador cuando en la división interviene un número de 64bits y el programa se compila para 32 bits. Sabiendo que los operadores son dos números de 64 bits y que estos se pasan en forma de 4 parámetros de 32 bits cada uno… vemos que el primer operador es en realidad la concatenación de las dos primeras variables que vimos en el primer punto (0x7F06F93, 0xBB) lo que nos da el número 0xBB07F06F93. El segundo parámetro es el número por el cual vamos a dividir, y vemos que es el segundo número que nos pide el programa (este es un numero de 32bits y los 32bits de nivel superior se rellenan con 0: mov [esp+0Ch], edx <-- edx =0]).
La segunda parte de este fragmento de código, compara el resultado de la división anterior con el primer número que nos pide el programa, si el resultado coincide nos muestra el mensaje “Serial number Correct!”, si el resultado no coincide se nos muestra “Tray Again!”.
En resumen:
Los números buscados tienen que ser primos, y además el resultado de multiplicar ambos tiene que ser 0xBB07F06F93 (803292082067). También sabemos que los números introducidos son enteros de 32bits con signo (por el “%d” que se usa en el scanf), con lo cual el máximo valor que puede tener cada uno de los números va a ser 2147483647.
Ahora necesitamos una comprobación de fuerza bruta que pruebe todos los productos de números primos entre sí desde 2 hasta 2147483647 (el mayor número entero de 32bits con signo), hasta encontrar una combinación cuyo resultado sea el número 803292082067.
Usamos un diccionario de números primos y esta pequeña utilidad escrita en c# para multiplicar todos los primos entre sí:
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Linq;

namespace Primos
{
    class Program
    {
        static void Main(string[] args)
        {

            long resultado = 803292082067;

            List l = new List();

            using (StreamReader sr = new System.IO.StreamReader(@"D:\primos.txt"))
            {
                while (!sr.EndOfStream)
                {
                    l.Add(int.Parse(sr.ReadLine()));
                }
            }
            l.Sort();

            using (StreamWriter sw = new StreamWriter(@"D:\resultado.txt"))
            {
                Parallel.For(0, l.Count, new ParallelOptions()
                { MaxDegreeOfParallelism = Environment.ProcessorCount }, i =>
                {                    
                    for(int j = i;j < l.Count;j++)
                    {
                        long calc = (long)l[i] * (long)l[j];
                        if (calc == resultado)
                        {
                            lock (sw)
                            {
                                string r = l[i] + " x " + l[j] + " = " + resultado;
                                Console.WriteLine(r);
                                sw.WriteLine(r);
                                sw.Flush();                                
                            }
                            break;
                        }
                        else if(calc>resultado)
                        {
                            break;
                        }
                    }
                });
            }
            Console.WriteLine("Finalizado...");
            Console.ReadKey();
        }
    }
}

Esta herramienta nos indica que la multiplicación de 880543 x 912269 da como resultado el número buscado.

MD5 de 880543 -> 0f15116e1011443612420bc1ca223c68
MD5 de 912269 -> 3310cd38956c9a35abae340d91f42925
Reto superado.
Nota: Realmente existirían otros dos números posibles, que serían el -880543 y -912269 ya que su multiplicación también da el resultado buscado. No se ha comprobado si el reto también se daba por válido el MD5 de alguno de esos números negativos.

::::::::::::::::::::[EXTRA]::::::::::::::::::::
 
 En el enlace de la imagen nos lleva al siguiente link:
http://ctf.navajanegra.com/extra.php

Hi, James Bond, what is your agent number?

Podemos predecir que nos pide que usemos el agent, asi que cambiamos el user-agent por el 007.

 Se actualiza la página y nos da un qrcode.


 Lo decodificamos y nos da un md5.


Googleamos el md5 y ya fue desencriptado: f3807a187fce8cd0d901726ee33331bc == BUDA
Tambien nos dice que enviemos via POST el master code.



Usando hackbar puede hacerse y nos lleva a un link para descargar una maquina virtual de mega.


 Descargamos la maquina virtual y al montarla nos pedia usuario y contraseña para iniciar sesión. Como no habia ganas de hacer mas fuerza bruta optamos por montar el disco en otra máquina y asi pudimos acceder a los archivos saltandonos esa protección.

En el directorio /home encontramos un readme.txt que decia:
Encuentra la contraseña del archivo /home/navaja/bof1, desbordando la pila, para obtener la clave del nivel :)
Bueno xD, lo que se hizo fue abrir el archivo bof1 con IDA para echarle un vistazo:

En la linea en donde está el breakpoint se encuentra la contraseña en claro:
GNU/Linux, asique no era necesario explotar el BOF para superar el reto.

 Calculamos su MD5: 4a58db979d107ca6300f1be1406b3605

Reto superado!!

Como este reto Extra tuvo un final un tanto descafeinado, decidimos ser "legales" y sacar la contraseña provocando un stack overflow:

Ejecutamos bof1 y nos aparece el siguiente mensaje “Pista: 0x8048474”, Pulsamos enter y nos aparece “Introducistes:” y el programa se cierra.


Aparentemente en 0x8048474 existe algo interesante…
Vamos lanzar el programa con gdb y echar un vistazo a ver que hay en 0x8048474


 Nos encontramos una función llamada “foo”, la cual llama a “printf” y luego a “fflush”. Ese printf suena a que nos van a mostrar algún mensaje…
Volvemos a ejecutar el programa y escribimos algo


Parece que el programa lee lo que escribimos y a continuación lo muestra y finaliza.
Escribimos un texto largo a ver qué pasa:


Escribimos un texto de 250 caracteres y vemos que se muestran, pero a continuación el programa falla, con un error SIGSEGV. La causa más posible de este error es porque el programa ha intentado acceder a una zona de memoria que no contiene código ejecutable o no tiene permisos de ejecución o de lectura. El error con total seguridad se ha producido porque la variable destinada a guardar el texto introducido no tiene el tamaño suficiente para guardar las 250 letras y no se ha hecho una comprobación previa de su longitud, a partir de aquí el trozo de texto que excede la longitud máxima ha sobrescrito otras variables y posiblemente la dirección de retorno de la función actual, con cual se ha derivado el retorno de esta función hacia una zona de memoria que no es ejecutable.
Vamos a repetir el paso anterior lanzando el programa en gdb: 


Nos aparece el mismo error de violación de segmento, y vemos que ha sido en la dirección de memoria 0x61616161, además vemos que el valor de eip es 0x61616161, con lo cual sabemos que se ha intentado ejecutar algo que estaba en esa dirección. Realmente 0x61616161 no es una dirección válida, sino que son las aaaa… que hemos escrito: 0x61 es el valor hexadecimal de la letra ‘a’, si hubiésemos puesto bbbb… tendríamos el error en 0x62626262.

Si volvemos al principio vemos que nos daban una pista: 0x8048474… Parece lógico que deberíamos hacer que la ejecución del programa saltase a esa dirección.
Sabemos que en algún punto entre la primera a y la última de las 250 existen 4 a’s que nos sobrescriben el valor de retorno desde la dirección original por la 0x61616161.

A partir de aquí tendríamos que localizar en que punto de las 250 a’s tenemos que insertar nuestra dirección 0x8048474. Esto lo podemos hacer cambiando las 250 a’s por grupos de 10 a’s, 10 b’s, 10 c’s.... Una vez encontrado el grupo de 10, cambiamos ese grupo por abcdefgijk y comprobando el valor del registro eip con los valores hexadecimales de las letras tendríamos la posición exacta en la que poner nuestra dirección de la pista 0x8048474, tendríamos que buscar el valor hexadecimal de las letras en orden inverso al que vemos en gdb, ej. Si el error se produce en 0x64636261 serían las letras de la posición abcd (Little endian). El resto de letras las podemos omitir, puesto que una vez llegado a ese punto el programa va a continuar la ejecución en la nueva dirección que le indiquemos. El 0x8048474 lo tendremos que escribir también ivnertido: 0x74840408 (Little endian).

Realizada la búsqueda de la posición por el método anterior vemos que tras la introducción de 212 a’s, los 4 caracteres siguientes son los que van a machacar la dirección de retorno y dirigirnos a la dirección de memoria que le indiquemos, en este caso la dirección de la pista.

Para escribir estos 4 bytes hexadecimales de la dirección a continuación de las a’s podemos crear un archivo con un editor hexadecimal y luego dirigirlo al programa con el comando cat o podemos usar Python o Perl para generar una cadena de texto con letras junto con la dirección al programa:

perl -e  'print "a"x212 . "\x74\x84\x04\x08"' | ./bof1

Con este comando creamos 212 a’s y a continuación la dirección y luego lo dirigimos al programa.


Contraseña: “GNU/Linux”



 

No hay comentarios:

Publicar un comentario