The Anatomy of a Bug Door: Dissecting Two D-Link Router Authentication Bypasses
October 01, 2020 | Vincent LeeBack in February, D-Link released a firmware patch for two authentication bypass vulnerabilities, ZDI-20-267 (CVE-2020-8863) and ZDI-20-268 (CVE-2020-8864), that affected the D-Link DIR-882, DIR-878 and DIR-867 routers. These wonderful bugs resided in the handling of the HNAP protocol. The vulnerabilities were discovered and reported to the Zero Day Initiative by chung96vn of VinCSS (Member of Vingroup).
We’ll first look into ZDI-20-268 to familiarize ourselves with HNAP’s authentication scheme. After that, we’ll analyze the rather peculiar ZDI-20-267, which has the word “backdoor” written all over it.
But first, what is HNAP?
HNAP, or Home Network Administration Protocol, is a proprietary SOAP-based protocol invented by Pure Networks, Inc., which was later acquired by Cisco. This protocol dates back to 2007 and can be thought of as a direct competitor of UPnP. The prominent users of this protocol were Cisco and D-Link. However, both have discontinued the use of this protocol in 2012 and 2016 respectively. This functionality is often hidden from the administrative panel, making it impossible to disable. If your router still supports HNAP, it probably means your router is due for an upgrade.
Being an obsolete proprietary protocol, little documentation for it exists on the Internet. HNAP offers two types of authentication schemes: Basic and HMAC-based. The best documentation on the HMAC-based authentication scheme I could find is a Github wiki page from a reverse engineering project.
HNAP Authentication Process
Authentication to the server (router) requires two transactions. First the client sends a request
message and obtains an authentication challenge from the server.
The server responds to the request with three values: Challenge
, Cookie
and PublicKey
The client must first combine the PublicKey
along with the user password to create a PrivateKey
. Take note of this as it will become important later. The client will then use the newly generated PrivateKey
and the Challenge
to generate a new value. The client places this value in the LoginPassword
field of the login
message as a response to the challenge issued by the server:
The server can authenticate the client by independently computing the PrivateKey
and LoginPassword
using the user account password on record, calculating the expected response to the Challenge, and comparing it with the LoginPassword
supplied by the client. If the values match, the client has successfully authenticated itself.
ZDI-20-268/CVE-2020-8864
This authentication bypass vulnerability is caused by the incorrect use of strncmp()
to compare the server-calculated LoginPassword
with the LoginPassword
presented by the client. Below is the control flow diagram of the vulnerable function:
In essence, the above segment of the control flow graph describes the following common vulnerable code pattern:
When attacker_provided_password
is an empty string, strlen()
returns 0. Then, since strncmp()
is called with a length parameter of 0, it does not compare any characters at all. Instead it returns a value of 0, indicating equality. In ZDI-20-268, if an attacker provides an empty LoginPassword
value, strncmp()
will return 0 and follow the code path for successful authentication.
ZDI-20-267/CVE-2020-8863
The title for this vulnerability reads:
D-Link Multiple Routers HNAP PrivateLogin Incorrect Implementation of Authentication Algorithm Authentication Bypass Vulnerability
The word “PrivateLogin” arouses curiosity. To whom is this Login private? Let’s take a look at how the router processes an HNAP login request to find out how this PrivateLogin backdoor was implemented in a few lines of code.
When authenticating through HNAP, the server normally generates the PrivateKey
based on the user’s password. However, something different happens when an attacker provides an additional <PrivateLogin>
element in the Login request. The server instead generates the PrivateKey
with the value of the Username
element instead of the user password. Below is an example of an authentication-bypassing request:
Below is Ghidra’s decompiler output of the function responsible for generating the authentication challenge values provided by the researcher:
At line 31, the contents of the PrivateLogin
element, if present, is extracted from the login request and stored in the PrivateLogin
variable. The Username
element is also extracted and stored in the Username
variable a few lines above.
The PrivateLogin
variable is later used at line 58. The if
condition can be understood more easily if we apply the De Morgan’s Law. The condition checks that the PrivateLogin
element is present and further ensures the PrivateLogin
element contains the string “Username”. If both conditions are satisfied, the value of the Username
element (i.e. “Admin”) will be copied into the Password
variable with strncpy()
. This differs from the normal code path where the router would call GetPassword()
to read the admin password from NVRAM.
At line 65, the now tainted Password
is passed into GenPrivateKey()
for the generation the Challenge
, Cookie
, and PublicKey
values for the authentication challenge. As a result, an attacker now knows all the all the required values to recreate the PrivateKey
and respond to the authentication challenge without knowing the real admin password to the router.
Conclusion
How did this backdoor get into the product? Why did the developer write these lines of codes? Was it part of the manufacturer’s original design? Or were these lines of code written by a rogue employee? Why didn’t a code review catch that? Was there any code review process? Was ZDI-20-268 also coded intentionally as an alternate means of maintaining a foothold? We don’t have answers to any of the above questions. However, we know for certain the existence of such vulnerabilities in the firmware is symptomatic of larger problems and warrants more action on the vendor’s part than merely shipping a patch.
Perhaps it is time to consider consumer-grade routers disposable items. The hardware has a tendency to last longer than the support lifecycle. We also saw this earlier this year when NETGEAR decided not to patch 45 models of home routers, instead choosing to designate them as out-of-support. Those shopping for new routers should consider how many years of manufacturer support will be available when making their purchasing decisions. It will certainly help ensure fewer security-related headaches in the future.
You can find me on Twitter @TrendyTofu, and follow the team for the latest in exploit techniques and security patches.