PIE TIME

pico
pwn

August 5, 20252 minutes

#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();
}

Este binario está compilado con PIE (Position Independent Executable), lo que permite que sus direcciones en memoria sean aleatorizadas en tiempo de ejecución mediante ASLR (Address Space Layout Randomization)."

El programa muestra una dirección que va cambiando por cada ejecución, esa dirección es la que apunta a la función main. Para sacar la base del PIE que aleatoriza las direcciones hay que restarle a la dirección proporcionada el offset de main, dando como resultado la dirección base del PIE

pwndbg> disass main
Dump of assembler code for function main:
   0x000000000000133d <+0>:	endbr64
>>> hex(0x556e594b233d - 0x000000000000133d)
'0x556e594b1000'

Una vez obtenida la base de PIE, se puede calcular cuál será la dirección de la función win que es la que muestra la flag

pwndbg> disass win
Dump of assembler code for function win:
   0x00000000000012a7 <+0>:	endbr64
>>> hex(0x556e594b1000 + 0x00000000000012a7)
'0x556e594b22a7'

Ahora si al binario se le pasara 0x556e594b22a7 mostraria la falg