Skip to main content

Compiled

First download the file from the room (https://tryhackme.com/room/compiled) in order to analyze it.

strings Compiled-1688545393558.Compiled
...
PTE1
u+UH
StringsIH
sForNoobH
Password:
DoYouEven%sCTF
__dso_handle
_init
Correct!
Try again!
...

Strings is for noob

Ghidra

undefined8 main(void)

{
int iVar1;
char local_28 [32];

fwrite("Password: ",1,10,stdout);
__isoc99_scanf("DoYouEven%sCTF",local_28);
iVar1 = strcmp(local_28,"__dso_handle");
if ((-1 < iVar1) && (iVar1 = strcmp(local_28,"__dso_handle"), iVar1 < 1)) {
printf("Try again!");
return 0;
}
iVar1 = strcmp(local_28,"_init");
if (iVar1 == 0) {
printf("Correct!");
}
else {
printf("Try again!");
}
return 0;
}
  1. undefined8 main(void):

    • main: This is the entry point of the program. Every C program starts execution here.
    • void: The void inside the parentheses means that the main function takes no arguments.
    • undefined8: This indicates the return type. undefined8 is often seen in decompiled code (like what you might get from Ghidra or IDA Pro). It essentially means "an 8-byte value of unspecified type". For our purposes, think of it as a generic return type, similar to int on many systems. The return value (0 in both success and failure cases) isn't crucial for solving the challenge.
  2. int iVar1;:

    • Declares an integer variable named iVar1. This variable will store the result of the strcmp function calls.
  3. char local_28 [32];:

    • Declares a character array (a string) named local_28.
    • [32]: This array can hold up to 32 characters (including the null terminator, \0, which marks the end of a C string). This is where the user's input will be stored. The name local_28 is typical of decompilers; it indicates a local variable at a specific offset on the stack.
  4. fwrite("Password: ",1,10,stdout);:

    • This line prints "Password: " to the console (standard output).
    • fwrite: A function that writes data to a stream.
    • "Password: ": The string to be written.
    • 1: The size (in bytes) of each element to be written (1 byte, because it's a character).
    • 10: The number of elements to write (10 characters in "Password: ").
    • stdout: A predefined stream representing the standard output (usually the console).
  5. __isoc99_scanf("DoYouEven%sCTF",local_28);:

    • This is the crucial line that reads user input. It's using the scanf function, a standard C input function.
    • __isoc99_scanf: A specific version of scanf (likely indicating the C standard used).
    • "DoYouEven%sCTF": This is the format string. The %s is a format specifier. It tells scanf to expect a string from the input. The input is expected to start with "DoYouEven", followed by the string we want to capture (%s), and it could continue with "CTF". However, the "CTF" part is not strictly enforced. The %s will read characters until it encounters whitespace (space, tab, newline).
    • local_28: The address of the local_28 array. scanf will write the string it reads from the input into this array.
  6. iVar1 = strcmp(local_28,"__dso_handle"); if ((-1 < iVar1) && (iVar1 = strcmp(local_28,"__dso_handle"), iVar1 < 1)) { ... }:

    • strcmp(str1, str2): This function compares two strings lexicographically (like dictionary order).
      • Returns 0 if str1 and str2 are equal.
      • Returns a value less than 0 if str1 comes before str2 alphabetically.
      • Returns a value greater than 0 if str1 comes after str2 alphabetically.
    • The first strcmp compares the user input with "__dso_handle".
    • The if condition is a bit convoluted. It checks if iVar1 is greater than -1 and if iVar1 (after being reassigned the result of the same comparison) is less than 1.
    • The result is that this if block executes if and only if iVar1 is 0. In other words, this is a complicated way of checking if (strcmp(local_28, "__dso_handle") == 0). If the strings are equal, it prints "Try again!" and exits. This is a red herring.
  7. iVar1 = strcmp(local_28,"_init"); if (iVar1 == 0) { ... } else { ... }:

    • This is the real password check.
    • strcmp is used again, this time comparing the user input with "_init".
    • if (iVar1 == 0): If the result of strcmp is 0 (meaning the strings are equal), the "Correct!" message is printed.
    • else: Otherwise, "Try again!" is printed.
  8. return 0;:

    • This line exits the main function and returns a value of 0 to the operating system. A return value of 0 typically indicates successful execution.

Solution

  1. Input Format and scanf's Behavior: The scanf format string DoYouEven%sCTF is deceptive. While it suggests the input should be DoYouEven<PASSWORD>CTF, the %s specifier reads characters only until it finds whitespace. The "CTF" part is a potential continuation, but not a requirement. Pressing Enter adds a newline character (\n), which is whitespace.

  2. Password: The code checks if the string captured by %s is equal to "_init".

  3. Correct Input: Because of the newline added by pressing Enter, the correct input is:

    DoYouEven_init
    • scanf reads DoYouEven.
    • scanf encounters %s and starts reading into local_28.
    • scanf reads _init.
    • scanf encounters the newline (\n) from pressing Enter. Because newline is whitespace, scanf stops reading for %s at this point. The "CTF" part is ignored.
    • local_28 contains "_init".
    • The second strcmp succeeds.

Key Takeaways

  • scanf with %s and Whitespace: This is the most important point. %s in scanf reads until any whitespace character is encountered (space, tab, newline, etc.). It does not require the rest of the format string to match exactly.
  • Trailing Newline: Pressing Enter adds a newline character (\n) to the input. This acts as the whitespace that terminates the %s input.
  • Format String as a Guide: The format string in scanf provides a guide for the expected input, but %s will stop reading at whitespace, regardless of the rest of the format string.
  • Red Herrings: The first strcmp check and the "CTF" in the format string are distractions.