Crackme Open

A Beginner’s Guide to Cracking Password-Protected Files

Samuel Selasi
7 min readJan 6, 2023
PC: IEEE Spectrum

Get ready for some hacking fun! In this blog post, we’ll show you how to break into a simple C executable file secured with a password using Ubuntu 20.04 LTS. Whether you’re just starting out or a seasoned pro, this tutorial has something for everyone. Time to flex those cyber skills!

All the files used in this tutorial can be found on GitHub here. You can clone the repository into your local environment to access the encrypted files.

To begin, we can execute the crackme file to observe its behavior by navigating to the crackme directory and entering the following command:

$ ./crackme

The following will be printed to standard output:

Access Denied

This suggests that the crackme file cannot be run in the usual way. As a result, we need to determine the cause of this issue. However, before we can do that, we need to identify the type of file it is.

The file command is used to identify the type of a file. It does this by performing a series of tests in a specific order: filesystem tests, magic number tests, and language tests.

PC: Here

These tests are designed to determine the file's type based on its content and any metadata associated with it. If you want to use the file command to identify the type of a specific file, you can do so by running file [filename] in your terminal. For example:

$ file crackme

would show you the type of the file crackme is as:

crackme: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=e06e0b0229279a69506925702a7f79e36bdc3eb2, not stripped

The information provided in the output of the file command reveals that the crackme file is:

  1. An executable file designed to be run on a 64-bit Linux operating system
  2. Compiled for the x86–64 architecture and linked dynamically, meaning it relies on shared libraries to function
  3. Interpreted by the /lib64/ld-linux-x86–64.so.2 interpreter
  4. Built for GNU/Linux 2.6.24 and has a unique identifier called a “BuildID”
  5. Has not been stripped, so it still contains debugging information and symbols that can be used for analysis.

ltrace is a utility that traces the dynamic library calls made by a program. Since we now know the file relies on shared libraries, ltrace can be used to analyze the crackme file. We may be able to see the specific library functions that the file calls and how they are used, which can provide additional insight into the behavior and purpose of the program.

It’s also worth noting that ltrace can be used in conjunction with other tools like gdb (GNU Debugger) to further analyze the behavior of the program and potentially reverse engineer it which we will not be using for this tutorial.

We can run ltrace on the crack me file by entering the following command:

$ ltrace ./crackme

the output of the command will be as follows:

__libc_start_main(0x40087d, 1, 0x7ffeef764458, 0x400a70 <unfinished ...>
strncmp("SHELL=/bin/bash", "Passw0rd=", 9) = 3
strncmp("PWD=/home/vagrant/crackme_tutori"..., "Passw0rd=", 9) = -10
strncmp("LOGNAME=vagrant", "Passw0rd=", 9) = -4
strncmp("XDG_SESSION_TYPE=tty", "Passw0rd=", 9) = 8
strncmp("MOTD_SHOWN=pam", "Passw0rd=", 9) = -3
strncmp("HOME=/home/vagrant", "Passw0rd=", 9) = -8
strncmp("LANG=C.UTF-8", "Passw0rd=", 9) = -4
strncmp("LS_COLORS=rs=0:di=01;34:ln=01;36"..., "Passw0rd=", 9) = -4
strncmp("SSH_CONNECTION=10.0.2.2 61015 10"..., "Passw0rd=", 9) = 3
strncmp("LESSCLOSE=/usr/bin/lesspipe %s %"..., "Passw0rd=", 9) = -4
strncmp("XDG_SESSION_CLASS=user", "Passw0rd=", 9) = 8
strncmp("TERM=xterm-256color", "Passw0rd=", 9) = 4
strncmp("LESSOPEN=| /usr/bin/lesspipe %s", "Passw0rd=", 9) = -4
strncmp("USER=vagrant", "Passw0rd=", 9) = 5
strncmp("SHLVL=1", "Passw0rd=", 9) = 3
strncmp("XDG_SESSION_ID=22", "Passw0rd=", 9) = 8
strncmp("XDG_RUNTIME_DIR=/run/user/1000", "Passw0rd=", 9) = 8
strncmp("SSH_CLIENT=10.0.2.2 61015 22", "Passw0rd=", 9) = 3
strncmp("XDG_DATA_DIRS=/usr/local/share:/"..., "Passw0rd=", 9) = 8
strncmp("PATH=/usr/local/sbin:/usr/local/"..., "Passw0rd=", 9) = -32
strncmp("DBUS_SESSION_BUS_ADDRESS=unix:pa"..., "Passw0rd=", 9) = -12
strncmp("SSH_TTY=/dev/pts/0", "Passw0rd=", 9) = 3
strncmp("OLDPWD=/home/vagrant/crackme_tut"..., "Passw0rd=", 9) = -1
strncmp("_=/usr/bin/ltrace", "Passw0rd=", 9) = 15
puts("Access Denied"Access Denied
) = 14
+++ exited (status 1) +++
PC: ALX

Lets take a closer look:

  1. __libc_start_main is a function that sets up a program’s environment and calls its main function. It takes in various arguments and is provided by the C standard library (libc). It is called by the program’s main entry point function.
  2. The lines beginning with strncmp show that the program is calling the strncmp function, which is a function that compares a given number of characters (in this case, 9 characters) of two strings. The strings being compared appear to be various environment variables (e.g. "SHELL", "PWD", "LOGNAME", etc.) and the string "Passw0rd=". It seems that the program is checking whether any of the environment variables begin with the string "Passw0rd=".
  3. The puts function is called at the end with the string "Access Denied", which may indicate that the program is printing this message if none of the environment variables begin with "Passw0rd=".

Thanks to ltrace, it’s clear that this binary file is searching for an environment variable named Passw0rd. Time to create one with a random value and see what happens!

To set an environment variable in Linux, we can use the export command in the terminal. For example, to set an environment variable named Passw0rd to a value of test, we can run:

export Passw0rd=test

It is now necessary to rerun ltrace on the crackme file after exporting a value to the Passw0rd environment variable. This can be done by executing the following command:

$ ltrace ./crackme

the output of the command will be as follows:

__libc_start_main(0x40087d, 1, 0x7fff085f1d38, 0x400a70 <unfinished ...>
strncmp("SHELL=/bin/bash", "Passw0rd=", 9) = 3
strncmp("PWD=/home/vagrant/crackme_tutori"..., "Passw0rd=", 9) = -10
strncmp("LOGNAME=vagrant", "Passw0rd=", 9) = -4
strncmp("XDG_SESSION_TYPE=tty", "Passw0rd=", 9) = 8
strncmp("MOTD_SHOWN=pam", "Passw0rd=", 9) = -3
strncmp("HOME=/home/vagrant", "Passw0rd=", 9) = -8
strncmp("LANG=C.UTF-8", "Passw0rd=", 9) = -4
strncmp("LS_COLORS=rs=0:di=01;34:ln=01;36"..., "Passw0rd=", 9) = -4
strncmp("SSH_CONNECTION=10.0.2.2 61015 10"..., "Passw0rd=", 9) = 3
strncmp("LESSCLOSE=/usr/bin/lesspipe %s %"..., "Passw0rd=", 9) = -4
strncmp("XDG_SESSION_CLASS=user", "Passw0rd=", 9) = 8
strncmp("TERM=xterm-256color", "Passw0rd=", 9) = 4
strncmp("LESSOPEN=| /usr/bin/lesspipe %s", "Passw0rd=", 9) = -4
strncmp("USER=vagrant", "Passw0rd=", 9) = 5
strncmp("SHLVL=1", "Passw0rd=", 9) = 3
strncmp("XDG_SESSION_ID=22", "Passw0rd=", 9) = 8
strncmp("XDG_RUNTIME_DIR=/run/user/1000", "Passw0rd=", 9) = 8
strncmp("SSH_CLIENT=10.0.2.2 61015 22", "Passw0rd=", 9) = 3
strncmp("XDG_DATA_DIRS=/usr/local/share:/"..., "Passw0rd=", 9) = 8
strncmp("PATH=/usr/local/sbin:/usr/local/"..., "Passw0rd=", 9) = -32
strncmp("Passw0rd=test", "Passw0rd=", 9) = 0
MD5_Init(0x7fff085f1b90, 0x400b06, 9, 6) = 1
strlen("test") = 4
MD5_Update(0x7fff085f1b90, 0x7fff085f2f68, 4, 0x7fff085f2f68) = 1
MD5_Final(0x7fff085f1bf0, 0x7fff085f1b90, 0x7fff085f1b90, 0) = 1
sprintf("09", "%02x", 0x9) = 2
sprintf("8f", "%02x", 0x8f) = 2
sprintf("6b", "%02x", 0x6b) = 2
sprintf("cd", "%02x", 0xcd) = 2
sprintf("46", "%02x", 0x46) = 2
sprintf("21", "%02x", 0x21) = 2
sprintf("d3", "%02x", 0xd3) = 2
sprintf("73", "%02x", 0x73) = 2
sprintf("ca", "%02x", 0xca) = 2
sprintf("de", "%02x", 0xde) = 2
sprintf("4e", "%02x", 0x4e) = 2
sprintf("83", "%02x", 0x83) = 2
sprintf("26", "%02x", 0x26) = 2
sprintf("27", "%02x", 0x27) = 2
sprintf("b4", "%02x", 0xb4) = 2
sprintf("f6", "%02x", 0xf6) = 2
strcmp("c4032d9e95a93d91b9b595dcfcca640b"..., "098f6bcd4621d373cade4e832627b4f6"...) = 51
puts("Access Denied"Access Denied
) = 14
+++ exited (status 1) +++
PC: Here

What do we have here?

  1. We already know the first line shows that the __libc_start_main function was called with four arguments: the main function’s address, the number of program arguments, a pointer to an array of the program’s arguments, and a pointer to a function to be called when the main function returns.
  2. The following lines show a series of calls to the strncmp function, which compares two strings and returns an integer indicating their lexicographical ordering. It appears that the program is trying to compare each of the environment variables in the system with the string "Passw0rd=".
  3. After this, there are calls to the MD5_Init, MD5_Update, and MD5_Final functions, which are part of the MD5 cryptographic hash function. It looks like the program is computing the MD5 hash of the value of the Passw0rd environment variable.
  4. Next, there are calls to the sprintf function, which formats a string and stores it in a buffer. It appears that the program is formatting the bytes of the MD5 hash as hexadecimal values and storing them in strings.
  5. The output includes a call to the strcmp function with two strings as arguments: "c4032d9e95a93d91b9b595dcfcca640b" and "098f6bcd4621d373cade4e832627b4f6". This indicates that the program is comparing the MD5 hash of the password to the hash of the Passw0rd environment variable that was exported.
  6. The puts function is called at the end with the string "Access Denied", indicating that the Passw0rd is incorrect. However, this will likely be resolved soon.

It is not possible to reverse an MD5 hash, but there are methods to crack it. You can use a dictionary that has strings and their corresponding MD5 hashes, or try brute force. However, simple passwords are often used, so an MD5 dictionary with a large number of entries may be able to convert the hash back to a string..

We can use this website to reverse the hashed strings to their values.

Source: MD5 Center

Now that we have determined that the hashed password is LionelMessi, we can set the Passw0rd environment variable to this value and rerun the ltrace command to see if it produces a different result. Let’s give it a try!

$ export Passw0rd=LionelMessi
$ ./crackme
Access Granted

We’ve successfully cracked the file using ltrace and a dictionary attack. This demonstrates how even seemingly secure programs can be vulnerable to simple cracking techniques.

PC: here

It’s always important to remember to use strong, unique passwords and to never reuse passwords across different accounts.

Keep an eye out for our upcoming release on GitHub of a C program that compares MD5 hashes to a dictionary and reverses them to their original string form. Stay tuned!

We hope you enjoyed this tutorial on cracking a simple file. If you have any comments or questions, please don’t hesitate to leave them in the comments section below. Happy hacking!

--

--