Baby Rev - SMP CTF 2024 - Selection Round

Posted on by NomanProdhan

Greetings, crackers!

I’ve created this beginner friendly Reverse Engineering challenge for the SMP CTF 2024 - Selection Round. Here’s a detailed explanation to guide you through solving it.

When you execute the binary, it prompts you to enter a flag. Your task is to figure out the correct flag to provide.

So lets reverse the binary to get the correct flag...

Upon opening the provided binary in Ghidra, you’ll notice that the main() function appears somewhat like this:

undefined8 main(void)

{
  size_t sVar1;
  char *pcVar2;
  undefined8 uVar3;
  size_t sVar4;
  long in_FS_OFFSET;
  ulong local_78;
  undefined8 local_68;
  undefined8 local_60;
  char local_58 [72];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  local_68 = 0x633563607c514e54;
  local_60 = 0x7e60773453607a;
  sVar1 = strlen((char *)&local_68);
  printf("Enter the flag: ");
  pcVar2 = fgets(local_58,0x40,stdin);
  if (pcVar2 == (char *)0x0) {
    puts("Error reading input.");
    uVar3 = 1;
  }
  else {
    sVar4 = strcspn(local_58,"\n");
    local_58[sVar4] = '\0';
    sVar4 = strlen(local_58);
    if (sVar1 == sVar4) {
      for (local_78 = 0; local_78 < sVar1; local_78 = local_78 + 1) {
        if ((char)(*(char *)((long)&local_68 + local_78) + -1) != local_58[local_78]) {
          puts("Incorrect flag.");
          uVar3 = 1;
          goto LAB_001012c3;
        }
      }
      puts("Correct flag!");
      uVar3 = 0;
    }
    else {
      puts("Incorrect flag.");
      uVar3 = 1;
    }
  }
LAB_001012c3:
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return uVar3;
}

The program initializes two 64-bit variables, local_68 and local_60, with hexadecimal values:

  local_68 = 0x633563607c514e54;
  local_60 = 0x7e60773453607a;

When these hexadecimal values are converted to characters, you will get characters like the following:

  local_68 = c5c`|QNT;
  local_60 = ~`w4S`z;

It's important to note that these two variables (local_68 and local_60) together act as a single variable, effectively forming a continuous sequence of characters.

Next, the program takes user input and stores it in the local_58 variable. It then checks if the length of the string in local_58 matches the combined length of local_68 and local_60.

Since the combined length of local_68 and local_60 is 15 characters, the flag we need to provide must also be 15 characters long.

    if (sVar1 == sVar4) { ## Checking the length if it is 15 chars long
      for (local_78 = 0; local_78 < sVar1; local_78 = local_78 + 1) {
        if ((char)(*(char *)((long)&local_68 + local_78) + -1) != local_58[local_78]) {
          puts("Incorrect flag.");
          uVar3 = 1;
          goto LAB_001012c3;
        }
      }
      puts("Correct flag!");
      uVar3 = 0;
    }

After comparing the length of the input string (local_58) with the combined length of local_68 and local_60, the program performs the following:

  • It iterates through each character of local_68 and local_60 combined (acting as a single variable).
  • For each character, it subtracts 1 from its ASCII value and compares the result with the corresponding character in the user input (local_58).
  • If all characters match after the subtraction, the program outputs "Correct flag!". Otherwise, it displays "Incorrect flag."

This means if we simply subtract 1 from each character of local_68 and local_60, we will get the actual flag. However, since the variables are stored in little-endian format, we first need to reverse the order of the characters in each string. Once reversed, the two strings are combined, and then the subtraction operation is applied to each character to produce the final flag.

Here’s a Python script to generate the flag:


#!/usr/bin/env python

# Strings from local_68 and local_60 in little-endian format
local_68 = "c5c`|QNT"
local_60 = "~`w4S`z"

# Reverse each string to handle the little-endian format
reversed_local_68 = local_68[::-1]
reversed_local_60 = local_60[::-1]

# Combine the reversed strings
combined_chars = reversed_local_68 + reversed_local_60

# Subtract 1 from each character to generate the flag
flag = ''.join(chr(ord(c) - 1) for c in combined_chars)

print(f"The generated flag is: {flag}")

I hope you enjoyed the challenge and writeup.

Happy Cracking 🤟