┌──(root@stanleyjobson)-[/publications]

└─# ./publications tp-link

Overview

I discovered a remote code execution vulnerability within the Web Portal of the TP-Link Archer VR1600V router.
This vulnerability can be exploited via a single HTTP request and allows an attacker with administrative access to the
web portal to gain administrative access to the underlying operating system. It is important to note that the
vulnerability requires local network access and cannot be exploited over the internet. The impacts of this
vulnerability are severe and wide-ranging. An attacker could modify the contents of the device and cause a loss of
availability to the device by deliberately modifying certain data within the device which would cause a boot failure on
the device. Furthermore, the confidentiality of the binaries and firmware could be compromised, as they would now be
accessible to the attacker. This would also allow an attacker to modify running configurations outside the parameters
of the vendor, potentially causing additional security issues. I followed responsible disclosure guidelines and
coordinated with the vendor to ensure that the vulnerability is patched in a timely and secure manner.

Technical Details

The vulnerability affects devices with a firmware version of <= 0.1.0 0.9.1 v5006.0 Build 220518 Rel.32480n.
The root cause of the issue is that a specific variable called X_TP_IfName that is passed to the web server
in a POST request during certain operations within the web portal is passed directly into an Operating System command.


The issue occurs because the user can supply arbitrary values within this variable including shell metacharacters
which can be used to 'break out' of the intended command and then run additional commands. While there was some
sanitization performed on this parameter (it was restricted to 15 characters which is not a lot of room for command
injection). A suitable bypass was eventually found which enabled unlimited code execution on the device.


As a simple example, consider the following scenario: There exists a service within a web page which checks if
another host is online. It may utilize the built-in "Ping" command to do this. The service will take a variable
called "host" from the user and then construct the following operating system command: ping -c 4 returning
the result to the end user. Secondly, there exists methods to "stack" commands. For Linux operating systems, the ';
' character can be used to append a command (e.g. ping 127.0.0.1; echo a) which will first execute the ping, then
execute the echo command. Referring back to our example, the service will work if the user supplies the expected
value (e.g. a website name or an IP address). However, if the user supplies the character to stack a command,
followed by another arbitrary command, they can get underlying code execution on the system even though it was not
intended.


So a vector is in hand to achieve command execution, however it is extremely limited. 15 characters is not enough
to build a traditional reverse shell. There are several possible options. One option is to use the vulnerability
repeatedly to build a script character by character, make the script executable with the chmod command and then
execute it directly via the vulnerability. This was not possible as the underlying operating system was a Linux
MIPS operating System which did not include the "print" command. The print command is a prerequisite for this sort
of method because it does not print a trailing new-line character which is a must for building the script character
by character. Trying to do this using the available 'echo' command resulted in new-lines being inserted into the
script on each execution rendering it useless. Another method to consider was using an available binary to expose
pseudo operating system access or shell access. Two prerequisites are needed for this a) the ability to use the
binary to create a shell and b) the ability for the binary to be remotely exposed by binding to the local network
interface (because we don't already have local shell access).


After searching, telnetd was identified as a candidate where we can expose a shell even with the character
restrictions. There is a feature of telnetd where you can specify what program to run on the telnet daemon using
the "-L" flag. By default this is /bin/logon. However we can specify an arbitrary program, including the shell
binary (sh) which would provide a TTY interface. This meets our first prerequisite. The telnet daemon is a well
known program for remotely interacting with systems. It by default binds to Port 23 on the local network. A port
can also be specified with the "-p" parameter, however there is not enough room for this. Therefore we are limited
to the default Port of 23. However this satisfies condition two, that the binary be able to be remotely exposed. We
can therefore specify the 'sh' shell to be tied to the telnet daemon and exposed via Port 23 with the following
command: 'telnetd -l sh'. Including the two stack command characters, this totals exactly 15 characters. Just
enough to fit into the injection point. As the web server is running as admin, the shell exposed via the interface
is admin too. This gives us total remote access to the device.


That being said, it is important to note that the web portal is not exposed remotely, and this is a completely
local attack vector which cannot be exploited via the internet. As a result, an attacker must have local network
access to the device and given we are required to access the administrator portal, must have administrative access
as well. This is typically a default set of credentials but can be configured by the user.

Reproduction Steps

The vulnerability can be demonstrated with the following request:

POST /cgi?2 HTTP/1.1
Host: 192.168.1.1
User-Agent: python-requests/2.20.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
TokenID:
Referer: http://192.168.1.1/
Cookie: JSESSIONID=
Content-Length: 81

[WAN_IP_CONN#1,7,1,0,0,0#0,0,0,0,0,0]0,2
X_TP_IfName=;telnetd -l sh;
enable=1

Disclosure Timeline

15-Jan-2023 - Issue identified
27-Jan-2023 - Issue submitted to TP-Link Security
29-Jan-2023 - Issue confirmed received by TP-Link
03-Feb-2023 - Issue confirmed by TP-Link Security
06-Mar-2023 - Beta Firmware tested and issue confirmed Fix
14-Apr-2023 - Issue confirmed fixed in latest available firmware