51ng3

Squirrel CTF 2025

calendar icon 3-5 Mars 2025 author icon NaNoBlaze tag icon Web, reverse, Pwn

Writeup for Squirrel CTF 2025

Summary

Pwn

Reverse

IA

dejavu

The challenge give us a small program :

void win(void)

{
  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;
  undefined8 local_30;
  undefined8 local_28;
  undefined8 local_20;
  undefined4 local_18;
  FILE *local_10;
  
  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;
  local_28 = 0;
  local_20 = 0;
  local_18 = 0;
  puts("You got it!!");
  local_10 = (FILE *)FUN_00401100("flag.txt",&DAT_00402015);
  if (local_10 == (FILE *)0x0) {
    puts("Error: Could not open flag.txt (create this file for testing)");
  }
  else {
    fgets((char *)&local_78,100,local_10);
    printf("%s",&local_78);
    fclose(local_10);
  }

This is the main
undefined8 main(void)

{
  char local_48 [64];
  
  setbuf(stdout,(char *)0x0);
  setbuf(stdin,(char *)0x0);
  printf("pwnme: ");
  gets(local_48);
  return 0;
}
}

Quickly, we can see that me need to overflow the function to get the flag (gets() is a really bad function, here there is no verification of the input from the user). I used gdb to help me and quickly I wrote a little payload to do that. By doing so i ended up with the flag : squ1rrel{w3v3_b33n_h3r3_b3f0r3_n0w_0nt0_b1gger_4nd_better}.

droid

In that challenge we get an apk file; I used cutter to learn more about the file and found that function in the application :

public final class MainActivityKt {
   private static final int[] expected = new int[]{110, 150, 207, 72, 80, 147, 236, 122, 155, 186, 15, 250, 149, 240, 243, 207, 21, 59, 90, 3, 173, 237, 86, 27, 70, 28, 30, 188, 23, 153, 88};
   private static final int[] key = new int[]{29, 231, 186, 121, 34, 225, 137, 22, 224, 209, 63, 142, 249, 193, 157, 144, 124, 72, 5, 96, 157, 221, 103, 68, 40, 45, 109, 136, 123, 173, 37};

                :
                :

   public static final boolean check(String var0) {
      Intrinsics.checkNotNullParameter(var0, "text");
      if (var0.length() != expected.length) {
         return false;
      } else {
         int[] var3 = new int[expected.length];
         int var1 = 0;

         for(int var2 = expected.length; var1 < var2; ++var1) {
            var3[var1] = var0.charAt(var1) ^ key[var1];
         }

         var0 = ArraysKt.joinToString$default(var3, (CharSequence)null, (CharSequence)null, (CharSequence)null, 0, (CharSequence)null, (Function1)null, 63, (Object)null);
         System.out.println(var0);
         var0 = ArraysKt.joinToString$default(expected, (CharSequence)null, (CharSequence)null, (CharSequence)null, 0, (CharSequence)null, (Function1)null, 63, (Object)null);
         System.out.println(var0);
         return Arrays.equals(var3, expected);
      }
   }

   public static final int[] getExpected() {
      return expected;
   }

   public static final int[] getKey() {
      return key;
   }
}

This is a function that verifies a word, probably the password. We will try to reverse it to get the password then. To get the flag I need for each position i from 0 to 30 : compute the character as flag[i] = (char)(expected[i] ^ key[i]), then i convert it to ascii and add it to my list of characters. I did the code in Python and got that :

# Array containing the expected values (encrypted or encoded data) that the flag should decrypt to
expected = [110, 150, 207, 72, 80, 147, 236, 122, 155, 186, 15, 250, 149, 240, 243, 207, 21, 59, 90, 3, 173, 237, 86, 27, 70, 28, 30, 188, 23, 153, 88]

# Array containing the key values used to encrypt or decrypt the flag
key = [29, 231, 186, 121, 34, 225, 137, 22, 224, 209, 63, 142, 249, 193, 157, 144, 124, 72, 5, 96, 157, 221, 103, 68, 40, 45, 109, 136, 123, 173, 37]

flag = ""  # Initialize an empty string to store the decrypted flag

# Iterate over the indices of the expected and key arrays to decrypt each character
for i in range(len(expected)):
    # XOR the corresponding values from expected and key to get the original character code
    char_code = expected[i] ^ key[i]
    # Convert the character code to its ASCII character and append it to the flag
    flag += chr(char_code)

# Print the final decrypted flag
print("Flag:", flag)

Once I executed that code I got the flag : sq1rrel{k0tl1n_is_c001_n1s4l4}.