Skip to content

flip-out

Category: Pwn

Description

My friend made this app with a flag in it...

nc tjc.tf 31601

Attachments: chall

Write-up

Let's proceed with analyzing the binary using Ghidra. This is the generated pseudocode for the main() function:

Text Only
undefined8 main(void)

{
  uint uVar1;
  FILE *__stream;
  undefined8 uVar2;
  long in_FS_OFFSET;
  undefined8 local_b8;
  undefined8 local_b0;
  undefined8 local_a8;
  undefined8 local_a0;
  undefined8 local_98;
  undefined8 local_90;
  undefined8 local_88;
  undefined8 local_80;
  undefined8 local_78;
  undefined8 local_70;
  undefined8 local_68;
  undefined8 local_60;
  undefined8 local_58;
  undefined8 local_50;
  undefined8 local_48;
  undefined8 local_40;
  undefined8 local_38;
  undefined local_30;
  undefined7 uStack_2f;
  undefined uStack_28;
  undefined8 local_27;
  long local_10;

  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  setbuf(stdout,(char *)0x0);
  local_b8 = 0x20676e6968746f4e;
  local_b0 = 0x6820656573206f74;
  local_a8 = 0x4e202e2e2e657265;
  local_a0 = 0x7420676e6968746f;
  local_98 = 0x656820656573206f;
  local_90 = 0x2e2e2e6572;
  local_88 = 0;
  local_80 = 0;
  local_78 = 0;
  local_70 = 0;
  local_68 = 0;
  local_60 = 0;
  local_58 = 0;
  local_50 = 0;
  local_48 = 0;
  local_40 = 0;
  local_38 = 0;
  local_30 = 0;
  uStack_2f = 0;
  uStack_28 = 0;
  local_27 = 0;
  __stream = fopen("flag.txt","r");
  if (__stream == (FILE *)0x0) {
    printf("Cannot find flag.txt.");
    uVar2 = 1;
  }
  else {
    fgets((char *)&local_38,0x19,__stream);
    fclose(__stream);
    printf("Input: ");
    __isoc99_scanf(&DAT_0010202d,&local_b8);
    uVar1 = atoi((char *)&local_b8);
    if ((int)uVar1 < 129) {
      printf("%s",(long)&local_b8 + (long)(int)(uVar1 & 0xff));
      uVar2 = 0;
    }
    else {
      uVar2 = 0;
    }
  }
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return uVar2;
}

From the pseudocode, we can observe that the program reads the content of the flag.txt file and stores it in the local_38 variable.

Additionally, the user input is read and saved into the local_b8 variable. It is then casted as a signed integer and stored in uVar1. If uVar1 is less than 129, the program will print the string content at the memory location &local_b8 + (uVar1 & 0xff). The uVar1 & 0xff operation ensures that the offset added to local_b8 is at most 1 byte in size. Since our input should be less than 129, we can ignore the & 0xff part.

To make the program print the string content stored in the local_38 variable, i.e. our flag, we need to ensure that &local_b8 + uVar1 == &local_38. The stack layout in the following image illustrates the variables involved:

By observing the difference from &local_b8 to &local_38 (which is 0x80 or 128), we can conclude that specifying the input as 128 will yield the flag.

Flag: tjctf{chop-c4st-7bndbji}