Remote Root in DirecTV's Wireless Video Bridge: A Tale of Rage and Despair

UPDATE: After the initial publication of this blog, an official Belkin spokesperson reached out to the ZDI to confirm this bug is being fixed. They stated DirecTV/AT&T will be addressing this through WVB Firmware version 1.0.41. The firmware is rolling out to customers now, and they expect the firmware rollout to be completed by 12/20. We are pleased to know they actively correcting this bug. We thank the folks at Belkin for reconsidering this matter and look forward to working with them again in future.

Original post:

In this guest blog, Trend Micro DVLabs researcher Ricky Lawshae discusses the recently disclosed CVE-2017-17411. He discovered and reported this bug through the ZDI program.

Earlier this year, I learned that AT&T was starting to move customers away from its U-Verse service in favor of its DirecTV offerings. As a U-Verse customer, I saw a chance to try out a new service while saving some money at the same time, so I decided to give it a shot. After the installation was over, I found myself with a slew of new devices on my network, all begging for me to come and play with them. Today, the ZDI published an advisory about a zero-day vulnerability in of those devices. Gather round, my friends, as I relate to you the story of what I found during my investigation.

First, a quick demonstration that results in a root shell on the device in question:

Getting to Know the Linksys WVBR0-25

As was the case with U-Verse, DirecTV also has wireless cable box options for making installation easier. The Wireless Genie Mini (C41W) cable box pairs with a wireless video bridge to communicate with the main Genie DVR. The wireless video bridge in this case was a Linksys WVBR0-25. I had a bad experience with a wireless video bridge like this in the past, so it seemed like a good place to start looking for problems. I started out by trying to browse to the web server on the device. I expected to find a login page of some sort. What I found instead was a wall of text streaming before my eyes.

Instead of a login prompt or an index page of any kind, I was presented with the output of several diagnostic scripts containing just about everything you could want to know about the bridge, including the WPS pin, connected clients, running processes, and much more. This by itself is pretty bad as far as information disclosure goes, considering there was no authentication needed to get to this information, but I continued looking through it anyway. About halfway down the page, it started spitting out the contents of log files, and while scanning through those I saw something that made me stop dead in my tracks. With teeth clenching and knuckles turning white, I managed to get out a strained "WHAT...IS...THAT??" before attempting to confirm my suspicion.

The Easiest Command Injection Ever

A few lines in this log file, prepended with sys_cmd, seemed to indicate that they were using my IP address and user-agent in a system command to create an MD5 hash. Ostensibly, this is used as some form of access logging or tracking functionality. The logs showed the exact command that was being run and the subsequent output of that command. The problem here, however, is that users have complete control over what they want to send as a user-agent header. I surmised that if the device isn't properly sanitizing the user-agent it is given, it would be sending untrusted data directly to the system for execution. There’s no way that could be the case though, right?

Thanks to the verbose logging on this page I could see that changing my user-agent to "; id; uname -a #" had indeed changed the syntax of the command to be executed. The return value also showed the device had happily executed my new commands and executed them as the root user, too! No login prompt. No input sanitization. Very helpful, verbose output. It literally took 30 seconds of looking at this device to find and verify an unauthenticated remote root command injection vulnerability. It was at this point that I became pretty frustrated. The vendors involved here should have had some form of secure development to prevent bugs like this from shipping. More than that, we as security practitioners have failed to affect the changes needed in the industry to prevent these simple yet impactful bugs from reaching unsuspecting consumers. So, once I finally managed to regain my composure, I decided to buy one of these off eBay to tear apart and figure out exactly what was going on.

Examining the Firmware

The device has an Entropic ARC processor and an MXIC MX25L12845E 128Mb serial flash chip for firmware storage. I pulled the flash chip off the board and dumped its contents over the SPI bus by connecting it to my Bus Pirate and running the very useful flashrom program against it. Using binwalk to examine the resulting binary file showed, among other things, a squashfs filesystem that contained all the files I needed to root-cause this vulnerability.

Bus Pirate connected to SPI pins of serial flash chip

The device was running a lighttpd web server, and as defined in its configuration file, browsing to the root of the web site would result in /dispatcher.cgi?template=SysInfo.asp being rendered. The SysInfo.asp file was the page responsible for displaying all the diagnostic output I was seeing. It also showed dispatcher.cgi was actually a symbolic link to apply.cgi, which itself is a compiled ARC executable file used as kind of a “do everything” agent for the web server. It was in apply.cgi that I found the actual root cause.

Disassembly of vulnerable portion of apply.cgi

As you can see in the screenshot above, the sys_cmd message is output to the log with the supplied command string using a function called ulogf(). After that, the command is passed without any input sanitization to popen() to execute. Since the lighttpd process is run with root privileges, any commands executed by the popen() call will be run with root privileges as well. A bit later, you can see the exit status and output of the command get logged as well after a subsequent call to pclose(). Using system() or popen() to execute commands from untrusted input is about as textbook as it gets with regard to command injection. The logging just made it that much easier to find and exploit.

Vulnerability Disclosure

After verifying and root-causing the vulnerability, I submitted a bug report to the ZDI program. They attempted to work with Linksys to get it fixed, but unfortunately the vendor ceased being responsive, all deadlines have long since expired, and this bug is now being publicly disclosed.

06/14/17 - ZDI disclosed the report to the vendor (security@linksys.com)09/14/17 - ZDI sent a follow-up to the vendor requesting a status update10/10/17 - ZDI sent a follow-up to the vendor requesting a status update11/20/17 - ZDI notified the vendor of the intent to release the 0-day report on 12/12We have never received any reply.

Needless to say, due to the ease of exploitation and the potentially vast install base, disclosure in this manner is less than ideal. However, we have seen devices like this one used in botnets in the past. Consumers and enterprises alike should be made aware of the risks of having these devices on their networks. There’s also the non-zero possibility of someone else finding this vulnerability and incorporating it into exploit kits or malware. In the absence of an actual patch from the vendor, users should protect themselves by limiting the devices that can interact with the WVBR0-25 to those that actually need to reach it. It should also be noted that the DVLabs filter team wrote and shipped filter 29060 back on July 6, 2017, which protects Trend Micro customers from this attack.

I hope you enjoyed sharing in my pain as I went on this little adventure! You can find me on Twitter at HeadlessZeke, and follow the ZDI team for the latest in exploit techniques and security patches.