DEV Community

Emir Mrkaljević
Emir Mrkaljević

Posted on

Noticing when a smart device starts behaving differently

A one-time audit of a smart plug or camera tells you what it does today. It says nothing about next month, after a firmware update or a change on the vendor's side. That gap is what I worked on in the last two releases of iotaudit, a small open-source (MIT) tool I use to audit the devices on my own network.

If you missed the earlier post about the per-device grade and the one-page report, it is here.

Everything below runs locally. There is no telemetry, no account, and it is meant only for your own network and devices.

Comparing two audits

capture and analyze already save a JSON report. Since 0.1.9 you can compare two of them:

pip install -U iotaudit

iotaudit diff yesterday.json today.json
iotaudit diff yesterday.json today.json --json

# or print the diff right after a new analysis
iotaudit analyze capture.pcap --device 192.168.1.50 \
    --json today.json --out today.html \
    --compare yesterday.json
Enter fullscreen mode Exit fullscreen mode

Devices match by MAC, then by IP. For each device it lists new and gone destination domains and IPs, new countries, new open ports, grade changes, verdict changes, newly seen unencrypted traffic, and new UPnP forwards when the JSON has them.

Here is a made-up example of the kind of output you get (invented device and addresses, not from a real network):

EXAMPLE OUTPUT (made up)
device 02:00:00:00:00:01 (192.168.1.50)
  grade: B -> D
  new domains: telemetry.example.net
  new IPs: 198.51.100.23
  new countries: SG
  new open ports: 23/tcp
  new unencrypted traffic: HTTP to 198.51.100.23
Enter fullscreen mode Exit fullscreen mode

The exit code is the part I care most about. It is 1 when something security relevant appeared: a new device, destination, country, open port, a worse grade, unencrypted traffic, or a UPnP forward. It is 0 otherwise, including when things only went away or the grade got better. A verdict change is printed but does not exit 1 on its own. A missing or unreadable file exits 2.

That makes it easy to put in cron and only hear about it when something new shows up. This is the script from the README:

#!/bin/sh
# 15 6 * * 1-5 "$HOME/iotaudit/check.sh"
report=$(iotaudit diff "$HOME/iotaudit/yesterday.json" "$HOME/iotaudit/today.json") || {
    printf '%s\n' "$report"
    exit 1
}
exit 0
Enter fullscreen mode Exit fullscreen mode

The same comparison is available to MCP clients as the diff_results tool.

Offline known issue hints

0.1.10 adds a small curated list of public CVEs (14 entries right now) that is shipped inside the package. It is matched against version strings iotaudit already sees: nmap service versions, HTTP Server headers, UPnP and SSDP headers. Think MiniUPnPd, Dropbear, lighttpd, BusyBox, RomPager, the usual embedded suspects.

Each match shows up as known_issue_hints in the JSON and in the HTML/PDF report, with a link to the public NVD page. I was careful about the wording: every hint says the issue is possible based on the version string, and that you still need to check the actual firmware. Vendors backport fixes without changing banners all the time.

For the same reason, a hint only changes the grade when the observed version matches a listed version exactly and the entry is critical. Version ranges and lower severities stay as hints. There is no network lookup at runtime and no update command; the list is whatever shipped with the release.

What I would like to hear

If you run it against your own devices and the diff is noisy or a hint looks wrong, an issue on GitHub helps a lot. Suggestions for well documented CVEs to add to the list are welcome too.

Repo: https://github.com/emirmrkaljevic/iotaudit

Top comments (0)