Skip to content

Latest commit

 

History

History
87 lines (74 loc) · 2.86 KB

janken.md

File metadata and controls

87 lines (74 loc) · 2.86 KB

Janken (easy)

For this challenge we get a binary that will be running on the remote.

First I check the rules of the game, and it seems like a rock, paper, scissors game. When playing we can type rock, paper, scissors, the opponent will guess as well and we need to win 100 times. Let's see how the game is implemented in ghidra

  for (; rounds < 100; rounds = rounds + 1) {
    fprintf(stdout,"\n[*] Round [%d]:\n",rounds);
    game();
  }

In main we see that the game function is called 100 times, let's see what the game function does.

  tVar2 = time((time_t *)0x0);
  srand((uint)tVar2);
  iVar1 = rand();
  local_78[0] = "rock";
  local_78[1] = "scissors";
  local_78[2] = "paper";
  local_38 = 0;
  local_30 = 0;
  local_28 = 0;
  local_20 = 0;
  local_58[0] = "paper";
  local_58[1] = "rock";
  local_58[2] = "scissors";
  fwrite(&DAT_00102540,1,0x33,stdout);
  read(0,&local_38,0x1f);
  fprintf(stdout,"\n[!] Guru\'s choice: %s%s%s\n[!] Your  choice: %s%s%s",&DAT_00102083,
          local_78[iVar1 % 3],&DAT_00102008,&DAT_0010207b,&local_38,&DAT_00102008);
  local_88 = 0;
  do {
    sVar4 = strlen((char *)&local_38);
    if (sVar4 <= local_88) {
LAB_001017a2:
      pcVar5 = strstr((char *)&local_38,local_58[iVar1 % 3]);
      if (pcVar5 == (char *)0x0) {
        fprintf(stdout,"%s\n[-] You lost the game..\n\n",&DAT_00102083);
                    /* WARNING: Subroutine does not return */
        exit(0x16);
      }
      fprintf(stdout,"\n%s[+] You won this round! Congrats!\n%s",&DAT_0010207b,&DAT_00102008);
      if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
        __stack_chk_fail();
      }
      return;
    }
    ppuVar3 = __ctype_b_loc();
    if (((*ppuVar3)[*(char *)((long)&local_38 + local_88)] & 0x2000) != 0) {
      *(undefined *)((long)&local_38 + local_88) = 0;
      goto LAB_001017a2;
    }
    local_88 = local_88 + 1;
  } while( true );

First our input is read, and the opponent chooses a random move. local_78 is the array of moves for the opponent. At matching indices local_58 contains the winning moves that we need to make, important to note how a draw counts as a lose for some reason.

But look at what function is used! strstr looks for the second argument in the first argument, and returns the index of the first occurrence or NULL if not found.

Now notice how when reading user input 0x1f bytes are read.

We can just send rockpaperscissors on each choice and it would surely contain the winning move!

from pwn import *
p = remote('165.227.224.40', 30509)

payload = 'rockpaperscissors'
p.sendlineafter(b'>>', b'1')

for i in range(99):
    p.sendlineafter(b'>>', b'rockpaperscissors')
    print(f'sent {i}')
p.interactive()

For some reason there was an issue with sending this 100 times, so I decreased the count to 99

After this the opponent gives us the flag.