DISCLAIMER: The author is not responsible for the misuse of the information contained in this post.
The Dlink DVA-5592 shows a status page right after logging in. This page contains, as shown below, sensitive information such as the password of the Wi-Fi.
The URL for the status page is http://192.168.X.X/ui/status/ and if one tries to access it without being logged in, they are redirected to the login page. The status page, as you might have noticed, has a language button in the up-right corner that, surprise surprise, is used to change the language of the interface. Selecting a different language causes a request been performed to the following URL:
http://192.168.X.X/ui/status/content?lang=YY See the
content path right after
status? The response obtained from requesting that URL contains the text in the selected language along with sensitive information I carefully redacted in the screen-shot above. Whenever I see the possibility of accessing the same information from different URLs, I automatically check if these URLs properly verify that the request is authenticated.
Turns out that if you request
http://192.168.X.X/ui/status/content, the router’s web interface does not check the session cookie, meaning that Dribble, or anybody else connected to the router, does not even need to brute-force the login page to have access to the Wi-Fi password.
This is particularly interesting not only for Dribble, but also in a scenario where the DVA-5592 is configured to have a guest Wi-Fi network with hosts isolation enabled. Users connected to the guest Wi-Fi can easily retrieve the password for the “main” Wi-Fi network and have unauthorized access to it.
Nothing really special here. While playing with the D-Link DVA-5592 I thought about messing around a little with some parameters to see if I could find something else. It turns out that some parameters are vulnerable to Reflected Cross-Site Scripting. It also turns out that there’s a parameter called
action__key which acts as a Cross-Site Request Forgery token which makes the Reflected Cross-Site Scripting to fall into the “Self” category. The issue is spread throughout the all web interface and gets triggered whenever an input generates an error and the same input is reflected in the same form along with the error message.
Here I show an example of the vulnerability in the page used to create a new user for accessing a shared folder. If the username is something like
a"><script>alert('xss');</script>, the web interface generates an error and reflects back the value of the username in the input form.
POST /ui/dboard/storage/storageusers/addstorageusers HTTP/1.1
In the response you can see the payload being reflected.
HTTP/1.1 200 OK
Date: Thu, 24 Jan 2019 11:19:25 UTC
Server: HTTP Server
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<title>Residential Gateway - D-Link</title>
<div class="formField" id="password">
<input type="password" autocomplete="off" name="password" value="a"><script>alert('xss');</script>" autocomplete='off'/>
<span class='text' style='visibility:hidden'><input type='checkbox' name='passwordShow' tabindex='-1'/> mostra password</span>
fieldPassword('password', 'passwordShow', 1, 0);
<span class='texterror'>Groups not configured</span>
Which ultimately shows the canonical alert box.
This issue was the one that made me chuckle, a complete authentication bypass of the web interface of the Alcatel LINKZONE MW40-V-V1.0. Just a quick recap: I was looking into the login process of the Alcatel LINKZONE MW40-V-V1.0 to implement a brute-forcer to include in Dribble. First of, the web interface of the Alcatel LINKZONE MW40-V-V1.0, by default, is not password protected.
This already makes it easy in case you’re targeting the average user but, of course, I wanted to make sure that the whole thing could work also when the user had setup a password. Once I started to analyze the HTTP traffic, I soon learnt that the front-end uses the JSON-RPC standard to communicate with the back-end. The whole front-end is downloaded the first time you visit the web interface and after that all the info related to the status of the router are retrieved with JSON-RPC calls. All I needed was to find the request that accessed the Wi-Fi password, and soon enough I found it to be this one:
POST http://192.168.1.1/jrd/webapi HTTP/1.1
Nice, the value for
_TclRequestVeerificationToken seems to be some sort of verification token, so now what I need is to find out how that token is generated.
However, before I could even start looking into it, another request caught my attention:
POST http://192.168.1.1/jrd/webapi HTTP/1.1
This request is generated whenever I want to perform any action prior to the login and already contains the
_TclRequestVerificationToken … weird. That
GetLoginState also seems interesting, and the response contains even more interesting stuff.
HTTP/1.1 200 OK
You are telling me that the front-end is asking
GetLoginState, the request already contains the value for
_TclRequestVerificationToken without being logged in, and the back-end is answering with
"State": 0 …
The front-end is simply “blocking” what are suppose to be unauthenticated users from viewing the content of the web interface. All one needs to do is intercepting the response to the
GetLoginState request and change the value of
1 and voilà… you are now logged in.
This is the main reason why this post comes so late. Here’s the deal: I contacted Alcatel to notify the vulnerability, but Alcatel doesn’t seem to have a security response team. I figured I would give a try with the “general” support team. They answered pretty fast but they couldn’t really understand what I was trying to tell them. I thus shot a short video showing that it was possible to have access to the router without knowing the password. They finally told me that they would look into it but there wouldn’t be any further communication from their side.
D-Link, on the other hand, does have a Security Incident Report Team. I contacted them and provided all the details of the two issues and they told me to ask for the CVEs myself and that they would contact me after looking into the issues. They also said it shouldn’t take longer than a few days. Over a month and three e-mails later … still no news from their side.
So what about the CVEs then? CVEs are like Pokémon gym badges, the more you have the more Pokémon will respect you …
I asked for CVEs … a couple of months ago or so and still no news so …
(OK, the CVEs have been allocated, of course, but are still in the RESERVED state.)
While looking for ways to easily get the Wi-Fi password from the only two routers I have constant access to (a D-Link DVA-5592 and an Alcatel LINKZONE), I discovered that both do not correctly implement an authentication mechanism. For the D-Link this is “limited” to a status page which also contains the password of the Wi-Fi in clear text. The Alcatel, on the other hand, lacks of proper authentication entirely which results in a complete takeover of the web interface.
I am very happy I finally managed to find the time to implement Dribble, not only because it was in my TO-DO list for a very long time and I could finally scratch it off (I really like to scratch things off), but also because working on it resulted in some collateral findings, which I believe to be a very satisfying way to discover something new.