In a previous post we shared our considerations on the impact of vulnerabilities in Internet connected devices that are EoL. We used the vulnerabilities that we identified in the D-Link DSL-2640B DSL gateway as a use case to support our considerations. In this post we describe the technical details of these vulnerabilities.
Before we dive into the technical details, it's important to note that:
- all vulnerabilities are (at least) applicable to the D-Link DSL-2640B (HW revision B2, Firmware version: EU_4.01B)
- all vulnerabilities apply to the latest available firmware (as of 27/03/2020)
- all vulnerabilities have been reported to D-Link
- we are not aware of any security fix released by D-Link
- as the device is EoL, following D-Link's policy, no fix may ever be available
The vulnerabilities described in this post may apply to other hardware revisions, other firmware versions and even completely different models. We did not investigate this further and D-Link did not provide any additional insights.
The following vulnerabilities are described in this post:
- CVE-2020-9275 – D-Link DSL-2640B - Remote credentials exfiltration
- CVE-2020-9279 – D-Link DSL-2640B - Hard-coded privileged account
- CVE-2020-9278 – D-Link DSL-2640B - Unauthenticated configuration reset
- CVE-2020-9277 – D-Link DSL-2640B - CGI Authentication bypass
- CVE-2020-9276 – D-Link DSL-2640B - do_cgi buffer overflow
We hope we provided sufficient technical details of the identified vulnerabilities. Additional information (e.g. video demonstrations) may be provided in the future.
We hope you enjoy the technical remainder of this post! :)
CVE-2020-9275 – D-Link DSL-2640B - Remote credentials exfiltration
This vulnerability allows retrieval of the administrative password by sending a specific UDP packet to port 65002 of the device.
An attacker connected to the WiFi or the local LAN, or who is able to reach the internal device interface in any other way, can retrieve the device password with a single
Most functionality of the device, including the administration panel and the web server, are implemented in a single process named
cfm executed at startup. The
cfm process listens on
65002. Likely to support device configuration from a dedicated application. The screenshot below, shows the function implementing the communication protocol. The function name,
pcApplication, is taken directly from the binary's symbols.
Communication is done using D-Link's proprietrary protocol for which no information is publicly available. Reversing the
cfm binary yields the following structure for the protocol packet.
Several commands are supported and accessible by specifying the command code in the 2 bytes
cmd field. Communication is in plaintext and without authentication. The code only checks, for some commands, that the provided
MAC address matches the device
\x00\x01 allows retrieving system information from the device, including the device administrative password which is returned in plaintext. For example:
python -c 'print("\x00\x01"* 5)' | nc -u 192.168.1.1 65002 ####MAC_ADDRESS####<boardID=D-4P-W><sysVersion=EU_3-10-02-3B00.A2pB022g2.d20h> <sysModel=DSL-2640B><local_username=admin><local_password=password> <local_ipaddress=192.168.1.1>
The MAC address check mentioned earlier is not performed for the
\x00\x01 command. Any additional bytes are completely ignored which allowed us to identify the vulnerability in a very trivial manner.
In fact, we found this vulnerability using a rather dumb fuzzing campaign. To start, we simply piped
65002. Obviously, we did not think this approach would yield vulnerabilities in any way. Especially because no traffic monitoring, no payload selection and no target debugging were in place. However, surprisingly, the device kindly returned the administrative password within a few minutes…
time cat /dev/urandom | nc -u 192.168.1.1 65002 &ZLM���<boardID=D-4P-W><sysVersion=EU_3-10-02-3B00.A2pB022g2.d20h> <sysModel=DSL-2640B><local_username=admin><local_password=a> <local_ipaddress=192.168.1.1>^C real 2m53.240s user 0m0.599s sys 0m21.439s
Due of the (very) forgiving implementation, any
UDP packet with
\x00\x01 at the right location would return the administrative password. Even our initial dumb approach yielded the administrative password within minutes.
Our initial test identified the vulnerability is exploitable from the LAN. Nonetheless, the service seems to be listening on all the interfaces (see below).
Unfortunately, we were unable to verify the vulnerability on the WAN side as we lacked a suitable DSL connection. Using the information we have, we cannot exclude that the vulnerability is also exploitable on WAN side. Of course, we would be happy to hear more insight on this.
CVE-2020-9279 – D-Link DSL-2640B - Hard-coded privileged account
For this vulnerability we identified is a hard-coded user account. An attacker may use these credentials to login into the device in order to perform administrative tasks.
The vulnerability was identified by analyzing the authentication process accessible via the web interface. While the
cfm process provides the communication "plumbing", the actual authentication is delegated to an external library
libpsi.so. The library uses an object-oriented approach for handling the authentication credentials and the incoming authentication requests.
An analysis of the
cfm process revealed a code path supporting authentication for the user named
default passwords used for authentication are hard-coded in the
Reverse engineering this library told us that the following
default credentials can be used for logging into the web interface of the device.
Username: user Password: 00202b004720
Although the password of the user
user can be changed, no web interface control is provided for modifying it. Therefore, this password will be set to its default state for the entire life time of the device. It is important to note that the account is valid for authenticating to any service relying on
lipsi.so, such as
ssh. As far as we know, the user
user has similar capabilities as the
Interestingly, even though
libpsi.so is only released in binary format, the credentials are clearly visible in the GPL source code of the device (see picture below).
Also, interestingly, these credentials are referred to as
ASUS_USER_ACCOUNT. One may wonder how an ASUS related account ends up in a D-Link device.
The source code itself does not reveal any intention of obfuscation. The credentials seem to be valid for other ASUS devices as well. ASUS refers to them as the
ASUS Super account in some old pages.
One could say that it's basically an ASUS
feature ( :-) ) which ended up for some unknown reason in a D-Link device. The supply chain of IoT devices are definitely not devoid any mysteries. We believe it may be the result of some "supply chain magic" rather than malicious intent.
The last remark we would like to make is that this vulnerability may be exploited through browser pivoting. A malicious website, visited with any device connected to the WiFi/LAN, may perform crafted requests towards the gateway.
CVE-2020-9278 – D-Link DSL-2640B - Unauthenticated configuration reset
This vulnerability allows an attacker to reset the device to its default configuration by accessing a specific URL. No authentication is required.
In fact, the following URLs can be accessed without authentication.
Specifically, the device can be reset to default factory configuration by simply requesting the following URL:
An attacker may reset the administrative password to its default value
admin, log in and perform any administrative tasks on the device, such as upload of malicious firmware or configuration of malicious DNS servers.
While the exploitation of this vulnerability requires access to the device LAN interface, it can also be remotely exploited via browser pivoting. An attacker in control of a malicious website may blindly reset the configuration of the device and, under some conditions, take full control of the device.
CVE-2020-9277 – D-Link DSL-2640B - CGI Authentication bypass
The CVE-2020-9277 vulnerability allows bypassing the authentication process for authenticated resources. An attacker may be able to directly access administrative functions of the web interface, without the need to supply valid credentials.
The web server first identifies (1) whether the requested
URL requires authentication. The check is carried on by analyzing the requested file extension, located at the
end of an
URL. For instance, accessing administrative
cgi modules requires authentication. The authentication is not performed immediately but delayed at a later point in the code.
The code then identifies (2) special resources for which the authentication is not necessary. Examples are images or
start of an
URL with the specific string (e.g:
utils.js) using the
strncmp() function. If a match is found, no authentication is performed, regardless of the outcome of (1). The request is then further processed as it had been successfully authenticated.
Finally, if a
cgi module is requested, the
do_cgi() function determines (3) the module to be executed by searching the module name
anywhere in the
URL, using the
All the above checks act in isolation, no state is carried over. An attacker can then craft malicious URLs for bypassing authentication for
cgi modules. The attack URL below changes the device admin password to newpass without any need for authentication:
Original URL: http://<device_IP_address>/redpass.cgi?sysPassword=newpass Attack URL: http://<device_IP_address>/images/redpass.cgi?sysPassword=newpass
This vulnerability gives an attacker full device control and allows performing unauthenticated administrative functions. This vulnerability requires accessing the device LAN interface, but it is suitable for exploitation via browser pivoting, allowing for remote attacks over the Internet.
CVE-2020-9276 – D-Link DSL-2640B - do_cgi buffer overflow
This vulnerability is a buffer overflow occurring in the
do_cgi() function, while parsing the requested
cgi module name. An attacker may execute arbitrary code on the device with administrative privileges, by supplying a malicious
cgi module name in the URL.
do_cgi function, in order to identify the module to be executed, copies the module name on the stack. However, it does not check whether the length of the supplied module name fits in the allocated buffer (see picture).
cgi module name will overwrite the return address saved on the stack, allowing for a classical stack buffer overflow which is easy to exploit.
do_cgi() function can, in principle, only be accessed after authentication. However, unauthenticated exploitation of this vulnerability is possible by combining it with CVE-2020-9277. In the picture below we exploit this vulnerability without authentication, execute a reverse shell payload.
While the vulnerability is potentially exploitable via browser pivoting, exploitation may not be trivial due to the URL mangling introduced by the browser when applying URL encoding on the outgoing requests.