Sometimes at Exploitee.rs, we look for fun devices to hack and sometimes the devices find us. Today we’re going to talk about a recent time where we found ourselves in the latter situation and our experience with the Western Digital series of Networked Attached Storage devices.
In the middle of last year I (Zenofex) began looking for a NAS that provided hardware decoding through my currently prefered media player, Plex. After a bit of research I ordered a Western Digital “MyCloud” PR4100. This device met all the requirements of what I was looking for and came highly recommended by a friend. After adding the NAS to my network and visiting the device’s admin page for the first time, I grew weary of adding a new device to my network without giving it a proper audit. So, I logged in, enabled SSH access, and looked at how the web server functionality of the device worked.
I quickly found the first bug that shocked me, this bug was based on code that performed a user login check but did so using cookies or PHP session variables. Using cookies for authentication isn’t necessarily a bad thing, but the way that the Western Digital MyCloud interface uses them is the problem. Examine the code below.
$ret = 0;
if (isset($_SESSION['username']) && $_SESSION['username'] != "")
$ret = 2; //login, normal user
if ($_SESSION['isAdmin'] == 1)
$ret = 1; //login, admin
else if (isset($_COOKIE['username']))
if (isset($_COOKIE['username']) && $_COOKIE['username'] != "")
$ret = 2; //login, normal user
if ($_COOKIE['isAdmin'] == 1)
$ret = 1; //login, admin
“username” variable is set and is not empty – User is logged in as a normal privileged user.“isAdmin” variable is set to 1 – User is logged in as an administrator.
This means that any time there is a login check within the PHP scripts, an attacker is able to bypass the check by supplying 2 specially crafted cookie values.
During the process of writing up my findings a new firmware was rolled out patching the above bug. However, this patch introduced a new vulnerability which had the same consequences as the original (prior to the update). Below is the current version including the fixed code.
20 function login_check()
22 $ret = 0;
24 if (isset($_SESSION['username']))
26 if (isset($_SESSION['username']) && $_SESSION['username'] != "")
27 $ret = 2; //login, normal user
29 if ($_SESSION['isAdmin'] == 1)
30 $ret = 1; //login, admin
32 else if (isset($_COOKIE['username']))
34 if (isset($_COOKIE['username']) && $_COOKIE['username'] != "")
35 $ret = 2; //login, normal user
37 if ($_COOKIE['isAdmin'] == 1)
38 $ret = 1; //login, admin
40 if (wto_check($_COOKIE['username']) === 0) //wto check fail
41 $ret = 0;
44 return $ret;
In the updated version of the code, a call to the new method “wto_check()” is made (line 40). This function runs a binary on the device with the client supplied username as an argument along with the user’s IP address. If the user is currently logged in and hasn’t timed out the value 1 is returned, otherwise 0 is returned (indicating the user isn’t logged in). The code for the “wto_check()” method can be found below.
4 return value: 1: Login, 0: No login
6 function wto_check($username)
8 if (empty($username))
9 return 0;
11 exec(sprintf("wto -n \"%s\" -i '%s' -c", escapeshellcmd($username), $_SERVER["REMOTE_ADDR"]), $login_status);
12 if ($login_status === "WTO CHECK OK")
13 return 1;
15 return 0;
18 /* ret: 0: no login, 1: login, admin, 2: login, normal user */
In the above you can see that on line 11 the command is formatted to include the username and IP address as arguments to the “wto” binary. The problem with the above is the incorrect use of the PHP method “escapeshellcmd()” which, in its intended usage, handles an entire command string, and not just an argument. This is because the “escapeshellcmd()” function does not escape quotes and therefore allows an attacker the ability to break out of the encapsulating quotes (in our case for the “-n” argument), allowing for new arguments to be supplied to the binary. Because of this, instead of actually checking if the user is logged in, we can add new arguments and log the user in ourselves. Although we do not believe simply verifying that the user is already logged in by checking an IP address and login timeout is sufficient. The programmer who wrote this code should have used “escapeshellarg()”, which is intended to filter independent binary arguments and which does filter out quotes. Using “escapeshellarg()” as opposed to the currently used “escapeshellcmd()” would have at least prevented this attack from working.
Command Injection Bugs
A majority of the functionality of the WDCloud web interface is actually handled by CGI scripts on the device. Most of the binaries use the same pattern, they obtain post/get/cookie values from the request, and then use the values within PHP calls to execute shell commands. In most cases, these commands will use the user supplied data with little or no sanitization. For example, consider the following code from the device.
The code above assigns a value from the COOKIE superglobal variable, which contains array indexes for cookies submitted from the request, to the local variable “$username”. This value is then immediately used in a PHP “exec()” call as an argument to the local “wto” binary. Since there is no sanitization, using a username value like
turns the existing exec command into
wto -n "$(touch /tmp/1)" -g
and executes the user supplied command within.
Because the argument is encapsulated with double quotes and we use the “$(COMMANDHERE)” syntax, the command “touch /tmp/1” is executed prior to the execution of the “wto” binary and the return value of which is used as its “-n” argument. This basic pattern resulting in a command injection vulnerability is used multiple times within the many scripts used by the web interface. While some may have normally been prevented by authentication being required, that restriction is overcome by the authentication bypass mentioned above. Also, it is important to note that all commands executed through the web interface are done so as the user the web-server is running as, which, in this case is root.
While you may think that the above bugs are severe, there are a number of other errors within the web interface with some being as simple as the normal authentication being commented out:
The above code consists of no checks for authentication and, when called will simply retrieve the uploaded file contents and use the user supplied path to determine where to place the new file.
Beyond the bugs listed in this blog post, our wiki is full of bugs we’ve found within the MyCloud web interface. Our general goal at Exploitee.rs is to get bugs fixed as quickly as possible. However, the large number of severe findings means that we may need to re-evaluate the product after the vendor has properly fixed the released vulnerabilities.
At Exploitee.rs, we normally attempt to work with vendors to ensure that vulnerabilities are properly released. However, after visiting the Pwnie Awards at the last BlackHat Vegas, we learned of the vendor’s reputation within the community. In particular, this vendor won a “Pwnie for Lamest Vendor Response” in a situation where the vendor ignored the severity of a set of bugs reported to them. Ignoring these bugs would leave the vulnerable devices online for longer periods while responsible disclosure is worked out. Instead we’re attempting to alert the community of the flaws and hoping that users remove their devices from any public facing portions of their networks, limiting access wherever possible. Through this process, we’re fully disclosing all of our research and hoping that this expedites the patches to users’ devices.
Bugs Found Statistics
1 x Login Bypass
1 x Arbitrary File Write
13 x Unauthenticated Remote Command Execution Bugs
70 x Authentication Required Command Execution Bugs*
*”Authentication Required” bugs can be reached with the login bypass bug.
Most, if not all, of the research can be applied to the entire series of Western Digital MyCloud products. This includes the following devices:
My Cloud Gen 2
My Cloud Mirror
My Cloud PR2100
My Cloud PR4100
My Cloud EX2 Ultra
My Cloud EX2
My Cloud EX4
My Cloud EX2100
My Cloud EX4100
My Cloud DL2100
My Cloud DL4100
For the complete listing and a small write-up on each of the bugs found during our Western Digital MyCloud research, visit the Exploitee.rs Wiki.
For updates on Western Digital’s response or alerts when new content is added to our wiki or blog follow us on twitter @Exploiteers