PIE TIME

https://play.picoctf.org/practice/challenge/490arrow-up-right

📂 Category

Binary Exploitation

🔍 Source Code Analysis

We begin by analyzing the provided source code to understand the program's logic, identify potential vulnerabilities, and determine the possible attack vectors

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void segfault_handler() {
  printf("Segfault Occurred, incorrect address.\n");
  exit(0);
}

int win() {
  FILE *fptr;
  char c;

  printf("You won!\n");
  // Open file
  fptr = fopen("flag.txt", "r");
  if (fptr == NULL)
  {
      printf("Cannot open file.\n");
      exit(0);
  }

  // Read contents from file
  c = fgetc(fptr);
  while (c != EOF)
  {
      printf ("%c", c);
      c = fgetc(fptr);
  }

  printf("\n");
  fclose(fptr);
}

int main() {
  signal(SIGSEGV, segfault_handler);
  setvbuf(stdout, NULL, _IONBF, 0); // _IONBF = Unbuffered

  printf("Address of main: %p\n", &main);

  unsigned long val;
  printf("Enter the address to jump to, ex => 0x12345: ");
  scanf("%lx", &val);
  printf("Your input: %lx\n", val);

  void (*foo)(void) = (void (*)())val;
  foo();
}

⚙️ How the Program Works

The binary functions as follows:

  1. It prints the memory address of the main() function in hexadecimal format.

  2. It then prompts the user to enter a target address (also in hex).

  3. Finally, it attempts to call the function located at the address provided by the user.

From the provided source code, we observe that there is a function named win(), which prints the flag when executed. However, this function is not called anywhere within the main() function.

The interesting part is that the program allows the user to provide a memory address, and it will attempt to call the function located at that address. This is the vulnerability we can exploit.

🎯 Objective

Our goal is to find the memory address of the win() function and input it when prompted, causing the binary to execute win() and print the flag.


🛠️ How to Find the Address of win()

Although the program prints the address of main(), we still need the exact memory address of win().

To do this, we can analyze the binary using gdb (GNU Debugger).

The main address is 0x55555555533d . Let's disassemble main and confirm that

When the binary is executed, it prints the address of the main() function. This confirms that the printed address is indeed that of main() in memory.

Now, to reach the win() function, we can calculate the offset between main() and win(), and use it to determine the memory address of win() at runtime.

  • Main function address: 0x000055555555533d

  • Win function address: 0x00005555555552a7

Great! Since the offset is 150 bytes (0x96 in hex), and the binary allows us to input a function pointer, we can write a simple exploit script :

WOOHOO we got our flag

Last updated