|
import argparse |
|
import base64 |
|
from browsermobproxy import Server |
|
from bs4 import BeautifulSoup |
|
import os |
|
import requests |
|
from selenium import webdriver |
|
from selenium.webdriver.support.ui import WebDriverWait |
|
from selenium.webdriver.support import expected_conditions as EC |
|
from xml.etree import ElementTree |
|
|
|
parser = argparse.ArgumentParser( |
|
formatter_class=argparse.RawDescriptionHelpFormatter, |
|
description=''' |
|
python cas_auth_dance.py portal-address |
|
|
|
Requirements: |
|
chrome webdriver |
|
python 3 |
|
selenium |
|
beautifulsoup4 |
|
browsermob-proxy – ./browsermob-proxy-2.1.4/bin/browsermob-proxy |
|
''' |
|
) |
|
|
|
parser.add_argument( |
|
'portal', |
|
type=str, |
|
help='The GlobalProtect portal address' |
|
) |
|
|
|
|
|
def firewall_request(portal, endpoint, form): |
|
url = 'https://{portal}/{endpoint}'.format( |
|
portal=portal, |
|
endpoint=endpoint |
|
) |
|
headers = { |
|
'Content-Type': 'application/x-www-form-urlencoded', |
|
'User-Agent': 'PAN GlobalProtect/4.1.3-8 (Apple Mac OS X 10.14.0)' |
|
} |
|
res = requests.post(url, headers=headers, data=form, verify=False) |
|
return res |
|
|
|
def parse_prelogin_xml(xml): |
|
parsed_xml = ElementTree.fromstring(xml) |
|
tree = ElementTree.ElementTree(parsed_xml) |
|
root = tree.getroot() |
|
saml_request = root.findall('saml-request')[0] |
|
return base64.b64decode(saml_request.text) |
|
|
|
|
|
def open_login_flow(saml_request): |
|
fd = open('./prelogin.html', 'wb') |
|
fd.write(saml_request) |
|
fd.close() |
|
server = Server('./browsermob-proxy-2.1.4/bin/browsermob-proxy') |
|
server.start() |
|
proxy = server.create_proxy() |
|
chrome_options = webdriver.ChromeOptions() |
|
chrome_options.add_argument("--proxy-server={0}".format(proxy.proxy)) |
|
chrome_options.add_argument("--ignore-certificate-errors") |
|
driver = webdriver.Chrome(chrome_options=chrome_options) |
|
proxy.new_har('cas') |
|
uri = os.getcwd() + '/prelogin.html' |
|
driver.get('file://' + uri) |
|
try: |
|
WebDriverWait(driver, 3600).until( |
|
EC.url_contains('ACS') |
|
) |
|
finally: |
|
driver.quit() |
|
har = proxy.har |
|
har_entries = har['log']['entries'] |
|
server.stop() |
|
|
|
for entry in har_entries: |
|
if 'SAML2/Callback' in entry['request']['url']: |
|
return entry |
|
|
|
def get_cas_saml_response(saml_request): |
|
url = saml_request['request']['url'] |
|
form = saml_request['request']['queryString'] |
|
res = requests.get(url, data=form) |
|
soup = BeautifulSoup(res.text, 'html.parser') |
|
return soup.find('input', {'name': 'SAMLResponse'}).get('value') |
|
|
|
def get_acs_prelogin_cookie(portal, saml_request, saml_response): |
|
relay_state = '' |
|
for item in saml_request['request']['queryString']: |
|
if item['name'] == 'RelayState': |
|
relay_state = item['value'] |
|
break |
|
form = { |
|
'RelayState': relay_state, |
|
'SAMLResponse': saml_response |
|
} |
|
response = firewall_request(portal, 'SAML20/SP/ACS', form) |
|
return response.headers.get('prelogin-cookie') |
|
|
|
|
|
def main(args): |
|
tmp_prelogin_form = { |
|
'tmp': 'tmp', |
|
'clientVer': 4100, |
|
'clientos': 'Mac', |
|
'os-version': 'Apple Mac OS X 10.14.0', |
|
'ipv6-support': 'yes' |
|
} |
|
prelogin = firewall_request(args.portal, 'global-protect/prelogin.esp', tmp_prelogin_form) |
|
prelogin_html = parse_prelogin_xml(prelogin.text) |
|
saml_request = open_login_flow(prelogin_html) |
|
saml_response = get_cas_saml_response(saml_request) |
|
prelogin_cookie = get_acs_prelogin_cookie(args.portal, saml_request, saml_response) |
|
print(prelogin_cookie) |
|
|
|
if __name__ == '__main__': |
|
args = parser.parse_args() |
|
main(args) |