Introduction
In HackTheBox Hunting License , we need to extract three passwords from an ELF executable named license
and answer a few basic questions about the executable to obtain the flag. We’ll use tools like Radare2 or Ghidra to analyze and reverse-engineer the executable.
HackTheBox Certified Defensive Security Analyst Study Notes
HackTheBox Certified Penetration Testing Specialist Study Notes
HackTheBox Hunting License Description
STOP! Adventurer, have you got an up to date relic hunting license? If you don’t, you’ll need to take the exam again before you’ll be allowed passage into the spacelanes!
Obtaining The First Password
We are provided with a binary whose source code can be viewed using a disassembler such as Ghidra. The main function looks like the below:
Another function of interest is exam() that compares passwords. If you look closely, we can see that a plain text password is written as an argument to the string comparison function strcmp. The password is PasswordNumeroUno. Additionally, iVar1
verifies if user_input
matches local_1c
. Tracing it back, local_1c
is modified using the reverse(&local_1c, t, 0xb)
function.
Obtaining The Second Password
If you open the binary and analyze it using radar2, you will notice that the second password can be derived by reversing a particular suspicious string in the executable. With a bit of inspection, it’s straightforward to determine what this reversed string likely represents as the second password.
Or in Ghidra:
The second password is provided as the second parameter to the reverse()
function, which simply reverses the string. Here’s a simplified version of the code for clarity:
void reverse(char *param1, char *param2, int param3) {
for (int i = 0; i < param3; i++) {
param1[i] = param2[param3 - i - 1];
}
param1[param3] = 'void reverse(char *param1, char *param2, int param3) {'; // Null-terminate the reversed string
for (int i = 0; i < param3; i++) {
param1[i] = param2[param3 - i - 1];
}
param1[param3] = '\0'; // Null-terminate the reversed string
}
// Example usage
char encoded_password[] = "drowssaP"; // This is the original (reversed) password string
char decoded_password[9]; // Array to store the reversed result
reverse(decoded_password, encoded_password, 8); // Decode by reversing
printf("Decoded password: %s\n", decoded_password);
}
// Example usage
char encoded_password[] = "drowssaP"; // This is the original (reversed) password string
char decoded_password[9]; // Array to store the reversed result
reverse(decoded_password, encoded_password, 8); // Decode by reversing
printf("Decoded password: %s\n", decoded_password);
To get the second password in the correct format, you can use CyberChef to swap the endianness after reversing the string, as you mentioned. Since the length is known to be 0xb
(or 11), here’s how you can proceed:
- Reverse the Encoded Password: Input the reversed password into the script or reverse it manually.
Swap Endianness in CyberChef:
- Go to CyberChef (https://gchq.github.io/CyberChef/).
- Paste the reversed password result.
- Apply the “Swap endianness” operation.
- Set the length to 11 bytes (or
0xb
).
The output should be the final, correctly formatted second password.
The second password is : P4ssw0rdTw0
Obtaining The Third Password
The third and final password is obtained by XORing certain bytes. To identify which bytes are involved and understand the specifics of the XOR operation, we need to examine the xor
function closely in the executable. This will reveal the bytes used and the XOR process applied.
The XOR function:
The function takes four parameters:
arg4
: The XOR key used to decode the password.
arg1
: The buffer address where the decoded password will be stored for later comparison.
arg2
: The byte array that will be XORed (the encoded password).
arg3
: The length of the byte array to XOR (the password’s length).
To retrieve the password, we can create a Python script that performs the XOR operation on the byte array exactly as the xor
function does.
Here’s a general basic script structure but this script can be customized to fit our scenario:
def decode_password(encoded_password, length, xor_key):
decoded_password = ""
for i in range(length):
# XOR each byte in the encoded password with the key
decoded_char = chr(encoded_password[i] ^ xor_key)
decoded_password += decoded_char
return decoded_password
# Example encoded password byte array, length, and XOR key (fill with actual values)
encoded_password = [0xXX, 0xXX, 0xXX] # Replace with actual byte values
length = len(encoded_password)
xor_key = 0xYY # Replace with the actual XOR key
password = decode_password(encoded_password, length, xor_key)
print("Decoded password:", password)
Replace encoded_password
and xor_key
with the actual values from the executable. This will output the decoded password for use.
By executing the script, we can obtain the third and final password: ThirdAndFinal!!!
You can also watch: