#!/usr/bin/python from socket import * import os, sys, random, time PUSH = 0x41 POP = 0x42 PRINT = 0x43 XCHG = 0x44 ADD = 0x45 SUB = 0x46 INC = 0x47 DEC = 0x48 AUTH = 0x49 PRIV_INST = 0x4a findyou = 0 inception_flag = 0 LEVEL1_PASSWORD = "" SP_HIGH = 0x1000 SP_LOW = 0 SP_CURRENT = -1 SP_DATA = [] SP_DATA.append("BOTT") SP_CURRENT = 0 INCEPTION_LEVEL_ONE = 0 INCEPTION_LEVEL_TWO = 0 INCEPTION_LEVEL_THREE = 0 LEVEL2_INST_COUNT = 0 LEVEL2_HEAP = "" LEVEL2_BASEADDR = 0 def op_push(data): global SP_HIGH, SP_LOW, SP_CURRENT, SP_DATA if SP_CURRENT > SP_HIGH: return -1 else: SP_CURRENT += 1 if len(SP_DATA) > SP_CURRENT: SP_DATA.pop(SP_CURRENT) SP_DATA.insert(SP_CURRENT, data) def op_pop(): global SP_HIGH, SP_LOW, SP_CURRENT, SP_DATA if SP_CURRENT < SP_LOW: return -1 else: SP_CURRENT -= 1 def op_print(): global SP_HIGH, SP_LOW, SP_CURRENT, SP_DATA if SP_CURRENT > SP_HIGH or SP_CURRENT < SP_LOW: return -1 print SP_DATA[SP_CURRENT] def op_xchg(): global SP_HIGH, SP_LOW, SP_CURRENT, SP_DATA if (SP_CURRENT - 1) < SP_LOW: return -1 tmp = SP_DATA[SP_CURRENT-1] SP_DATA[SP_CURRENT-1] = SP_DATA[SP_CURRENT] SP_DATA[SP_CURRENT] = tmp def op_add(data): global SP_HIGH, SP_LOW, SP_CURRENT, SP_DATA if SP_CURRENT < SP_LOW: return -1 tmp = SP_DATA[SP_CURRENT] tmp = int(tmp.encode("hex")) to_add = int(data.encode("hex")) sum = tmp + to_add if sum > 0xffffffff: sum = sum ^ 0x100000000 sum = str(sum) SP_DATA[SP_CURRENT] = sum.decode("hex") def op_sub(data): global SP_HIGH, SP_LOW, SP_CURRENT, SP_DATA if SP_CURRENT < SP_LOW: return -1 tmp = SP_DATA[SP_CURRENT] tmp = int(tmp.encode("hex")) to_sub = int(data.encode("hex")) sum = tmp - to_sub if sum < 0: sum = 0 sum = str(sum) SP_DATA[SP_CURRENT] = sum.decode("hex") def op_inc(): global SP_HIGH, SP_LOW, SP_CURRENT, SP_DATA if SP_CURRENT < SP_LOW: return -1 tmp = SP_DATA[SP_CURRENT] tmp = int(tmp.encode("hex")) if tmp == 0xffffffff: tmp = 0 else: tmp += 1 tmp = str(tmp) SP_DATA[SP_CURRENT] = tmp.decode("hex") def op_dec(): global SP_HIGH, SP_LOW, SP_CURRENT, SP_DATA if SP_CURRENT < SP_LOW: return -1 tmp = SP_DATA[SP_CURRENT] tmp = int(tmp.encode("hex")) if tmp == 0: tmp = 0xffffffff else: tmp -= 1 tmp = str(tmp) SP_DATA[SP_CURRENT] = tmp.decode("hex") def op_auth(static={"seed":0}): global LEVEL1_PASSWORD global SP_HIGH, SP_LOW, SP_CURRENT, SP_DATA try_count = 0 if len(LEVEL1_PASSWORD) == 0: LEVEL1_PASSWORD = "%d%d%d%d" % (random.randrange(0, 0xa), random.randrange(0, 0xa), random.randrange(0, 0xa), random.randrange(0, 0xa)) LEVEL1_PASSWORD += "%d%d%d%d" % (random.randrange(0, 0xa), random.randrange(0, 0xa), random.randrange(0, 0xa), random.randrange(0, 0xa)) static["seed"]=int("%d" % (random.randrange(0, 0xa))) if SP_CURRENT > SP_HIGH or SP_CURRENT < SP_LOW: return 0 if len(SP_DATA) < 2: return 0 TRY_PASSWORD = SP_DATA[SP_CURRENT] TRY_PASSWORD += SP_DATA[SP_CURRENT+1] sleep_time = "0.%d" % (static["seed"]) for i in range(0, len(LEVEL1_PASSWORD), 1): if LEVEL1_PASSWORD[i] != TRY_PASSWORD[i]: print "Ariadne: password is not matched." sys.stdout.flush() return 0 else: # preventing from bruteforce time.sleep(float(sleep_time)) auth_level1() def op_level2_inst(): if check_priv_level1(): pass else: print "Ariadne: You don't have the priv, do not stay away from me, cobb.." sys.stdout.flush() sys.exit(0) print "Ariadne: What do you want, cobb?" sys.stdout.flush() level2_init() while 1: inst = sys.stdin.readline() inst = inst.strip() if level2_parse_inst(inst) == 1: pass else: level2_exec_inst() break def auth_level1(): global INCEPTION_LEVEL_ONE INCEPTION_LEVEL_ONE = 1 print "Ariadne: you've just got into inception level1!" sys.stdout.flush() def auth_level2(): global INCEPTION_LEVEL_TWO INCEPTION_LEVEL_TWO = 1 print "Ariadne: you've just got into inception level2!" sys.stdout.flush() def check_priv_level1(): global INCEPTION_LEVEL_ONE if INCEPTION_LEVEL_ONE == 1: return 1 else: return 0 def check_priv_level2(): global INCEPTION_LEVEL_TWO if INCEPTION_LEVEL_TWO == 1: return 1 else: return 0 def level2_init(): global LEVEL2_HEAP global LEVEL2_BASEADDR heapsize = random.randrange(0, 0xffff) LEVEL2_HEAP = " " * heapsize LEVEL2_BASEADDR = heapsize def level2_end(): global LEVEL2_HEAP heapsize = random.randrange(0, 0xffff) LEVEL2_HEAP += " " * heapsize def level2_exec_inst(): global LEVEL2_HEAP global LEVEL2_BASEADDR eip = LEVEL2_BASEADDR while 1: eip = eip & 0x1ffff offset = 0 opcode = LEVEL2_HEAP[eip:eip+4] if opcode == "INFO": print "Ariadne: [INFO instruction] INCEPTION!!" sys.stdout.flush() elif opcode == "PRNT": arr = LEVEL2_HEAP[eip+3].split() tmp = 0 while 1: if LEVEL2_HEAP[eip+5+tmp] == ' ': break else: tmp += 1 length = LEVEL2_HEAP[eip+len(opcode)+len(" "):eip+len(opcode)+len(" ")+tmp] length = int(length) payload = LEVEL2_HEAP[eip+len(opcode)+len(" ")+tmp+1:eip+len(opcode)+len(" ")+tmp+length+1] print "Ariadne: [PRNT instruction] '%s'" % (payload) sys.stdout.flush() offset = tmp+length+2 elif opcode == "EXIT": sys.exit(0) elif opcode == "PRIV": auth_level2() elif opcode == "DEEP": if check_priv_level2() == 1: print "Ariadne: [DEEP instruction]" sys.stdout.flush() level3_start() else: print "Ariadne: [DEEP instruction] - you don't have the priv." sys.stdout.flush() sys.exit(0) else: print "Ariadne: Process ends: (%s)" % (opcode) sys.stdout.flush() break eip += len(opcode) + 1 + offset def level2_jit_inst(opcode, loopcount, static={"point":0}): global LEVEL2_HEAP global LEVEL2_BASEADDR current_point = static["point"] for i in range(0, loopcount, 1): LEVEL2_HEAP += "%s\n" % (opcode) current_point += len(opcode) + 1 static["point"] = current_point def level2_parse_inst(data, static={"loop":0}): global LEVEL2_INST_COUNT if LEVEL2_INST_COUNT > 10: print "Ariadne: Instruction count has been over 10." sys.stdout.flush() sys.exit(0) else: pass if len(data) < 4: print "Ariadne: Instruction string length must be 4 at least." sys.stdout.flush() sys.exit(0) inst = data[0:4] if inst == "LOOP": arr = data.split() if len(arr) != 2: sys.exit(0) try: static["loop"] = int(arr[1]) except: sys.exit(0) return 1 elif inst == "PRNT": pass elif inst == "PRIV": if check_priv_level2(): pass else: print "Ariadne: You don't have the priv." sys.stdout.flush() sys.exit(0) elif inst == "INFO": pass elif inst == "GOGO": level2_end() return 0 elif inst == "EXIT": pass else: sys.exit(0) level2_jit_inst(data, static["loop"]) static["loop"] = 1 return 1 def level3_init(): global signature global randdir randdir = random.randrange(0x1000000000, 0x2000000000) os.system("mkdir /home/beist/ctf/tmp/%d" % (randdir)) signature = "%02x%02x" % (random.randrange(0, 0x100), random.randrange(0, 0x100)) signature = "0x%s" % (signature) signature = int(signature, 16) fp = open("/home/beist/ctf/tmp/%d/inception" % (randdir), "w") fp.write("%s\n" % (signature)) directions = ["east", "west", "north", "south"] for i in range(0, 50): x = random.randrange(0, len(directions)) fp.write("%s\n" % (directions[x])) fp.close() def level3_find_you(): global inception_flag global signature global findyou if inception_flag != 1: print "Ariadne: you're not in inception." sys.stdout.flush() sys.exit(0) fp = open("./inception", "r") check = fp.readline() check = check.strip() if check != str(signature): print "Ariadne: you're cheating on me!!!!!!!!!!!!! %s(%d) %s(%d)" % (check, len(check), signature, len(str(signature))) sys.stdout.flush() sys.exit(0) print "Ariadne: hm... let's see.." sys.stdout.flush() for c_direction in fp: direction = sys.stdin.readline() direction = direction.strip() c_direction = c_direction.strip() if direction != c_direction: print "Ariadne: you don't find me.." sys.stdout.flush() sys.exit(0) else: print "Ariadne: good luck.." sys.stdout.flush() findyou = 1 def level3_into_inception(): global inception_flag global randdir if inception_flag == 1: print "Adriadne: already.." sys.stdout.flush() sys.exit(0) inception_flag = 1 os.chdir("/home/beist/ctf/tmp/%d/" % (randdir)) print "Ariadne: deep.." sys.stdout.flush() def rc4crypt(data, key): x = 0 box = range(256) for i in range(256): x = (x + box[i] + ord(key[i % len(key)])) % 256 box[i], box[x] = box[x], box[i] x = 0 y = 0 out = [] for char in data: x = (x + 1) % 256 y = (y + box[x]) % 256 box[x], box[y] = box[y], box[x] out.append(chr(ord(char) ^ box[(box[x] + box[y]) % 256])) ret = ''.join(out) return ret.encode("hex") def level3_enc(data): # my_very_secret_key is 16 byte random value fp = open("/home/beist/ctf/my_very_secret_key", "rb") key = fp.readline() tmp = time.time() tmp = str(tmp) tmp = tmp.split(".") tmp = tmp[0] payload = key + tmp ret = rc4crypt(data, payload) fp.close() return ret def level3_exchange(): global signature global magicvalue print "Ariadne: who you want to exchange, cobb? everything you try is useless.. stay here forever.." sys.stdout.flush() hostinfo = sys.stdin.readline() hostinfo = hostinfo.strip() if ":" not in hostinfo: sys.exit(0) payload = "%s %s" % (hostinfo, signature) arr = payload.split(":") host = arr[0] port = arr[1].split() port = port[0] port = int(port) try: client = socket(AF_INET, SOCK_STREAM) client.connect((host, port)) client.send("do you hear me?\n") data = client.recv(20) magicvalue = level3_enc(data) sys.stdout.flush() client.close() except: print "Ariadne: it seems this world is going to be down..!" sys.stdout.flush() sys.exit(0) if len(data) < 16: print "Ariadne: too short! yours.." sys.stdout.flush() sys.exit(0) magicvalue = level3_enc(data) client.close() def level3_escape(): global magicvalue if inception_flag != 1: print "Adriadne: you think i'm stupid?" sys.stdout.flush() sys.exit(0) print "Ariadne: you really want to escape from this world.. i'd miss you.." sys.stdout.flush() inst = sys.stdin.readline() inst = inst.strip() value = str(inst) if value == magicvalue: print "%s" % (os.getcwd()) fp = open("/home/beist/ctf/key", "r") key = fp.readline() print "the key is %s! congrats!" % (key) sys.stdout.flush() fp.close() else: print "Ariadne: how come you forgot our thing.. it was '%s'!!!" % (magicvalue) print "Ariadne: let's stay here forever.. with me." sys.stdout.flush() sys.exit(0) def level3_givemesg(): global randdir global signature global inception_flag if inception_flag != 1: print "Adriadne: you think i'm stupid?" sys.stdout.flush() sys.exit(0) print "Ariadne: title?" sys.stdout.flush() filename = sys.stdin.readline() filename = filename.strip() if filename.isalpha(): pass else: print "Ariadne: you think i'm stupid?" sys.stdout.flush() sys.exit(0) print "Ariadne: memo?" sys.stdout.flush() memo = sys.stdin.readline() memo = memo.strip() fp = open("./%s" % (filename), "w") fp.write(memo) fp.close() print "Ariadne: thanks.. girls love letters.. always.. :)" sys.stdout.flush() def level3_start(): level3_init() while 1: print "Ariadne: what do you want..?" sys.stdout.flush() inst = sys.stdin.readline() inst = inst.strip() if inst == "EXCHANGE": level3_exchange() elif inst == "ESCAPE": if findyou != 1: print "Ariadne: you didn't find me yet.." sys.exit(0) level3_escape() elif inst == "FINDYOU": level3_find_you() elif inst == "MOREDEEP": level3_into_inception() elif inst == "GIVEMESG": level3_givemesg() else: sys.exit(0) def parse_inst(input): op = input[0:1] op = int(ord(op)) if op == PUSH: data = input[1:5] op_push(data) elif op == POP: op_pop() elif op == PRINT: op_print() elif op == ADD: data = input[1:5] op_add(data) elif op == SUB: data = input[1:5] op_sub(data) elif op == INC: op_inc() elif op == DEC: op_dec() elif op == AUTH: op_auth() elif op == PRIV_INST: op_level2_inst() else: print "Ariadne: that's an invalid instruction." sys.stdout.flush() while 1: print "Ariadne: Hi, darling...." sys.stdout.flush() input = sys.stdin.readline() input = input[:-1] print input parse_inst(input)