This is one of the reversing problems that I solved during SarCTF a couple months back in February of 2020. I decided to write this up since I believe it to a good beginner problem for people looking to get into reverse engineering.
# Problem Description> While the children were playing toys, Sherlock was solving crosswords in large volumes.
# Reversing the BinaryUsing `file` we can see we're given an unstripped 64-bit ELF file: `ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=2e45dc319e3736db1643abb283b0ed9a18681261, not stripped`. Running the binary, we're presented with the following output:
```➜  sarctf ./crossw0rd Welcome. You're in function check. Please Enter a password to continue. 1 attempt remaining:passwordWrong password! Your attempt is over.```
Since we need to reverse engineer the executable to get the password, let's go ahead and throw this in a disassembler/decompiler of your choice, I'll be using Ghidra.
After analyzing the binary, we can see several exported symbols. Let's start with `main()`:
*Main*
```cundefined8 main(void){  check();  return 0;}```
Only one call to follow so let's look at `check()`. We can clearly see that this function is responsible for prompting the user, taking input, and finally verifying said input. `check()` also calls another function named `e()`, and checks against it's return value. If it's **FALSE**, we lose.
*check*```cvoid check(void)
{  char cVar1;  long in_FS_OFFSET;  char local_28 [24];  long local_10;   local_10 = *(long *)(in_FS_OFFSET + 0x28);  puts(      "Welcome. You\'re in function check. Please Enter a password to continue. 1 attemptremaining:"      );  scanf("%s",local_28);  cVar1 = e(local_28);  if (cVar1 == '\0') {    puts("Wrong password! Your attempt is over.");  }  else {    puts("You cracked the system!");  }  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {                    /* WARNING: Subroutine does not return */    __stack_chk_fail();  }  return;}```
*E*
```culong e(char *param_1)
{  byte bVar1;  char cVar2;   if ((((param_1[7] == '5') && (param_1[0x11] == 'g')) && (param_1[2] == 'A')) &&     (cVar2 = b(param_1), cVar2 != '\0')) {    bVar1 = 1;  }  else {    bVar1 = 0;  }  return (ulong)bVar1;}```
`e()` checks 4 things: 8th character must equal **5**, 18th character must equal **g**, string passed into this function must not be **NULL**, and `b()` must return **TRUE**. Let's take a look at what `b()` expects.
This time, `b()` checks 5 things: 16th character must equal **i**, 10th character must equal **r**, 2nd character must equal **L**, `d()` must return **TRUE**, and string passed in cannot be **NULL**.
*B*```culong b(char *param_1)
{  byte bVar1;  char cVar2;   if ((((param_1[0xf] == 'i') && (param_1[9] == 'r')) && (param_1[1] == 'L')) &&     (cVar2 = d(param_1), cVar2 != '\0')) {    bVar1 = 1;  }  else {    bVar1 = 0;  }  return (ulong)bVar1;}```
This continues on for 4 more functions, the steps moving forward are exactly the same. There are 8 functions in total worth looking at: `main()`, `check()`, and `a()-f()`.
*D*```culong d(char *param_1)
{  byte bVar1;  char cVar2;   if ((((param_1[10] == '3') && (param_1[0x12] == '}')) && (param_1[6] == 'a')) &&     (cVar2 = f(param_1), cVar2 != '\0')) {    bVar1 = 1;  }  else {    bVar1 = 0;  }  return (ulong)bVar1;}```
*F*```culong f(char *param_1)
{  byte bVar1;  char cVar2;   if ((((*param_1 == 'F') && (param_1[0xe] == '5')) && (param_1[0x10] == 'n')) &&     (cVar2 = c(param_1), cVar2 != '\0')) {    bVar1 = 1;  }  else {    bVar1 = 0;  }  return (ulong)bVar1;}```
*C*```culong c(char *param_1)
{  byte bVar1;  char cVar2;   if ((((param_1[3] == 'G') && (param_1[0xb] == 'v')) && (param_1[5] == '3')) &&     (cVar2 = a(param_1), cVar2 != '\0')) {    bVar1 = 1;  }  else {    bVar1 = 0;  }  return (ulong)bVar1;}```
*A*```cundefined8 a(char *param_1)
{  undefined8 uVar1;   if ((((param_1[4] == '{') && (param_1[0xc] == '3')) && (param_1[8] == 'y')) &&     (param_1[0xd] == 'r')) {    uVar1 = 1;  }  else {    uVar1 = 0;  }  return uVar1;}```
# Putting It TogetherAfter reversing through functions `a()-f()`, you should be able to string together the expected password. We run the binary one more time, giving it the correct password, and we get the flag: `FLAG{3a5yr3v3r5ing}`
Author: [medarkus](https://twitter.com/v0idptr_)