Crackmes.de - crackme.02.32 by geyslan
This is a crackme level 3 (Medium) from https://crackmes.one/crackme/5ab77f6533c5d40ad448cbc2
Fast static analysis Link to heading
First, use the file
command to see what kind of file it is:
$ file crackme.02.32
crackme.02.32: ELF 32-bit LSB executable, Intel 80386, (SYSV), too many section (65535)
A 32 bit ELF, with a nice “too many sections”, no other userfull information.
Checking the strings in the binary :
Judging by the “tracing not allowed” and “I’m sorry GDB…” there are a few anti-debug methods out there.
Anti-debug Link to heading
Lets run the program :
$ ./crackme.02.32
Please tell me my password: testtest
No! No! No! No! Try again.
Classic, the binary expects a password. This challenge isn’t difficult to solve without debugging, but it’s interesting to see what protections are in place and how they can be bypassed to make analysis easier.
Here is the codeflow that determines if the programme is run with a debugger, we can find it by looking at where the “anti-debug” strings are used:
There are two differents tests :
- Test if the program is run under gdb using this technic:
“When a process uses fork(2) to spawn a child process, the parent’s file descriptors are inherited to the new child process. In normal cases, the new process should have only FDs 0 (stdin), 1 (stdout) and 2 (stderr). However, GDB opens up some more FDs (3, 4 and 5) and never closes them, so they are inherited.”
Source: https://xorl.wordpress.com
As we can see, a file descriptor is created (pointing to /tmp), and his _fileno is checked, if fileno > 5 the program leaves.
Another block calls the ptrace
function to check if the process is being traced (used by ltrace or gdb for example). If it is, the program stops:
Bypass this is easy, we can just the change the :
mov eax, ds:dword_8049C08
into :
mov eax, 0
and it will no more jump to the “tracing is not allowed” block.
Get the password Link to heading
Continuing with the main
function, we can see that our input is used as a parameter and passed to a function. This function loops over the chars and performs a binary OR with the value 0x90h
.
Then, the return value is compared with a char array :
Little sum up :
- We enter a string
- This string is ORed with 0x90
- The result must match this char array :
[0xF7, 0xF8 ,0xF1 ,0xF4 ,0xF1 ,0xF8 ,0xB3 ,0xFC ,0xFC] #(I'll call it "tab")
One thing i’m sure :
OR(tab,tab) == tab
What if the input is exactly the same tab ?
$ python2 -c 'print "\xF7\xF8\xF1\xF4\xF1\xF8\xB3\xFC\xFC"' | ./crackme.02.32
Please tell me my password: The password is correct!
Congratulations!!!
If we want an ascii solution, we can remove the MSB in tab (in order to have smaller numbers which fit in the readable range of the ascii table), lets script that :
#!/usr/bin/python3
tab = [0xF7, 0xF8 ,0xF1 ,0xF4 ,0xF1 ,0xF8 ,0xB3 ,0xFC ,0xFC]
res = ""
for elt in tab:
h1 = str(bin(elt))[2:] # remove '0b'
res += chr(int(h1[1:],2)) # remove first '1'
print("result : ", res)
And the result is : wxqtqx3||
Please tell me my password: wxqtqx3||
The password is correct!
Congratulations!!!
In fact, there are a lot of solutions (512) because we can OR a lot of values to match the key.