Sometimes you want to sit down and do some reversing without melting your brain. That’s what difficulty 1 crackmes are for. This one is babyFirstCrackme by idanhajbeko, uploaded to crackmes.one (ID 680d04208f555589f3530fb5): a 64-bit ELF written in C that asks for a password and tells you whether it’s right. We’ll solve it three different ways, from the laziest to the most “proper”.
First contact
Before opening anything heavy, see what you’re dealing with:
file babyFirstCrackme
# babyFirstCrackme: ELF 64-bit LSB pie executable, x86-64, dynamically linked, not stripped
not stripped is a good sign: it keeps the function names. Run it to see the behaviour:
./babyFirstCrackme
# Enter the password:
# test
# Wrong password! (in red)
Asks for a password, compares it, responds. Classic.
Path 1: strings
The fast lane. If the password is written as-is inside the binary (spoiler: it is), strings pulls it out:
strings babyFirstCrackme | grep -i -E 'pass|w0rd|@|!'
Among the noise, one string screams password: !_-P@$$w0rD-_!. In a level 1 crackme that’s usually enough, but it doesn’t tell you why it’s the password. Let’s confirm.
Path 2: ltrace
ltrace traces library calls. Since the comparison is done with strcmp, you’ll see both arguments side by side:
ltrace ./babyFirstCrackme
# printf("Enter the password:\n")
# ...
# strcmp("test", "!_-P@$$w0rD-_!") = -1
# puts("Wrong password!")
There it is, served on a plate: the program compares your input against !_-P@$$w0rD-_!. You don’t even need to open a disassembler.
Path 3: Ghidra
To actually understand the flow, open it in Ghidra, import the binary, let it analyse, and jump to main. The decompilation is straightforward:
undefined8 main(void) {
char local_3f8 [1000];
printf("Enter the password:\n");
__isoc99_scanf(&DAT_...,local_3f8);
if (strcmp(local_3f8,"!_-P@$$w0rD-_!") == 0) {
getFlag(); // prints the flag in green
} else {
// "Wrong password!" in red
}
return 0;
}
No XOR, no arithmetic, no obfuscation: a direct comparison against the embedded string. The password is literally !_-P@$$w0rD-_!.
./babyFirstCrackme
# Enter the password:
# !_-P@$$w0rD-_!
# Correct! Here is your flag: (in green)
The hints bonus
The challenge ships with a second binary holding the hints, and that one does have a little substance: an XOR for you to practise with. The operation is 0x4D2 ^ 0x30 = 0x4E2, which in decimal is 1250. Nothing wild, but it’s the perfect excuse to open the Python calculator and remember that XOR is reversible:
>>> 0x4D2 ^ 0x30
1250
Wrap-up
babyFirstCrackme doesn’t try to be hard, and that’s fine: it’s there to drill the flow file → run → strings/ltrace → Ghidra before you get into binaries that actually fight back. The lesson that carries over to tougher challenges is that a password compared in the clear with strcmp protects absolutely nothing; it lives inside the binary and anyone with five minutes pulls it out. When you start seeing strcmp replaced by byte-by-byte checks, hashes, or decryption routines, that’s when the fun begins.