# insomnihack 2018 onewrite

Let's take a look at the binary:

```
$    file onewrite
onewrite: ELF 64-bit LSB pie executable, x86-64, version 1 (GNU/Linux), dynamically linked, for GNU/Linux 3.2.0, with debug_info, not stripped
$    pwn checksec onewrite
[!] Did not find any GOT entries
[*] '/Hackery/pod/modules/stack_pivot/insomnihack18_onewrite/onewrite'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
$    ./onewrite
All you need to pwn nowadays is a leak and a qword write they say...
What do you want to leak ?
1. stack
2. pie
 > 1
0x7ffe246ac1a0
address : 0x7ffe246ac1a0
data : 5
```

So we can see that we are dealing with a `64` bit binary with a Stack Canary, NX, and PIE. When we run it, it appears to give us a choice between a stack or PIE infoleak. After that, it looks like it gives us a write to a region of memory we specify.

## Reversing

When we take a look at the main function in Ghidra, we see this:

```
void main(void)

{
  setvbuf((FILE *)stdin,(char *)0x0,2,0);
  setvbuf((FILE *)stdout,(char *)0x0,2,0);
  puts("All you need to pwn nowadays is a leak and a qword write they say...");
  do_leak();
  return;
}
```

So we can see it prints some text, and calls `do_leak`:

```
void do_leak(void)

{
  long choice;
  undefined auStack24 [8];
  undefined *do_leak_adr;
 
  do_leak_adr = do_leak;
  puts("What do you want to leak ?");
  puts("1. stack");
  puts("2. pie");
  printf(" > ");
  choice = read_int();
  if (choice == 1) {
    printf("%p\n",auStack24);
  }
  else {
    if (choice == 2) {
      printf("%p\n",do_leak_adr);
    }
    else {
      puts("Nope");
    }
  }
  do_overwrite();
  return;
}
```

So we can see it prompts us for a choice. If we choose `1`, it will print the address of `auStack24` and give us a stack infoleak. If we choose `2`, it will print the address of the `do_leak` function and give us a PIE infoleak. So we essentially get a choice between either a PIE or a stack infoleak. Then it calls `do_overwrite`:

```
void do_overwrite(void)

{
  void *ptr;
 
  printf("address : ");
  ptr = (void *)read_int();
  printf("data : ");
  read(0,ptr,8);
  return;
}
```


Here we can see it prompts for an address with `read_int` and stores it in `ptr`. It then let's us write `8` bytes (a QWORD) to `ptr`. So essentially we have a single QWORD write to an address that we specify, with data that we control.

## Exploitation

So our exploit will have two parts. The first is we will use a partial overwrite to call the `do_leak` function multiple times, to get both a stack and PIE infoleaks. Then we will write to the `fini_array` to essentially give us as many writes as we want. Using that we will write our rop chain to memory. Proceeding that we will just call a gadget which will pivot the stack to execute our rop chain.

#### Infoleaks / Partial Overwrites

So for the first run through, we will choose the stack infoleak. Using this we will be able to know where the saved return address for `do_leak` is. Let's find the offset using pwntools and gdb:

We set a breakpoint for the `ret` instruction in `do_leak`:

```
Breakpoint 1, 0x00007f6814bc3ab7 in ?? ()
[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────────────────────────────── registers ────
$rax   : 0x1               
$rbx   : 0x00007f6814bc3060  →   sub rsp, 0x8
$rcx   : 0x0               
$rdx   : 0x8               
$rsp   : 0x00007ffe8c136818  →  0x00007f6814bc3b09  →   nop
$rbp   : 0x00007f6814bc4780  →   push r15
$rsi   : 0x00007ffe8c136800  →  0x00007f6814bc4704  →  0x2a9c3b3d894c002a ("*"?)
$rdi   : 0x0               
$rip   : 0x00007f6814bc3ab7  →   ret
$r8    : 0x00007f68152da880  →  0x00007f68152da880  →  [loop detected]
$r9    : 0x0               
$r10   : 0x00007f6814c49840  →   add BYTE PTR [rax], al
$r11   : 0x[PII_REDACTED]000246
$r12   : 0x00007f6814bc4810  →   push rbp
$r13   : 0x0               
$r14   : 0x0               
$r15   : 0x0               
$eflags: [zero carry PARITY adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000
───────────────────────────────────────────────────────────────────── stack ────
0x00007ffe8c136818│+0x0000: 0x00007f6814bc3b09  →   nop    ← $rsp
0x00007ffe8c136820│+0x0008: 0x00007f6814bc3060  →   sub rsp, 0x8
0x00007ffe8c136828│+0x0010: 0x00007f6814bc4089  →   mov edi, eax
0x00007ffe8c136830│+0x0018: 0x[PII_REDACTED]000000
0x00007ffe8c136838│+0x0020: 0x[PII_REDACTED]000000
0x00007ffe8c136840│+0x0028: 0x00007ffe8c136948  →  0x00007ffe8c1373de  →  "./onewrite"
0x00007ffe8c136848│+0x0030: 0x00007f6814bc3ab8  →   sub rsp, 0x8
0x00007ffe8c136850│+0x0038: 0x[PII_REDACTED]000000
─────────────────────────────────────────────────────────────── code:x86:64 ────
   0x7f6814bc3aad                  call   0x7f6814bc39c3
   0x7f6814bc3ab2                  nop    
   0x7f6814bc3ab3                  add    rsp, 0x18
 → 0x7f6814bc3ab7                  ret    
   ↳  0x7f6814bc3b09                  nop    
      0x7f6814bc3b0a                  add    rsp, 0x8
      0x7f6814bc3b0e                  ret    
      0x7f6814bc3b0f                  nop    
      0x7f6814bc3b10                  push   rbx
      0x7f6814bc3b11                  sub    rsp, 0x88
─────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "onewrite", stopped, reason: BREAKPOINT
───────────────────────────────────────────────────────────────────── trace ────
[#0] 0x7f6814bc3ab7 → ret
[#1] 0x7f6814bc3b09 → nop
[#2] 0x7f6814bc3060 → sub rsp, 0x8
[#3] 0x7f6814bc4089 → mov edi, eax
────────────────────────────────────────────────────────────────────────────────
gef➤  i f
Stack level 0, frame at 0x7ffe8c136818:
 rip = 0x7f6814bc3ab7; saved rip = 0x7f6814bc3b09
 called by frame at 0x7ffe8c136828
 Arglist at 0x7ffe8c136810, args:
 Locals at 0x7ffe8c136810, Previous frame's sp is 0x7ffe8c136820
 Saved registers:
  rip at 0x7ffe8c136818
```

So we can see that the saved return address is stored at `0x7ffe8c136818` and points to `0x7f6814bc3b09`. That address corresponds to `0x00108b09` in `do_leak`. The address we leaked was `0x7ffe8c136800`. Then the offset to the saved return address for `do_leak` from the address we have leaked is `0x7ffe8c136818 - 0x7ffe8c136800 = 0x18`

```
        00108aff e8 5c 84        CALL       puts                                             int puts(char * __s)
                 00 00
        00108b04 e8 0c ff        CALL       do_leak                                          undefined do_leak()
                 ff ff
        00108b09 90              NOP
        00108b0a 48 83 c4 08     ADD        RSP,0x8
```

What we can do here is a partial overwrite. That is where we only overwrite only a part of the saved return instruction. Because PIE works by addressing all instructions to an address and adding that to whatever the base