piątek, 12 września 2025

picoCTF - PIE TIME

W tym poście chciałbym opisać rozwiązanie zadania PIE TIME z działu Binary Exploitation PicoCTF.


Do zadania dołączony został kod w C oraz skompilowany projekt. 
Kod w C wygląda następująco:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <signal.h>
  4. #include <unistd.h>
  5.  
  6. void segfault_handler() {
  7.   printf("Segfault Occurred, incorrect address.\n");
  8.   exit(0);
  9. }
  10.  
  11. int win() {
  12.   FILE *fptr;
  13.   char c;
  14.  
  15.   printf("You won!\n");
  16.   // Open file
  17.   fptr = fopen("flag.txt", "r");
  18.   if (fptr == NULL)
  19.   {
  20.       printf("Cannot open file.\n");
  21.       exit(0);
  22.   }
  23.  
  24.   // Read contents from file
  25.   c = fgetc(fptr);
  26.   while (c != EOF)
  27.   {
  28.       printf ("%c", c);
  29.       c = fgetc(fptr);
  30.   }
  31.  
  32.   printf("\n");
  33.   fclose(fptr);
  34. }
  35.  
  36. int main() {
  37.   signal(SIGSEGV, segfault_handler);
  38.   setvbuf(stdout, NULL, _IONBF, 0); // _IONBF = Unbuffered
  39.  
  40.   printf("Address of main: %p\n", &main);
  41.  
  42.   unsigned long val;
  43.   printf("Enter the address to jump to, ex => 0x12345: ");
  44.   scanf("%lx", &val);
  45.   printf("Your input: %lx\n", val);
  46.  
  47.   void (*foo)(void) = (void (*)())val;
  48.   foo();
  49. }

Jak widać w kodzie naszym zadaniem jest wprowadzenie poprawnego adresu aby wywołać funkcję win(), która otworzy plik z flagą i ją wyświetli.

Po uruchomieniu programu na środowisku otrzymujemy następujący komunikat:

  1. Address of main: 0x5ff0beec033d
  2. Enter the address to jump to, ex => 0x12345:

Format adresu wskazuje, że jest to system 64 bitowy. 

Jeśli wprowadzimy błędny adres wyświetli się informacja "Segfault Occured.."

Można wykorzystać decompiler online, ponieważ musimy znaleźć adresy funkcji win oraz main. 


  1. //----- (00000000000012A7) ----------------------------------------------------
  2. int win()
  3. {...}
  4.  
  5. //----- (000000000000133D) ----------------------------------------------------
  6. int __fastcall main(int argc, const char **argv, const char **envp)
  7. {...}

Jak widać win ma adres 12A7, natomiast main 133D. Przesunięcie miedzy nimi wynosi 0x133D - 0x12A7 = 0x96. 

Wprowadzenie adresu 0x12A7 nie będzie działało poprawnie, ponieważ musimy znać adres na jakim program jest ładowany do pamięci. Czyli adres będzie adresem bazowym przesuniętym o adres funkcji main. Przesunięcie nie ulegają zmianie, ponieważ są przygotowywane podczas kompilacji programu a nie jego uruchomienia. 

Dla powyższego przypadku adres wynosi 0x5FF0BEEC033D. Od niego należy odjąć wartość przesunięcia między funkcjami czyli 0x96 co w tym przypadku da wartość 5FF0BEEC02A7.

  1. picoctf@webshell:~$ nc rescued-float.picoctf.net <port>
  2. Address of main: 0x5ff0beec033d
  3. Enter the address to jump to, ex => 0x12345: 0x5FF0BEEC02A7
  4. Your input: 5ff0beec02a7
  5. You won!
  6. picoCTF{<flaga>}