PLT_PlayIT

Deals with GOT overwrite by utlizing Write-What-where primitive

In this binary, we can see in line 18, local_28 bariable (which is only 8 bytes) is allowed to write 24 bytes in the memroy. What this will essentially do is overwrite local_20 and local_18 variables too which are the subsequent 8 bytes each variable in memory (making total 24 bytes).

But we see that local_18 is a pointer. So we can overwrite it's value with an address.

Now in line 20, we see the value of local_18 is assigned as local_28. So at the address pointed by local_18, local_28 will be written to. And look at line 21, at the address pointed by local_18[1] (as in local_18 + 8 bytes) local_20 is being written to.

This allows us to utilize the "Write What Where" exploit primitive. We can write essentially 2 values in memory.

local_28 -> Written in addr (*local_18)

local_20 -> Written in addr + 8 (local_18[1])

Input would be: local_28 (8 bytes) + local_20 (8 bytes) + local_18 (8 bytes)

So, essentially we have to craft a payload which would:

  1. Write a malicious shellcode (or shell giving string) to a location

  2. Have it called using system()

  3. Overwrite GOT of a function by system. SHould be a function which comes after the initialization of local_28, local_20 and local_18

Let's write "/bin/sh" somewhere in memory whose next 8 bytes and should be overwritten by system's PLT stub function.

This makes it simple. Only puts comes after initialization and is operating on local_28. So, local_28 becomes "/bin/sh". puts() is to be replcaced with system()'s PLT stub address

Upon exploring Ghidra I see one such prominent location at address 00601010:

So, the payload becomes: "/bin/sh" + PLT STUB address of System() + 0x00601010

This would mean that 00601010 would be written with "/bin/sh"

00601010 + 8 (which is puts()) would be overwritten by PLT stub of system()

Essentially when puts(local_28) will be called, system(local_28) will execute.

System@plt is at:

The same could be done using pwntools:

So, exploit becomes: "/bin/sh" + 0x00000000004005d0 + 0x0000000000601010

I am representing the addresses in 64 bit value (8 byte addresses)

Let's whip up pwntools in python3 and let me guide you through my exploit dev

  1. Made the payload but only interacting with binary intially to see how it reacts first before sending in the payload. Adding a \x00 terminated the string (/bin/sh) and is exactly 8 bytes long too.

  1. It is taking input after it says "to save: ". Let's incorporate that in code

  1. After it says that, I have to give an input. I use sendline to provide payload as an input.

  1. But where is the shell? The process breaks the execution after input so we can use interactive() to interact with the process after our input.

But let me first set a SUID bit on this binary and run the exploit as a low priv user, so that when exploit works, I get a root shell. I'll also add a flag.txt file that can only be read by the root user.

Let me also set SUID on local.py

  1. Now it looks like this:

  1. Cool, let's give it a whirl.

Let's run this on our remote server with a few alterations

There we go. That's how I pwned playit using write-what-where primitive to overwrite GOT for puts and replace by system() to get the flag eventually!

Last updated