W tym poście chciałbym opisać rozwiązanie zadania babygame01 z picoCTF
Wykorzystam dekompiler online. W nim wybrałem Ghirda i Hex-Rays.
Po sprawdzeniu kodu znajduje funkcje odpowiedzialną za obsługę klawiszy w grze:
- void move_player(int *param_1,char param_2,int param_3)
- {
- int iVar1;
- if (param_2 == 'l') {
- iVar1 = getchar();
- player_tile = (undefined)iVar1;
- }
- if (param_2 == 'p') {
- solve_round(param_3,param_1);
- }
- *(undefined *)(*param_1 * 0x5a + param_3 + param_1[1]) = 0x2e;
- if (param_2 == 'w') {
- *param_1 = *param_1 + -1;
- }
- else if (param_2 == 's') {
- *param_1 = *param_1 + 1;
- }
- else if (param_2 == 'a') {
- param_1[1] = param_1[1] + -1;
- }
- else if (param_2 == 'd') {
- param_1[1] = param_1[1] + 1;
- }
- *(undefined *)(*param_1 * 0x5a + param_3 + param_1[1]) = player_tile;
- return;
- }
Funkcja wprowadza parametry param_1 i param_3 bezpośrednio do obliczania kolejnego położenia gracza. W powyższym kodzie nie widać żadnej metody weryfikacji obliczonej pozycji.
Jak można zaobserwować powyżej są dwie dodatkowe opcje w menu czyli klawisze 'p' oraz 'l'. Pierwszy nich przenosi gracze na pole zwycięzcy. Drugi pozwala na zmianę litery gracza. Żaden z nich nie zapewnia wygranej.
Funckja odpowiadająca za inicjalizację mapy:
- void init_map(int param_1,int *param_2)
- {
- int local_10;
- int local_c;
- for (local_10 = 0; local_10 < 0x1e; local_10 = local_10 + 1) {
- for (local_c = 0; local_c < 0x5a; local_c = local_c + 1) {
- if ((local_10 == 0x1d) && (local_c == 0x59)) {
- *(undefined *)(param_1 + 0xa8b) = 0x58;
- }
- else if ((local_10 == *param_2) && (local_c == param_2[1])) {
- *(undefined *)(local_c + param_1 + local_10 * 0x5a) = player_tile;
- }
- else {
- *(undefined *)(local_c + param_1 + local_10 * 0x5a) = 0x2e;
- }
- }
- }
- return;
- }
Odczytanie flagi:
- if (local_aa4 != '\0') {
- puts("flage");
- win();
- fflush(_stdout);
- }
Czyli zmienna local_aa4 musi być różna od zera w celu odczytania flagi.
- char local_aa4;
- undefined local_aa0 [2700];
Wynika z tego, że zmienna local_aa4 jest zapisana na stosie za zmienna local_aa0. Tablica local_aa0 jest tablicą wykorzystywaną do inicjalizacji planszy (29x89 z zapasem). Wobec tego aby wprowadzić dane do wartości local_aa4, tak aby nie była wartością zerową, należy cofnąć się poza plansze. Dokładnie poniżej punktu zerowego.