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.