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
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}