Skip to main content
  1. Writeups/

Angry

BuckeyeCTF 2022 216 Points 69 Solves
 Author
Author
mouthon
Hacker

A reverse challenge that highly suggested to use symbolic excecution, but it was easily doable without it.

Challenge description
#

Fight anger with angr Associated file: angry

First inspection
#

$ file Angry 
Angry: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=722f16df6b8b09063ca2c42ce04d8d1930eba1c8, for GNU/Linux 3.2.0, stripped
$ ./Angry 
Welcome to Angry Frob, not your normal frob.
The special number today is... 42
Enter something for us to frobnicate: 
test
Failure, you didn't send an interesting string.
$ strings Angry
[...]
Welcome to Angry Frob, not your normal frob.
The special number today is... %d
Enter something for us to frobnicate: 
Congratulations, you found the special string to frob.
Failure, you didn't send an interesting string.
[...]

Ok, it seems like we have to reach the part where “Congratulations” is printed.

Decompiling with Ghidra
#

The code is pretty short, and after some renaming and retyping of the variables, we get the following :

uint encode_char(byte c,byte key)

{
  return (int)(uint)c >> (8 - key % 8 & 0x1f) | (uint)c << key % 8;
}

void encode(char *string_io,char key)

{
  char cVar1;
  size_t len;
  char local_15;
  int i;
  
  len = strlen(string_io);
  local_15 = key;
  for (i = 0; (ulong)(long)i < len; i = i + 1) {
    cVar1 = encode_char(string_io[i],local_15);
    string_io[i] = cVar1;
    local_15 = string_io[i];
  }
  return;
}

int main(void)

{
  int iVar1;
  size_t len;
  size_t lenFlag;
  long in_FS_OFFSET;
  char guess [104];
  long local_20;
  
  local_20 = *(long *)(in_FS_OFFSET + 0x28);
  puts("Welcome to Angry Frob, not your normal frob.");
  printf("The special number today is... %d\n",0x2a);
  puts("Enter something for us to frobnicate: ");
  fgets(guess,99,stdin);
  len = strcspn(guess,"\n");
  guess[len] = '\0';
  encode(guess,0x2a);
  len = strlen(guess);
  lenFlag = strlen(&DAT_00104020);
  if (len == lenFlag) {
    iVar1 = strcmp(guess,&DAT_00104020);
    if (iVar1 == 0) {
      puts("Congratulations, you found the special string to frob.");
      goto LAB_001013d4;
    }
  }
  puts("Failure, you didn\'t send an interesting string.");
LAB_001013d4:
  if (local_20 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}

So encode_char is just a leftRotate, that’s easy to inverse. Then encode has an initialization byte, and then use the previous cipher byte to encode the next plain byte. The resulting encoded string is compared to a string hold in the binary, that we can extract with Ghidra.

Decoding with Python
#

We implement the decoding in this script. Running it gives us the flag: buckeye{st!ll_b3tt3r_th4n_strfry}

Other writeups of challenges from BuckeyeCTF 2022.
Angry