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:
- #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();
- }
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:
- Address of main: 0x5ff0beec033d
- 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.
- //----- (00000000000012A7) ----------------------------------------------------
- int win()
- {...}
- //----- (000000000000133D) ----------------------------------------------------
- int __fastcall main(int argc, const char **argv, const char **envp)
- {...}
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.
- picoctf@webshell:~$ nc rescued-float.picoctf.net <port>
- Address of main: 0x5ff0beec033d
- Enter the address to jump to, ex => 0x12345: 0x5FF0BEEC02A7
- Your input: 5ff0beec02a7
- You won!
- picoCTF{<flaga>}