Post

Circle City Con CTF2021 - Guardian

Reversing

We have a really cool owl mascot, but there’s no really cool owl themed movies….well actually….there’s one.

Primeros pasos

Para este se entrega un binario llamado “guardian”, y la dirección y puerto donde corre el binario “35.224.135.84:2000”.

1
2
$ file little
guardian: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=7d78bf75ff54ea16c4065908d62a89e4c7e0af53, for GNU/Linux 3.2.0, not stripped

Con el comando strings podemos ver la cadena “flag.txt”, seguramente lo use para leer un archivo con este nombre si se cumplen algunas condiciones.

Análisis dinámico

Si se ejecuta el binario se produce una “segmentation fault”, pero si creamos un archivo flag.txt en el mismo directorio del binario ya no se produce este error:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$ echo "CCC{fake_flag}" > flag.txt
$ ./guardian

!WWWWWeeu..   ..ueeWWWWW!
 "$$(    R$$e$$R    )$$"
  "$8oeeo. "*" .oeeo8$"
  .$$#"""*$i i$*"""#$$.
  9$" @*c $$ $$F @*c $N
  9$  NeP $$ $$L NeP $$
  `$$uuuuo$$ $$uuuuu$$"
  x$P**$$P*$"$P#$$$*R$L
 x$$   #$k #$F :$P` '#$i
 $$     #$  #  $$     #$k
d$"     '$L   x$F     '$$
$$      '$E   9$>      9$>
$6       $F   ?$>      9$>
$$      d$    '$&      8$
"$k    x$$     !$k    :$$
 #$b  u$$L      9$b.  $$"
 '#$od$#$$u....u$P$Nu@$"
 ..?$R)..?R$$$$*"  #$P
 $$$$$$$$$$$$$$@WWWW$NWWW
 `````""3$F""""#$F"""""""
        @$.... '$B
       d$$$$$$$$$$:
       ````````````


HOOOOOOOOOO Goes there? Do you have the password?
>

Ni strace ni ltrace mestran información interesante para solucionar el reto.

Si se hacen unas pocas pruebas, rápidamente puede verse que, despues de introducir la contraseña, el binario muestra tantos “Check marks” como caracteres de la contraseña coinciden con el contenido del archivo flag.txt hasta el primer caracter distinto:

1
2
3
4
5
...
> CCC{
✅  ✅  ✅  ✅
Hoo hoo hoo!
That is incorrect, my guardian.

Una pequeña dificultad es que solamente se imprimen 8 Checks por línea:

1
2
3
4
5
HOOOOOOOOOO Goes there? Do you have the password?
> CCC{fake_flag}
✅  ✅  ✅  ✅  ✅  ✅  ✅  ✅
✅  ✅  ✅  ✅  ✅  ✅  ✅
We will do our best.....you have fought well.

Solución

Una vez comprendido el funcionamiento del binario, solamente hay que escribir un solver que valla probando todos los caracteres posibles y cuando detecte un Check más que antes, actualice el contenido de la contraseña y vuelva a empezar:

solver.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/python3

from pwn import *
import string

context.log_level = 'error'

abc = "?$!_0123456789{}" + string.ascii_letters 

flag = "CCC{"

while True:
    for c in abc:
        s = remote("35.224.135.84", 2000)
        #s = process("./guardian")

        num_check_marks = 0

        s.recvuntil("\n>") # Banner
        s.sendline(flag+c)

        # Count Chekc Marks
        for _ in range((len(flag) // 8) + 1):
            num_check_marks += len(s.recvline().decode('utf-8')) // 3

        if num_check_marks > len(flag):
            flag += c
            print(flag)

            if c == '}':
                exit()

        s.close()

El script funciona tanto como con el binario local como con el remoto, simplemente hay que comentar una de las líneas 14 y 15 y dejar otra sin comentar. El script termina en menos tiempo si se ejecuta de forma local, por temas de latencia.

This post is licensed under CC BY 4.0 by the author.