Fiddling with IoT home security
Last year I installed an IoT home security system; back then I did not bother
to connect it to the internet mostly because of my own laziness but also
because IoT most of the times rhymes with: overpriced crap prone to also being
a security nightmare.
I am not going to name the brand, but it is fairly well known and its pricing
is not on the cheap side (€ 700 for main unit and external keyboard).
Hardware wise it is well made, just by looking at it one could tell that quite
some engineering was poured into it, it has all kind of expansion cards and
the quality seems more than decent.
Software, hard to say though.
Just to be on the safe side, I have put it into its own network segment which
is segregated from the rest of the network.
To add a little bit of context:
- IoT: 192.168.3.253
- IoT Network gateway and recursive DNS server for LAN: 192.168.3.1
- Laptop: 192.168.1.101
Lets start by sniffing network traffic and see what it does:
mikrotik> /tool/sniffer/print
only-headers: no
memory-limit: 100KiB
memory-scroll: yes
file-limit: 1000KiB
streaming-enabled: yes
streaming-server: 192.168.0.101:37008
filter-stream: yes
filter-interface: all
filter-direction: any
filter-operator-between-entries: or
quick-rows: 20
quick-show-frame: no
running: no
A few seconds after firing up Wireshark this pops up:
The interesting bits are:
- DNS queries, packets number 6906, 6907.
- DNS replies, packets number 6911 and 6912.
- TCP handshake, packets number 11748, 11753 and 11755.
- TLS handshake, packets 11758 and onward.
Time to fire up mitmproxy, but first we need to make some changes on mikrotik and laptop:
mikrotik> /ip/firewall/filter/add chain=forward action=accept src-address=192.168.3.253 dst-address=192.168.0.101 log=yes
...
laptop> sudo firewall-cmd --add-port=443/tcp --zone=FedoraWorkstation
success
laptop> sudo firewall-cmd --list-all-zones | grep -A13 active
FedoraWorkstation (default, active)
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces: wlp1s0
sources:
services: dhcpv6-client
ports: 443/tcp
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
Since we know what kind of domain the IoT device is trying to connect to, lets poison the DNS so that it is fouled into connecting to out mitmproxy:
mikrotik> /ip/dns/static/add address=192.168.1.101 comment=mitm-iot name=www. type=A
mitmproxy needs to be listening on port 443, obviously it also needs to run as root.
Unfortunately though the IoT device is clever enough not to trust mitmproxy self signed SSL certificate, resulting in the following error:
[12:22:38.888][192.168.3.253:57754] client connect
[12:22:38.891][192.168.3.253:57754] Client TLS handshake failed. The client may not trust the proxy's certificate for www. (OpenSSL Error([('SSL routines', '', 'no shared cipher')]))
[12:22:38.891][192.168.3.253:57754] client disconnect
I could have played a little bit with SSL, maybe create a certificate with
matching common name, subject alternative name and whatnot.
Hopefully it would not have worked since SSL certificate would still be self
signed.
Instead I tried to connect to the domain with a regular browser, and to my disbelief I landed on a full blown login page.
The domain is protected by cloudflare, but after a few minutes of googlefoo I
found the real IP of the server hosting the service.
This server seems like a regular VPS hosted on Digital Ocean with not so
strict security hardening nor up to date software:
laptop> telnet 68.* 22
Trying 68.*...
Connected to 68.*.
Escape character is '^]'.
SSH-2.0-OpenSSH_7.9p1 Debian-10+deb10u4
^]
telnet> quit
Connection closed.
Website footer also reports copyright 2017, which probably also means that
the server (running Debian 10) is probably not the only thing that has not
seen any update in quite a few years.
Since I have an account on the platform, I fired up mitmproxy again (this time
on port 8080), imported its CA into Chromium keystore and started poking
around a bit.
Website is very minimal, almost looks like an high school diploma project.
Authentication is handled using a PHP session cookie.
HTTP expires header is set 44 years in the past (19 nov 1981).
User and password are sent in clear in the body of an HTTP POST.
At least TLS certificates is from letsencrypt and webserver supports TLS v1.3.
I did not uncover anything super nasty, but this is far from ideal still:
- un-patched server. Most likely also a single machine with no HA.
- Most likely un-mantained software (copyright 2017 in the footer).
- Cloudflare is used but is basically useles since the real backend server can be found in 5 minutes.
- The website appears to provide the same functionalities of the mobile APP,
but in a much more hackable way. It is trivial to rebuild a complete API
swagger just by fiddling with it.
What follows for example is the API call to disable a security zone: