As a part of Lullabot’s security team, we’ve been keeping track of how the Internet of Things plays a role in our company security. Since we’re fully distributed, each employee works day-to-day over their home internet connection. This subreddit reminds us that most “smart” devices are actually quite dumb as far as security goes. With malware like Mirai actively focusing on home IoT devices including cameras, we know that anything we plug in will be under constant assault. However, there can be significant utility in connecting physical devices to your local network. So, my question: is it possible to connect an “IoT” device to my home network securely, even when it has known security issues?
An opportunity presented itself when we needed to buy a new baby monitor that supported multiple cameras. The Motorola MBP853CONNECT was on sale, and included both Wifi and a “regular” proprietary viewer. Let’s see how far we can get.
The Research
Before starting, I wanted to know if anyone else had done any testing with this model of camera. After searching for “motorola hubble security” (Hubble is the name of the mobile app), I came across Push To Hack: Reverse engineering an IP camera. This article goes into great detail about the many flaws they found in a different Motorola camera aimed at outdoor use. Given that both cameras are made by Binatone, and connect to the same remote services, it seemed likely that the MBP853 was subject to similar vulnerabilities. The real question was if Motorola updated all of their cameras to fix the reported bugs, or if they just updated a single line of cameras.
These articles were also great resources for figuring out what the cameras were capable of, and I wouldn’t have gotten as far in the time I had without them:
Goals
I wanted to answer these three questions about the cameras:
- Can the cameras be used in a purely “local” mode, without any cloud or internet connectivity at all?
- If not, can I allow just enough internet access to the camera so it allows local access, but blocks access to the cloud services?
- If I do need to use the Hubble app and cloud service, is it trustworthy enough to be sending images and sounds from my child’s bedroom?
The Infrastructure
I recently redid my home network, upgrading to an APU2 running OPNSense for routing, combined with a Unifi UAP-AC-PRO for wireless access. Both software stacks support VLANs—a way to segregate and control traffic between devices on the same ‘physical’ network. For WiFi, this means creating a separate SSID for the cameras, and assigning it a VLAN ID in the UniFi controller. Then, in OPNSense, I created a new interface with the same VLAN ID. On that interface, I enabled DHCP, and then set up basic firewall rules to block all traffic. That way, I could try setting up the camera while using Wireshark on my laptop to sniff the traffic, without worrying that I was exposing my real network to anything nefarious.
Packet Sniffing
One of the benefits of running a “real” operating system on your router is that all of our favorite network debugging tools are available, including tcpdump. Since Wireshark will be running on our local workstation, and not our router, we need to capture the network traffic to a separate file. Once I knew the network interface name using ifconfig
, I then used SSH along with -w -
to reroute the packet dump to my workstation. If you have enough disk space on the router, you could also dump locally and then transfer the file after.
$ ssh root@router-ip-or-hostname tcpdump -w - -i igb0_vlan3000 > packet-dump.pcap
After setting this up, I realized that this wouldn't show traffic of the initial setup. That’s because, in setup mode, the WiFi camera broadcasts an open WiFi network. You then have to use the Android or iOS mobile app to configure the camera so it has the credentials to your real network. So, for the first packet dump, I joined my laptop to the setup network along with my phone. Since the network was completely open, I could see all traffic on the network, including the API calls made by the mobile app to the camera.
Verifying the setup vulnerability
Let's make sure this smart camera is using HTTPS and keeps my WiFi password secure.
I wanted to see if the same setup vulnerability documented by Context disclosing my WiFi passwords applied to this camera model. While I doubt anyone in my residential area is capturing traffic, this is a significant concern in high-density locations like apartment buildings. Also, since the cameras use the 2.4GHz and not the 5GHz band, their signal can reach pretty far, especially if all you’re trying to do is read traffic and not have a successful communication. In the OPNSense firewall, I blocked all traffic on the “camera” VLAN. Then, I made sure I had a unique, but temporary password on the WiFi network. That way, if the password was broadcast, at least I wasn’t broadcasting the password for a real network and forcing myself to reset it.
Once I started dumping traffic, I ran through the setup wizard with my phone. The wizard failed as it tests internet connectivity, but I could at least capture the initial setup traffic.
In Wireshark, I filtered to https traffic:
Oh dear. The only traffic captured is from my phone trying to reach 66.111.4.148
. According to dig -x 66.111.4.148
, that IP resolves to www.fastmail.com - in other words, my email app checking for messages. I was expecting to see HTTPS traffic to the camera, given that the WiFi network was completely open. Let’s look for raw HTTP traffic.
This looks promising. I can see the HTTP commands sent to the camera fetching it’s version and other information. Wireshark’s “Follow HTTP stream” feature is very useful here, helping to reconstruct conversations that are spread over multiple packets and request / response pairs. For example, if I follow the “get version” conversation at number 3399:
GET /?action=command&command=get_version HTTP/1.1
User-Agent: Dalvik/2.1.0 (Linux; U; Android 7.1.1; Nexus 6P Build/N4F26O)
Host: 192.168.193.1
Connection: Keep-Alive
Accept-Encoding: gzip
HTTP/1.1 200 OK
Proxy-Connection: Keep-Alive
Connection: Close
Server: nuvoton
Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0
Pragma: no-cache
Expires: 0
Content-type: text/plain
get_version: 01.19.30
Let’s follow the setup_wireless command:
GET /?action=command&command=setup_wireless_save&setup=1002000071600000000606blueboxthisismypasswordcamera000000 HTTP/1.1
User-Agent: Dalvik/2.1.0 (Linux; U; Android 7.1.1; Nexus 6P Build/N4F26O)
Host: 192.168.193.1
Connection: Keep-Alive
Accept-Encoding: gzip
HTTP/1.1 200 OK
Proxy-Connection: Keep-Alive
Connection: Close
Server: nuvoton
Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0
Pragma: no-cache
Expires: 0
Content-type: text/plain
setup_wireless_save: 0
That doesn't look good. We can see in the GET:
- The SSID of the previous WiFi network my phone was connected to (“bluebox”).
- The password for the “camera” network (thisismypassword).
- The SSID of that network.
Presumably, this is patched in the latest firmware update. Of course, there’s no way to get the firmware without first configuring the camera. So, I opened up the Camera VLAN to the internet (but not the rest of my local network), and updated.
That process showed another poor design in the Hubble. When checking for firmware updates, the app fetches the version number from the camera. Then, it compares that to a version fetched from ota.hubble.in
… over plain HTTP.
In other words, the firmware update itself is subject to a basic MITM attack, where an attacker could block further updates from being applied. At the least, this process should be over HTTPS, ideally with certificate pinning as well. Amusingly, the OTA server is configured for HTTPS, but the certificate expired the day I was writing this section.
After the update had finished, I reset the camera to factory defaults and checked again. This time, the setup_wireless_save
GET was at the least not in cleartext. However, I don’t have any trust that it’s not easily decryptable, so I’m not posting it here.
Evaluating Day-to-Day Security
Assuming that the WiFi password was at least secure from casual attackers, I proceeded to add firewall rules to allow traffic from the camera to the internet, so I could complete the setup process. This was a tedious process. tcpdump
along with the OPNSense list of “blocked traffic” was very helpful here. In the end, I had to allow:
- DNS
- NTP for time sync
- HTTPS
- HTTP
- UDP traffic
I watched the IPs and hostnames used by the camera, which were all EC2 hosted servers. The “aliases” feature in OPNSense allowed me to configure the rules by hostname, instead of dealing with constantly changing IPs. Of course, given the above security issues, I wonder how secure their DNS registrations are.
Needing to allow HTTP was a red flag to me. So, after the setup finished, I disabled all rules except DNS and NTP. Then, I added a rule to let my normal home LAN access the CAMERA VLAN. I could then access the camera with an RTSP viewer at the URL:
rtsp://user:pass@camera-ip:6667/blinkhd/
Yes, the credentials actually are user
and pass
.
And tada! It looked like I had a camera I could use with my phone or laptop, or better yet at the same time as my wife. Neat stuff!
It All Falls Apart
After a fresh boot, everything seemed fine with the video streams. However, over a day or two, the streams would become more and more delayed, or would drop, and, eventually, I’d need to restart the camera. Wondering if this had something to do with my firewall rules, I re-enabled the HTTP, HTTPS, and UDP rules, and started watching the traffic.
Then, my phone started to get notification spammed.
At this point, I’d been using the cameras for about two weeks. As soon as I re-enabled access to Hubble, my phone got notifications about movement detected by the camera. I opened the first one… and there was a picture of my daughter, up in her room, in her jammies.
It was in the middle of the day, and she wasn’t home.
What I discovered is that the camera will save a still every time it detects movement, and buffer them locally until they can be sent. And, looking in Wireshark, I saw that the snapshots were being uploaded with an HTTP POST to snap.json
without any encryption at all. Extracting the conversation, and then decoding the POST data (which was form data, not JSON!), I ended up with a picture.
I now had proof the camera was sending video data over the public internet without any security whatsoever. I blocked all internet access, including DNS, hoping that would still let local access work. It did!
Then, my wife and I started hearing random beeps in the middle of the night. Eventually, I tracked it to the cameras. They would beep every 15 minutes or so, as long as they didn’t have a working internet connection. This killed the cameras for home use, as they’d wake the whole family. Worse yet, even if we decided to allow internet access, if it was down in the middle of the night (our cable provider usually does maintenance at 3AM), odds are high we’d all be woken up. I emailed Motorola support, and they said there was no way to disable the beeping, other than to completely reset the cameras and not use the WiFi feature at all.
We’re now happily using the cameras as “dumb” devices.
Security Recommendations and Next Steps
Here are some ideas I had about how Motorola could secure future cameras:
- The initial setup problem could have been solved by using WPA2 on the camera. I’ve seen routers from ISPs work this way; the default credentials are unique per device, and printed on the bottom of the device. That would significantly mitigate the risk of a completely open setup process. Other devices include a Bluetooth radio for this purpose.
- Use encryption and authentication for all APIs. Of course, there are difficulties from this such as certificate management, hostname validation, and so on. However, this might be a good case where the app could validate based on a set of hardcoded properties, or accept all certificates signed by a custom CA root.
- Mobile apps should validate the authenticity of the camera to prevent MITM attacks. This is a solved problem that Binatone simply hasn’t implemented.
- Follow HTTP specifications! All “write” commands for the camera API use HTTP GETs instead of POSTs. That means that proxies or other systems may inadvertently log sensitive data. And, since there’s no authentication, it opens up the API to CSRF vulnerabilities.
In terms of recommendations to the Lullabot team, we currently recommend that any “IoT” devices be kept on completely separate networks from devices used for work. That’s usually as simple as creating a “guest” WiFi network. After this exercise, I think we’ll also recommend to treat any such devices as hostile, unless they have been proven otherwise. Remember, the “S” in “IoT” stands for “secure”.
Personally, I want to investigate hacking the camera firmware to remove the beeps entirely. I was able to capture the firmware from my phone (the app stores them in Android’s main storage), and since there’s no authentication, I’m guessing I could replace the beeps with silence, assuming they are WAV or MP3 files.
In the future, I’m hoping to find an IoT vendor with a security record that matches Apple’s, who is clearly the leader in mobile security. Until then, I’ll be sticking with dumb devices in my home.