babygame01

July 7, 20256 minutes
En este challenge no se proporciona código
Renombrar variables y entender el código
main
undefined4 main(void)
{
int iVar1;
undefined4 uVar2;
int in_GS_OFFSET;
int local_aac;
int local_aa8;
char local_aa4;
undefined local_aa0 [2700];
int local_14;
undefined *local_10;
local_10 = &stack0x00000004;
local_14 = *(int *)(in_GS_OFFSET + 0x14);
init_player(&local_aac);
init_map(local_aa0,&local_aac);
print_map(local_aa0,&local_aac);
signal(2,sigint_handler);
do {
do {
iVar1 = getchar();
move_player(&local_aac,(int)(char)iVar1,local_aa0) ;
print_map(local_aa0,&local_aac);
} while (local_aac != 0x1d);
} while (local_aa8 != 0x59);
puts("You win!");
if (local_aa4 != '\0') {
puts("flage");
win();
fflush(_stdout);
}
uVar2 = 0;
if (local_14 != *(int *)(in_GS_OFFSET + 0x14)) {
uVar2 = __stack_chk_fail_local();
}
return uVar2;
}
La variable local_aa0
tiene pinta que es la que almacena el mapa del juego
undefined local_aa0 [2700];
undefined mapa [2700];
En iVar1 se guarda el input de donde queremos ir
iVar1 = getchar();
move = getchar();
En la función move_player() se le pasa el movimiento, mapa y local_aac que tiene pinta de ser la posición del jugador.
move_player(&local_aac,(int)(char)move,mapa);
move_player(&pos_player,(int)(char)move,mapa);
Más abajo se valida si hemos llegado a la posición objetivo, de caso contrario sigue el bucle del programa. Por como está escrito parece que pos_player es la x, y local_aa8 es la y
} while (pos_player != 0x1d);
} while (local_aa8 != 0x59);
¿Pero entonces porque en move_player
se pasa solo la x? Lo que puede ser es que pos_player sea una lista de 2 ints int pos_player[2];
asi que local_aa8 = pos_player[1] y pos_player = pos_player[0]
} while (pos_player[0] != 0x1d);
} while (pos_player[1] != 0x59);
move_player
void move_player(int *pos_player,char move,int mapa)
{
int iVar1;
if (move == 'l') {
iVar1 = getchar();
player_tile = (undefined)iVar1;
}
if (move == 'p') {
solve_round(mapa,pos_player);
}
*(undefined *)(*pos_player * 0x5a + mapa + pos_play er[1]) = 0x2e;
if (move == 'w') {
*pos_player = *pos_player + -1;
}
else if (move == 's') {
*pos_player = *pos_player + 1;
}
else if (move == 'a') {
pos_player[1] = pos_player[1] + -1;
}
else if (move == 'd') {
pos_player[1] = pos_player[1] + 1;
}
*(undefined *)(*pos_player * 0x5a + mapa + pos_play er[1]) = player_tile;
return;
}
- Si el carácter previamente introducido es l, nos piden otro carácter que va a ser el icono de la posición del jugador (default: @).
- Si se había puesto una p, llama a solve_round, que básicamente te lleva automáticamente a la posición final
- Con w,a,s,d simplemente hace el movimiento en esa dirección
if (move == 'w') {
*pos_player = *pos_player + -1;
}
else if (move == 's') {
*pos_player = *pos_player + 1;
}
else if (move == 'a') {
pos_player[1] = pos_player[1] + -1;
}
else if (move == 'd') {
pos_player[1] = pos_player[1] + 1;
}
print_map
En la función print_mapa se imprime el mapa, justamente se hace un bucle de 30*90 que es igual a 2700 que es el tamaño que tenía mapa, así que podemos confirmar que realmente esa variable era el mapa
void print_map(int mapa,undefined4 pos_player)
{
int y;
int x;
clear_screen();
find_player_pos(mapa);
find_end_tile_pos(mapa);
print_flag_status(pos_player);
for (y = 0; y < 30; y = y + 1) {
for (x = 0; x < 90; x = x + 1) {
putchar((int)*(char *)(x + mapa + y * 0x5a));
}
putchar(10);
}
fflush(_stdout);
return;
}
find_player_pos
void find_player_pos(int mapa)
{
int y;
int x;
y = 0;
do {
if (29 < y) {
return;
}
for (x = 0; x < 90; x = x + 1) {
if (*(char *)(x + mapa + y * 90) == player_tile) {
printf("Player position: %d %d\n",y,x);
return;
}
}
y = y + 1;
} while( true );
}
Itera todo el mapa para buscar si en la array mapa hay un carácter igual a player_tile, player_tile es el carácter del jugador (default: @). Si lo encuentra entiende que el jugador está en esa posición. Esto significa que el player_tile se escribe directamente en la array mapa, en su posición correspondiente, después de hacer un movimiento. Volviendo a la función move_player(), al final del todo hay
*(undefined *)(*pos_player * 0x5a + mapa + pos_player[1]) = player_tile;
Esto escribe el carácter que representa al jugador (default: @) en la posición literal en la array 2d mapa, de forma simplificada sería como, mapa[227] = player_tile
Se está tomando los valores de pos_player directamente como posiciones dentro de mapa, pero en move_player al presionar cualquier tecla, se suma pos_player[x] + 1
o pos_player[x] - 1
, pero en ningún momento se valida si se excede el rango de la array.
Explotación
Entonces si nos ponemos en la posición 0 de la array mapa y vamos dándole a la a para ir atrás de array podemos llegar a sobreescribir otras variables.
Para comprobar esto me puse de player_tile la letra A
lA
Y me fui a arriba a la izquierda del mapa y fui retrocediendo posición por posición y en la cuarta a, el valor de “player has flag” paso a 65
Player has flag: 65
Justamente A en ascii es 65
$ ascii -d
0 NUL 16 DLE 32 48 0 64 @ 80 P 96 ` 112 p
1 SOH 17 DC1 33 ! 49 1 65 A 81 Q 97 a 113 q
2 STX 18 DC2 34 " 50 2 66 B 82 R 98 b 114 r
3 ETX 19 DC3 35 # 51 3 67 C 83 S 99 c 115 s
4 EOT 20 DC4 36 $ 52 4 68 D 84 T 100 d 116 t
5 ENQ 21 NAK 37 % 53 5 69 E 85 U 101 e 117 u
6 ACK 22 SYN 38 & 54 6 70 F 86 V 102 f 118 v
7 BEL 23 ETB 39 ' 55 7 71 G 87 W 103 g 119 w
8 BS 24 CAN 40 ( 56 8 72 H 88 X 104 h 120 x
9 HT 25 EM 41 ) 57 9 73 I 89 Y 105 i 121 y
10 LF 26 SUB 42 * 58 : 74 J 90 Z 106 j 122 z
11 VT 27 ESC 43 + 59 ; 75 K 91 [ 107 k 123 {
12 FF 28 FS 44 , 60 < 76 L 92 \ 108 l 124 |
13 CR 29 GS 45 - 61 = 77 M 93 ] 109 m 125 }
14 SO 30 RS 46 . 62 > 78 N 94 ^ 110 n 126 ~
15 SI 31 US 47 / 63 ? 79 O 95 _ 111 o 127 DEL
Así que hemos puesto player_tile en la variable que almacena lo que se printea como “player has flag”
Volviendo a main
do {
do {
move = getchar();
move_player(&pos_player[0],(int)(char)move,mapa) ;
print_map(mapa,&pos_player[0]);
} while (pos_player[0] != 29);
} while (pos_player[1] != 89);
puts("You win!");
if (has_flag != '\0') {
puts("flage");
win();
fflush(_stdout);
}
Lo que necesitamos para llegar a win es llegar a “x = 29”, “y = 89” y que has_flag sea distinto de 0
Payload final:
wwwwaaaaaaaap
- wwwwaaaa: Llegar hasta map[0]
- aaaa: Retroceder hasta la variable has_flag y sobreescribirla
- p: Usar la opción para que se solucione solo y llege hasta “x = 29” y “y = 89”
You win!
flage
PICOCTF{FLAGGG}