Swiss Hacking Challenge 2023 - x or y

Posted on Apr 30, 2023

Information

Challenge category: re

Challenge Description

Staring at the two options in front of her, Sarah was overwhelmed with indecision. She turned to her friend and asked, “Is it X or Y? I can’t decide. Can you help me figure it out?” Her friend took a moment to consider before replying, “Well, it depends on what you’re looking for. If you want something sweet, go for X. But if you want something savory, Y is the way to go.” Sarah thought about it for a moment before making her choice, grateful for her friend’s guidance.

Files

We are given an x_or_y.zip file containing a binary:

x_or_y: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=2551529b8c67cd6ec847697eff8e080df61bbc4c, for GNU/Linux 3.2.0, not stripped
Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      PIE enabled

Exploitation

When opening up the file and showing the decompilation of the main function we see the following:

undefined8 main(void)

{
  bool bVar1;
  long in_FS_OFFSET;
  int local_5c;
  undefined8 local_58;
  undefined8 local_50;
  undefined8 local_48;
  undefined4 local_40;
  undefined2 local_3c;
  undefined local_3a;
  byte local_38 [40];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  local_58 = 0x24a4b494b1a110a;
  local_50 = 0x110d261e17104c2c;
  local_48 = 0x49261d49491e264a;
  local_40 = 0x1261d15;
  local_3c = 0xb49;
  local_3a = 4;
  printf("Enter the password to continue: ");
  fgets((char *)local_38,0x20,stdin);
  bVar1 = true;
  for (local_5c = 0; local_5c < 0x1f; local_5c = local_5c + 1) {
    bVar1 = (bool)(bVar1 & (local_38[local_5c] ^ 0x79) ==
                           *(byte *)((long)&local_58 + (long)local_5c));
  }
  if (bVar1) {
    puts("This password is correct.");
    puts("Have a nice day!");
  }
  else {
    puts("Sorry, this password is wrong :(");
  }
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}

Basically the local58, local50, local48, local40, local3c and local3a seem to contain the flag XORed with 0x79. So we just need to XOR the values with 0x79 to get the flag.

import sys

def xor(x):
    # xor the bytes
    array = [ chr(x[i] ^ 0x79) for i in range(0, len(x))]
    # change byte order
    return [ array[i] for i in range(len(array)-1, -1, -1)]

# initialize the arrays
one =    bytearray.fromhex("024A4B494B1A110A")
two =    bytearray.fromhex("110D261E17104C2C")
three =  bytearray.fromhex("49261D49491E264A")
four =   bytearray.fromhex("040B4901261D15")
# concatenate the strings
total = xor(one) + xor(two) + xor(three) + xor(four)
# print the password
print("".join(total))

I had to try around a bit with the order of the arrays but in the end I got a flag.

Flag

The flag is:

shc2023{U5ing_th3_g00d_0ld_x0r}

Conclusion

x_or_y was a weird challenge but it somehow worked. During writing this writeup I was like wtf did I do there. But it worked so I’m happy. Also, this is finally my last writeup for SHC quals 2023, looking back I don’t know if I’d do writeups for every challenge again.

References

  1. https://favtutor.com/blogs/xor-python