This post is a walkthrough of the Try Hack Me room Crylo
Intro
Welcome to Crylo.
Crylo is an engaging room on TryHackMe that focuses on teaching two interesting topics: SQL Injection and bypassing Two-Factor Authentication (2FA) through exploiting the Crypto JS library. Through these concepts, participants learn how to overcome security challenges. In the Crylo room, you’ll explore techniques to go beyond just local connections and achieve command injection on a web application. This allows you to gain access to the server. Once you have access, you can uncover the sudo user’s password by utilizing the same AES encryption system that the server is employing. This room offers a hands-on and practical learning experience in the realm of cybersecurity.
NMAP Recon Scan
sudo nmap -sVC -T4 -oA nmap/tcp-ports 10.10.44.143
Starting Nmap 7.94 ( https://nmap.org ) at 2023-08-13 13:01 IST
Nmap scan report for 10.10.44.143
Host is up (0.0083s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 9f:7e:08:42:ea:bf:be:1a:1b:78:b0:f7:99:3c:ca:1d (RSA)
| 256 f8:f3:90:83:b1:bc:87:e8:93:a0:ff:d5:bc:1f:d7:e1 (ECDSA)
|_ 256 b6:77:4d:a6:6d:73:79:15:ea:39:0c:f6:1b:b4:0b:6c (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Spicyo
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 7.60 seconds
Ports of Interest
Port 22(OpenSSH) Port 80(Http on NGINX/1.18.0)
We can ignore port 22 for now as we do not have any credentials to use. Continue by browsing to port 80 where we are presented with a website for Spicyco.
Notice there is a Login button on the top right that we will need to dig deeper into! First we should run a directory enumeration scan. I used Gobuster to complete this scan.
Gobuster Directory Enumeration
gobuster dir -u http://10.10.44.143 -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
The login page we saw before shows up and also we can see a debug directory that might be worth looking.
Okay nothing of interest here for now as we don’t have any credentials for the site yet. Let’s take a look at the Login page now and try some default credentials or SQL Injection.
You should try some default username password combinations to see if we get lucky, but unfortunately this would be too easy.
Moving onto some SQL Injection I tried inputting the username admin' or 1=1--
while viewing the web developers console in chrome and saw a 500 (internal server error), which leads me to believe there is a possible injection point here.
Use Burpsuite to capture the login request then save this to a file called login.req
. This will be used with SQLMap next.
SQL Injection
I ran the following arguments with SQLMap. The argument --batch
will tell SQLMap to auto select answers and not wait for us to answer.
sqlmap -r login.req --risk=3 --level=3 --dump --batch
SQLMap Identifies the following.
Server: Ubuntu
Web Application: Nginx 1.18.0 as seen from our nmap scan earlier.
Database Back-end: MySQL: 5.0.12
Database: Food
SQLMap dumped the accounts_pintokens
which reveals two user to us user admin and anof.
Not sure what to do with the pintokens?
In the list of tables above there is a table called auth_user
which most likely will have a password column in it. Assuming it does proceed to try dump the password/s.
sqlmap -r login.req --dump -D food -T auth_user -C password
Admin Hash
Sure enough there is a password column and SQLMap managed to dump it for us. The password is hashed and will need to be cracked to be of any use. Hashcat is our best bet at cracking this hash and we can look up the the hash name and hash-mode on hashcat’s examples page https://hashcat.net/wiki/doku.php?id=example_hashes.
The mode we need to use is 10000
to crack the hash.
Hashcat was able to crack the password and now we have logon credentials for the admin user. Proceed to login through the login page. The password is correct but now we are being asked for a pin code i.e. a second form of authentication.
Using the web developer tools console in Chrome we can see a true or false check for the pin code.
Taking a closer look in the validation.js
script we can better understand what is happening.
If the jsonResponse.pin_set
is true we get redirected to /2fa and asked for the pin.
If the jsonResponse.pin_set
is false we are redirected to the /set-pin page. If we can redirect to here we can set a pin for the admin.
On line 23 of the validation.js
script is the first if statement, set a breakpoint here using the browsers developers tools.
Using the console enter the following to set the pin_set to false.
jsonResponse = {
"pin_set": "false",
"email": "admin@admin.com",
"success": "true"
}
Once this has been set resume the script and you should now be prompted to set a pin number. Keeping it simple we can just enter 1234
Now login once more and enter the pin you just set to be granted admin login access to the site.
We are logged in now as the admin user… Now that we are admin we can try return the the debug page that was forbidden earlier.
Forbidden (Bypass Debug Local Access)
Still forbidden and only available to local users. We can use Burpsuite to spoof our IP address as localhost.
Original Get Request before editing.
To bypass this restriction we can use the X-Forwarder-For
header and add this to our get request.
The “X-Forwarded-For” (XFF) header is not a part of the HTML request itself but is commonly used in HTTP requests as an HTTP header. It is used to indicate the original IP address of a client, especially when the request passes through one or more proxy servers or load balancers. This header provides information about the client’s IP address, allowing servers further down the chain to know the actual source of the request.
After sending the request we mange to bypass the local user check and are presented with an open port check page which is most likely vulnerable to code injection.
Let’s find out, but first just enter a port to see what it does.
We need to use Burpsuite again, so we can inject the X-Forwarder-For
header for this to continue to work.
OS Command Injection
Append more commands after the port number to see if it is executed on the target. I used ls -las
as an example to see if I could list the current working directory.
BurpSuite does show the contents of the current working directory albeit a little hard to read. This is enough for us to be able to try getting a reverse shell now.
Exploitation (Establishing a Foothold)
Now we know we can execute commands on the target it’s time to get our foothold.
Start pwncat-cs and listen for the bash reverse shell sent with BurpSuite.
Start Listener.
Session Established
Enumeration On Target
List the current working directory contents.
Check what other users are available on the target.
Three users found root, anof and crylo the current user we are now.
The first flag can be found in Crylo’s home folder. Submit to THM.
One of the room questions asked who is a member of the sudo group, so let’s take a look.
List members of the sudo group
Both these commands provide the same information and are handy to know.
cat /etc/group | grep '^sudo:'
sudo:x:27:anof
getent group sudo
sudo:x:27:anof
The user Anof is a member of the sudo group and is our answer to the question.
To get root we are given a hint ‘Exploit the web app to gain access to the machine and submit the flags.’
List the contents of the accounts folder.
Looking inside the enc.py
file we can see the password encryption that was used to encrypt the passwords for the users.
I downloaded it locally to modify and test it.
Looking inside the python3 enc.py
script you can see the AES encryption algorithm.
Run the python3 script with python3 enc.py
and you will get the following output.
Let’s try reverse the AES encryption. Save the following to ‘byte_decode.py’ This just cleans up the hex representation for us, so we can enter the hex values into Cyberchef.
import binascii
byte_string1 = b'\xc9;\xd4b\xce\xc15\x19;\x00Z^Nw\xafp\x10\xce/r\x0c\xf1\x1c&\x1c\x12a\xd9&b"\xc3'
hex_representation1 = binascii.hexlify(byte_string1).decode('utf-8')
byte_string2 = b'!6\x0b\xc7Xg@\xcc\xe3KY\xcfN\x9b\x81\x91'
hex_representation2 = binascii.hexlify(byte_string2).decode('utf-8')
byte_string3 = b'\x9f\xc9P\xff\xb3Z\x94\x84\x8a\xeb1\xa2/\xba\x8d\xa5'
hex_representation3 = binascii.hexlify(byte_string3).decode('utf-8')
print("KEY: " + hex_representation1)
print("IV: " + hex_representation2)
print("ENC: " + hex_representation3)
Run with python3 byte_decode.py
to clean up the hex representation.
KEY: c93bd462cec135193b005a5e4e77af7010ce2f720cf11c261c1261d9266222c3
IV: 21360bc7586740cce34b59cf4e9b8191
ENC: 9fc950ffb35a94848aeb31a22fba8da5
Now using Cyberchef enter the cleaned hex output in enc
above. If this is correct we should be able to see the original data input ’toor’ in the ouput text box, and we do!
We successfully reversed the AES encryption in Cyberchef, so we can try decrypt Anof’s base64 encoded data we found in the database earlier. But first we want to get the hex bytes of the base64 data using Cyberchef.
Decrypt Password For ANOF
from Crypto.Util.Padding import pad, unpad
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import base64
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.new(key, AES.MODE_CBC, iv)
pwd = unpad(cipher1.decrypt(b'\x54\x7e\x87\x8f\x8f\x9e\x42\x7e\x6e\x60\x65\x40\xc7\x2f\x07\xb7\xba\x64\x54\xef\x68\x78\xf5\x29\x10\xb0\xdd\x89\x71\x6a\xd5\x5d'),16)
password_text = "Password for user ANOF: " + pwd.decode('utf-8')
trophy = '\U0001F44D'
print('\n' + trophy + ' ' + password_text + '\n')
Run our python3 dec.py
to get the password for user Anof.
Cool! 🏆 Now we have the password for user Anof and proceed to get root access and complete the room.
Privilege Escalate
Switch user to anof now because we already know Anof is a member of the sudo group. All we have to do is just run sudo bash
to get a root shell.
Grab the root flag and submit.
Room Completed! 🏆🏆