In this article, we will be detailing an issue we discovered affecting a number of low-cost devices. It allowed for adversaries to remotely execute commands on the devices as a privileged user if they were in a position to conduct a Man-in-the-Middle attack. The binary responsible appears to be an insecure implementation of an OTA (Over-the-air) mechanism for device updates associated to the software company, Ragentek Group, in China. All transactions from the binary to the third-party endpoint occur over an unencrypted channel, which not only exposes user-specific information during these communications, but would allow an adversary to issue commands supported by the protocol. One of these commands allows for the execution of system commands. This issue affected devices out of the box.
On Tuesday, November 15th, the New York Times reported on an issue affecting a similar set of device manufacturers that caused the devices to report sensitive material, such as text messages and the user’s previous physical locations, back to the Chinese software company Shanghai ADUPS Technology Co., Ltd. This was an issue discovered and announced by Kryptowire, and covered in more detail in a posted article on their website. The issue described in this article is unrelated to the one discovered by Kryptowire.
We acquired one of the affected devices, a BLU Studio G, from Best Buy. After building a passive network traffic capturing system, an unencrypted transaction to the Ragentek head-end (oyag[.]lhzbdvm[.]com) was observed not long after proceeding through the Android first-use setup process on the device:
The device then attempted to contact two other pre-configured domains, which were previously unregistered until AnubisNetworks acquired them. This gave us immediate visibility into the larger population of affected devices, which are detailed later in this article. We were able to associate the network transactions back to specific binaries on the device, and were the ones investigated as part of this analysis:
The fact that the device reached out to defined head-ends immediately after initialization implies that the devices are affected by this issue out of the box, and were not subsequently compromised through other means, such as through a subsequent update.
Endpoints and Hosts
This binary has been observed to cycle through three specific hosts:
Only one HTTP Path has been seen in use when communicating with these hosts:
Submissions have been only been observed as a HTTP POST with the data blob passed as a parameter named ‘data’ in the URL, e.g.:
The set of HTTP headers from the client are consistent between the head-ends, with the exception of the Host header, which does not use the actual DNS host but uses the IP address of the host. An example is below:
The name of the command from the client is contained in the ‘name’ key of the pseudo-json blob that is sent as described above. The known key types and their expected responses are listed below for each command.
This command appears to be purposed for checking itself into the designated head-ends. Based from the response from the head-end, the device could enter either one of three states:
- Sleep for 6 months until the process restarts, or more likely until the device is rebooted.
- Enter a period of checking in via the “c_get_msg” command at an interval of every 10 minutes.
- If the “c_regist” request remains unanswered, as is the case for the majority of devices at the moment, it will try again in 10 minutes.
It’s worth noting that any response could be issued to the device in response to “c_regist” or “c_get_msg”. Through traffic analysis and simulated clients, any submission to the Ragentek head-end thus far using the c_regist command results in an immediate TCP RST response.
The payloads typically seen for this command contain mixed-use datatypes in the key values, but the key is always the same. Below is a sample of the values observed from the test device:
As shown above, this payload contains information such as the device model and version, the user’s phone number, their IMEI, among other identifiers, and is transmitted unencrypted.
The server is able to respond to requests from the client, but since the actual Ragentek head-end did not issue any commands in the course of this analysis, this had to be discovered by further investigation of the binary. By determining that it utilized Rui Maciel’s JSON library, it was straightforward to reverse the expected data structure of the server response. As shown below:
The values for “code” are strings, and are either:
The value of the “name” field was the desired command that server wished to issue. The protocol supports six defined command types:
The “details” JSON key value varies by command, but is also always a JSON object.
The most notable of the aforementioned commands is “push_commands”. The push_commands function allows the head-end to execute an arbitrary command of its choice on the device. In the communication structure, it requires a “details” JSON object of the following schema:
Before the command is executed, the values of “title” and “comments” are written into the local sqlite database. Whether it was successful, for example due to database error, the value of “commands” is executed via a system call. Despite the name of the key, it is a string, and not a list of commands. The client will subsequently send a “c_update_commands” message to the head-end, with a status value of “61”. If the client received a valid-form JSON back from the server, it will access the local database to likely log the response from the server.
Using the described information above, an example response from the server could thus be:
We also investigated where the debugs binary was referenced throughout the system and in other processes from a firmware image downloaded from one of the device brand websites. Two other important pieces of information were discovered by this investigation. First, an explicit check was added into the “top” and “ps” code to mask the fact that “/system/bin/debugsrun” and “/system/bin/debugs” were running, and would hide or skip its presence in the user output.
Screenshot of decompiled code from ‘top’
By comparing that discovery to the output of running the commands on the test device, which is a different brand than the firmware image, we confirmed the system was hiding the processes from “top”, although hiding only “debugsrun” from “ps”. “debugs” was observed in the “ps” output, executing out of “/data/debugs/”, and we simply attribute it actually appearing in the list as a mistake on the original author’s behalf, slightly out of date firmware on the test devices, or differences between the firmware of the different brands. Doing a cat of all commands for running pids under /proc, we also confirmed the processes are in fact running despite the output of the commands, and network traffic also verified this:
List of running processes under /proc
Second, we noticed the Java framework has also been modified to also hide references to this process. Specifically the core java.util.Scanner class has a modified next() method to exclude references to the binary names:
Code snippet from java.util.Scanner
In addition, the nextInt() method was modified to always return a pid of 10008 for the processes:
Third, the local sqlite database that the binary logged events, stored system and user information and fetched from, was located at /system/bin/unint8int.
It’s unclear why the author of this process wanted to purposely hide the presence of the process and local database on the device, although it’s worth noting that it did not attempt to do this comprehensively.
Proof of Concept
With the information learned and the attack surface made available, a head-end simulator can be built that has the ability to issue commands to affected devices. As a proof of concept, one of the these head-end simulators was created to respond back to the device with a static, crafted message to evaluate the desired command.
The test setup involved was an host containing:
- The simulated head-end HTTP server to respond to client requests.
- A BIND DNS server that acted as a recursive resolver for clients, but had three zones created for the three C&C domains. It would otherwise return correct responses to the clients.
Any desired device that wants to undergo testing simply needs to connect to a network configured to push out the described host as the resolver in the DHCP responses by competing with the local DHCP server, poison the devices ARP table of the local network DNS server if present, or just perform a full man-in-the-middle attack and intercept all traffic through targeting the local gateway or other means.
The command to undergo testing was the remote command execution functionality. This is the same as the “push_command” action described earlier in the article. In this case, the ability to write to protected space, “/data/system” was tested by using touch to create an empty file. Specifically, the following command was to be issued:
After configuring the device appropriately, the simulated head-end simply had to wait for the client to ultimately contact the head-end. Ultimately this request was received and an appropriately formatted response was sent to the client, as shown in this screenshot of output from the simulated head-end.
The device was then connected to a computer to access its local shell via adb. The below screenshot shows the directory listing for /data/system/, demonstrating that the file was created as expected with root owner and group, and that a standard user does not have the ability to write into this directory.
The following chart outlines the top set of device manufacturers affected, or previously affected, as reported by the binary. This information was generated based on the solicitations we received to our sinkholes.
Distribution of Observed Devices by Manufacturer
We have observed over 2.8 million distinct devices, across roughly 55 reported device models, which have checked into our sinkholes since we registered the extraneous domains. In some cases, we have not been to translate the provided device model into a reference to the real world device. These are the devices captured in the “Others” category above. Thus, there could be additional device models affected by this problem not outlined in this article or by CERT.
Please refer to the CERT Knowledgebase reference at the end of this article for additional information about how to check whether your device is affected. To manually verify, you can monitor for outbound connections from your phone to the hostnames described earlier in the article. If the transactions occur over HTTP instead of HTTPS, then the device would be affected by this issue.
This analysis revealed two critical discoveries:
- Firstly, the vulnerability described above allows for users to be subjected to significant attacks in positions where an adversary can perform a Man-in-the-Middle attack.
- Secondly, this OTA binary was distributed with a set of domains preconfigured in the software. Only one of these domains was registered at the time of the discovery of this issue. If an adversary had noticed this, and registered these two domains, they would’ve instantly had access to perform arbitrary attacks on almost 3,000,000 devices without the need to perform a Man-in-the-Middle attack. AnubisNetworks now controls these two extraneous domains to prevent such an attack from occurring in the future for this particular case.
Additional information about this issue can be found at the CERT Knowledgebase article: http://www.kb.cert.org/vuls/id/624539 and has been assigned CVE-2016-6564.
AnubisNetworks has worked with Google, BLU, and CERT in attempt to notify all affected parties.
Dan Dahlberg (Research Scientist at BitSight) & João Gouveia (CTO e Co-Founder of AnubisNetworks)
17th November 2016