Easy_Path_to_the_Grail

By DKvenom, 0-Day Aarhus

Description :

Author : NomanProdhan

Brave knight, your quest is simple yet essential—unlock the secrets hidden in this
binary challenge and tread the path to the grail. The journey will test your wits
as you reverse the provided binary, uncovering the treasure within.

Link to files

github.com/sajjadium

Solve

┌──(DKvenom㉿)-[~/CTF/KnightCTF/Easy_Path_to_the_Grail]
└─$ file grail.knight
grail.knight: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=e00aa2282067e0eb817f181164f23830fd0a4190, for GNU/Linux 4.4.0, not stripped

Its a Elf executable so i open op Ghidra and begin reversing (I have changed some var's names). If we take a look at main we see what the program does. To starters the program prints Enter the password (the original flag): that input is that put in transform_input(flag,Input) with flag and that input. We then String Compare on "D2C22A62DEA62CCE9EFA0ECC86CE9AFA4ECC6EFAC6162C3636CC76E6A6BE" (The Flag) if the input contains the flag and either win or lose.


undefined8 main(void)

{
  int iVar1;
  undefined8 uVar2;
  long in_FS_OFFSET;
  undefined flag [128];
  char Input [264];
  long local_10;

  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  printf("Enter the password (the original flag): ");
  iVar1 = __isoc99_scanf("%127s",flag);
  if (iVar1 == 1) {
    transform_input(flag,Input);
    iVar1 = strcmp(Input,"D2C22A62DEA62CCE9EFA0ECC86CE9AFA4ECC6EFAC6162C3636CC76E6A6BE");
    if (iVar1 == 0) {
      printf("Correct! The flag is %s\n",flag);
    }
    else {
      puts("Wrong password!");
    }
    uVar2 = 0;
  }
  else {
    puts("Input error.");
    uVar2 = 1;
  }
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return uVar2;
}

So what does transform_input(flag,Input); do? So here we have a for loop that runs though every char and runs another function called do_fight(*i) witch takes in the pointer. it then returns the output.

This function iterates through every character in the input string flag. For each character (*i, it calls another function called do_fight(*i), which takes each character, reverses the order of its bits, and returns the resulting byte. (0x00001111 = 0x11110000)

transform_input then converts that byte into a two-character hexadecimal string (using sprintf with %02X) and appends it to the Input buffer.

void transform_input(char *param_1,char *param_2)
{
  byte bVar1;
  char *local_28;
  char *i;

  local_28 = param_2;
  for (i = param_1; *i != '\0'; i = i + 1) {
    bVar1 = do_fight(*i);
    sprintf(local_28,"%02X",(ulong)bVar1);
    local_28 = local_28 + 2;
  }
  *local_28 = '\0';
  return;
}
byte do_fight(byte param_1)

{
  undefined local_1c;
  undefined local_d;
  undefined4 i;

  local_d = 0;
  local_1c = param_1;
  for (i = 0; i < 8; i = i + 1) {
    local_d = local_d << 1 | local_1c & 1;
    local_1c = local_1c >> 1;
  }
  return local_d;
}

Now that we know what the challenge do we can now begin to write som code to reverse the given flag.

SolveScript


def reverse_bits(byte_val):
    byte_val &= 0xFF
    local_d = 0
    local_1c = byte_val
    for _ in range(8):
        local_d = (local_d << 1) | (local_1c & 1)
        local_1c >>= 1
    return local_d

target = "D2C22A62DEA62CCE9EFA0ECC86CE9AFA4ECC6EFAC6162C3636CC76E6A6BE"


bytes_vals = [int(target[i:i+2], 16) for i in range(0, len(target), 2)]
reversed_bytes = [reverse_bits(b) for b in bytes_vals]
flag = bytes(reversed_bytes).decode('latin1')  # use latin1 to preserve byte values
print(flag)

KCTF{e4sy_p3asY_r3v_ch4ll3nge}