From 834d581b05809ea35de1e3bc1ab78eaf092c1e26 Mon Sep 17 00:00:00 2001 From: RocketDev Date: Fri, 13 Dec 2024 23:38:05 +0800 Subject: [PATCH 1/3] ROP: fix `self.leave is None` in some libc When `pop rbp; pop rsp; ret;` exists in libc, it is chosen instead of `leave`. Add a specific `order` to filter out the former one. --- pwnlib/rop/rop.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pwnlib/rop/rop.py b/pwnlib/rop/rop.py index 4505962d7..894b69243 100644 --- a/pwnlib/rop/rop.py +++ b/pwnlib/rop/rop.py @@ -1418,7 +1418,7 @@ def __getattr__(self, k): if not set(['rsp', 'esp']) & set(regs): self.pivots[sp_move] = addr - leave = self.search(regs=frame_regs, order='regs') + leave = self.search(regs=frame_regs, order='leav') if leave and leave.regs != frame_regs: leave = None self.leave = leave @@ -1451,7 +1451,7 @@ def search(self, move = 0, regs = None, order = 'size'): pointer is adjusted. regs(list): Minimum list of registers which are popped off the stack. - order(str): Either the string 'size' or 'regs'. Decides how to + order(str): Either the string 'size', 'leav' or 'regs'. Decides how to order multiple gadgets the fulfill the requirements. The search will try to minimize the number of bytes popped more than @@ -1459,7 +1459,9 @@ def search(self, move = 0, regs = None, order = 'size'): the address. If ``order == 'size'``, then gadgets are compared lexicographically - by ``(total_moves, total_regs, addr)``, otherwise by ``(total_regs, total_moves, addr)``. + by ``(total_moves, total_regs, addr)``, if ``order == 'regs'``, + then by ``(total_regs, total_moves, addr)``. ``order == 'leav'`` + is specifically for ``leave`` insn. Returns: A :class:`.Gadget` object @@ -1471,8 +1473,9 @@ def search(self, move = 0, regs = None, order = 'size'): # Search for an exact match, save the closest match key = { 'size': lambda g: (g.move, len(g.regs), g.address), - 'regs': lambda g: (len(g.regs), g.move, g.address) - }[order] + 'regs': lambda g: (len(g.regs), g.move, g.address), + 'leav': lambda g: ('leave' not in g.insns, len(g.regs), g.address) + }[order] # False is prior than True try: result = min(matches, key=key) From bc8a1263fa0e6e0dcf86dff689f1b0aac5cda0b3 Mon Sep 17 00:00:00 2001 From: RocketDev Date: Sat, 14 Dec 2024 00:10:13 +0800 Subject: [PATCH 2/3] add changelog for #2506 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecaac64d0..cdfcc25b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -89,6 +89,7 @@ The table below shows which release corresponds to each branch, and what date th - [#2502][2502] Fix loading ELF files without valid .dynamic section - [#2476][2476] Deprecate 'keepends' argument in favor of 'drop' in `tube.recvline*` - [#2364][2364] Deprecate direct commandline scripts invocation and exclude nonsense ones +- [#2506][2506] ROP: fix `ROP(ELF(exe)).leave` is `None` in some ELF [2471]: https://github.com/Gallopsled/pwntools/pull/2471 [2358]: https://github.com/Gallopsled/pwntools/pull/2358 @@ -106,6 +107,7 @@ The table below shows which release corresponds to each branch, and what date th [2502]: https://github.com/Gallopsled/pwntools/pull/2502 [2476]: https://github.com/Gallopsled/pwntools/pull/2476 [2364]: https://github.com/Gallopsled/pwntools/pull/2364 +[2506]: https://github.com/Gallopsled/pwntools/pull/2506 ## 4.14.0 (`beta`) From e93ca778c8da9dfdd51bff8bda825ebc7ee295e5 Mon Sep 17 00:00:00 2001 From: RocketDev Date: Fri, 20 Dec 2024 15:14:19 +0800 Subject: [PATCH 3/3] ROP: add sp_move when `pop rsp` --- pwnlib/rop/rop.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pwnlib/rop/rop.py b/pwnlib/rop/rop.py index 894b69243..3a15be29f 100644 --- a/pwnlib/rop/rop.py +++ b/pwnlib/rop/rop.py @@ -1391,6 +1391,8 @@ def __getattr__(self, k): if pop.match(insn): regs.append(pop.match(insn).group(1)) sp_move += context.bytes + if 'sp' in insn: + sp_move += 9999999 elif add.match(insn): arg = int(add.match(insn).group(1), 16) sp_move += arg