Feliz año! :D

Aquí tenéis el writeup de nuestro primer CTF del año, el nullcon HackIM.

Podeis escoger la Versión PDF o seguir leyéndolo aquí ;)




Trivia 100

La respuesta estaba en la película Ocean's 13, donde un syberterrorista le cambia los nombres a los personajes, y en concreto al protagonista, Reuben, quien pasará a llamarse Jason.


Trivia 300

Buscamos en Shodan el nombre del servidor y encontramos uno con ese mismo nombre. Leyendo la información que nos da Shodan, sacamos la versión de Sharepoint: 10.50.2500.0


Trivia 400

Y nos adjuntan la siguiente imagen:

Lo pasamos por una herramienta OCR para extraer la cadena binaria y hacemos lo que nos piden: 32-grams.

El proceso consite en hacer todas las subcadenas de 32 caracteres posibles y comprobar cuál es la que más se repite. Lo automatizamos con un script y llegamos a 01100101011101100110100101101100 (1702259052) con 21 ocurrencias, que en ASCII es: “evil”.

#!/usr/bin/env python

string = '''
010110110010111001101111010101010110101011101011000010010101101001100101011101100110100101101100101010101000
101100101010101010010110010101110110011010010110110011010101101010101010100101010110011001010111011001101001
011011001010101010111001010010101011100101010101011110101010101110101010011001010111011001101001011011001011
010001010101010111011010101001100101011101100110100101101100000001010110101010000000011111010101010101011010
100010111001101010101010101011000010101010101111011001010111011001101001011011001011110101110101101101111101
101101100101011101100110100101101100111101001010101000100100100110100110010101110110011010010110110001001001
001001010010010110110110011001010111011001101001011011001011101101010100100100101010110101100101011101100110
100101101100101101110101011011010101010101010010010001101000101011010110110101010100100101010101010010101010
011001010111011001101001011011001110101010110000100100000101010101100101011101100110100101101100101101010110
010100100110001001010111011011011011110101110100000101100101011101100110100101101100010101111101010111111100
001010101010000000101010101010011101010101111100001010101010111011011111011001010111011001101001011011001110
111110110111100011011011011001100101011101100110100101101100111011010101010100100101001011011011010111010101
101111010101010101100101011101100110100101101100010100100101011011010101000101010010010101101011111111011010
101001100101011101100110100101101100101011010001010101111010000101010110101010101011111101010101011001100101
011101100110100101101100101011111101101101111010100001010110010101110110011010010110110001101111011111011011
010110010101110110011010010110110010000000110110010101110110011010010110110001101101101011101011101001000010
'''.replace("\n", "")


def play(s):
    counts = {}
    for i in xrange(0, len(s) - (32 - 1)):
        x = s[i:i + 32]
        assert(len(x) == 32)
        if x in counts: counts[x] += 1
        else:           counts[x] = 1
 
    m = None
    mc = 0
    for x in counts:
        v = counts[x]
        if v > mc:
            m = x
            mc = v
    print m, "with", mc, "ocurrences" 
    print int(m, 2)


if __name__=="__main__":
    play(string)

El flag consistía en dar un sinónimo, que resultó ser: maleficence.


Crypto 100

Destaca la alternancia mayúsculas-minúsculas. Después de un rato, nos damos cuenta de que coindicen con los símbolos de los elementos químicos de la tabla periódica.

Sustituimos cada símbolo por su número atómico, obteniendo los códigos ASCII del texto resultante:


«IT IS THE FUNCTION OF SCIENCE TO DISCOVER THE EXISTENCE OF A GENERAL REIGN OF ORDER IN NATURE AND TO FIND THE CAUSES GOVERNING THIS ORDER. AND THIS REFERS IN EQUAL MEASURE TO THE RELATIONS OF MAN SOCIAL AND POLITICAL AND TO THE ENTIRE UNIVERSE AS A WHOLE.»


Una cita de Mendeleiev, el primer diseñador de la Periodic table, que resultó ser el flag.


Web 100

Nos dan el enlace a una web, que nos devuelve un 404:

Cada vez que recargamos la página, el Error Codevaría, y se repite la secuencia cíclicamente. Los caracteres que van apareciendo nos recuerdan a base 64.

Unimos todos los fragmentos y obtenemos:

TnVsbGNvbkdvYTIwMTVAV0VCMDAxMTA

Y finalmente, aplicando base64_decode(): NullconGoa2015@WEB001100.


Web 300

Nos dan un enlace a la siguiente web:

Tras intentar romperlo con inyecciones sin éxito...

Find the keys to your home... Probamos a meter "127.0.0.1" y nos lleva a esto:

loo[k]::back... eso nos recuerda a ipv6. Probamos a meterlo en ipv6:

Bingo! El flag era 0:0:0:0:0:0:0:1.


Web 400

Nos dicen que tenemos que comprar un pase gratis y nos dan un enlace, que nos lleva a la siguiente página:

Si le damos a Buy nos dirá que debemos comprarlo por ZERO rupee.

Mirando el código vemos algo interesante:

En el formulario, hay un campo msg que envía los datos del pase separando los campos con barras verticales: “Nullcon2015|Corporate|10999”.

El sistema verifica la validez de los mismos mediante un checksum, el cual vemos podemos ver cómo se genera gracias al código del comentario.

Tenemos sha256 y una clave constante de la cual conocemos la longitud: vulnerable a hash length extension attack (wiki), el cual nos permite incluir información extra.

Para explotarlo hacemos uso de la herramienta hashpump (github):

Reenviamos la petición modificando esos POST y finalmente:

El flag era: fl@g_*2o15.


Web 500

Nos dan el enlace a esta web:

Nos piden enviar un captcha muchas veces en 2 minutos.

Hacemos un script en Python utilizando OCR y finalmente nos escupe el flag: H@CKIM_C@pTcha!09022015.

#!/usr/bin/env python

from PIL import Image
import subprocess
import sys
import urllib
import urllib2

def onlycolor(iname, oname):
    i = Image.open(iname)
    l = i.load()
    for x in xrange(i.size[0]):
        for y in xrange(i.size[1]):
            if l[x, y] != (0x7A, 0x6F, 0xFF):
                l[x, y] = 0
            else:
                l[x, y] = (0xff, 0xff, 0xff)
    i.save(oname)
 
def download(cookie, outName):
    opener = urllib2.build_opener()
    opener.addheaders.append(('Cookie', cookie))
    f = opener.open("http://54.165.191.231/imagedemo.php")
    open(outName, "wb").write(f.read())
    
def getcode(image):
    return subprocess.check_output(["gocr", image]).replace("\n", "")

def sendcode(cookie, code):
    opener = urllib2.build_opener()
    opener.addheaders.append(('Cookie', cookie))
    r = opener.open("http://54.165.191.231/verify.php", urllib.urlencode({"solution": code, "Submit": "Submit"}))
    return r

def show(out):
    print out.read()

def play():
    r = urllib.urlopen("http://54.165.191.231/captcha.php")
    cookie = r.info().get("set-cookie")
    x = r.read()
    imgname = ("down.png", "processed.png")
    
    while True:
        download(cookie, imgname[0])
        onlycolor(*imgname)
        code = getcode(imgname[1])
        print code
        out = sendcode(cookie, code)
        show(out)
    
if __name__ == "__main__":
    play()



Happy h4cking! ;)