Skip to content

Flag cloud/app cameras by MAC OUI, not just open ports - #1

Open
holzmanshmuel wants to merge 1 commit into
NoamOhev:mainfrom
holzmanshmuel:feat/oui-vendor-flagging
Open

Flag cloud/app cameras by MAC OUI, not just open ports#1
holzmanshmuel wants to merge 1 commit into
NoamOhev:mainfrom
holzmanshmuel:feat/oui-vendor-flagging

Conversation

@holzmanshmuel

Copy link
Copy Markdown

What & why

scan.sh currently flags a host as camera-like only when it has a local stream port open (RTSP/ONVIF/DVR: 554/8000/8554/34567/37777/8899/...). That's the right signal for surveillance DVRs/NVRs and classic IP cams — but it structurally misses cloud/P2P cameras, which are most modern consumer cams (and a lot of cheap "spy cams").

Those devices don't run a server on the LAN. They open an outbound connection to a vendor cloud and the phone app pulls the feed from there — so they listen on nothing locally, scan.sh lists the host, and then walks right past it because no port matched.

I hit this in practice while testing the skill: two WiFi baby monitors — one IMILAB, one no-name cam on a Shenzhen Bilian WiFi module — showed up as [VENDOR] hosts with zero open ports and were silently ignored. Exactly the failure mode you'd care about in a rental: a cloud spy-cam would slip through the same way.

The change

Add a second, independent detection path: match each host's MAC OUI (first 3 octets → manufacturer) against a bundled offline vendor list, scripts/camera_ouis.txt.

Two confidence tiers so it doesn't cry wolf:

Tier Output Vendors
CAM >>> KNOWN CAMERA VENDOR Hikvision, Dahua, IMILAB, Wyze, Reolink, Arlo, Nanit, Amcrest, Uniview, Hanwha, Axis, …
MODULE >>> CAMERA-CAPABLE MODULE (verify) Shenzhen Bilian, Tuya — WiFi-module makers common in cheap cams, but also in bulbs/plugs, hence "verify"

Example output on a host that opens no port:

  10.0.0.42      xx:xx:xx:xx:xx:xx  [VENDOR]
        >>> KNOWN CAMERA VENDOR: Shanghai Imilab Technology Co.Ltd  (app/cloud cam — may expose NO local port)

Reworked the closing hint to distinguish the two suspect types and to tell the user that a vendor-flagged, no-port host is a cloud cam whose video the network scan can't reach — so the right next move is accounting for it / a physical lens sweep, not rtsp_probe.pl.

Design notes

  • Offline by design. No network calls at scan time and no device MACs ever leave the machine — appropriate for a privacy tool, and it works on flaky/no internet (the hotel/Airbnb case this skill is built for).
  • Data provenance. camera_ouis.txt is 247 OUI blocks derived from the IEEE OUI registry (via Wireshark's manuf). Header documents how to regenerate. Not exhaustive, and I explicitly excluded ultra-generic silicon (Espressif/Realtek) to avoid flagging every ESP32 smart-plug.
  • OUI normalization. arp strips leading zeros (20:b:cf20:0B:CF); oui_of() re-pads and uppercases before matching.
  • bash 3.2-safe (macOS default): plain grep against a TSV, no associative arrays. SCRIPT_DIR resolves via BASH_SOURCE so the DB is found regardless of cwd.
  • No behavior change to existing paths — port scan, MAC [RANDOM]/[VENDOR]/[ROUTER] classification, and the <<< CAMERA-LIKE PORT flag are all untouched. This is purely additive.

Limitations (also called out in SKILL.md / README)

A camera using MAC randomization, or one from an unlisted/no-name OUI, still won't match — so the physical lens sweep stays the backstop. This closes a big gap, it doesn't claim completeness.

Testing

  • bash -n on scan.sh; unit-tested oui_of() / cam_vendor() incl. the zero-stripped-MAC case.
  • Ran the full scan.sh end-to-end on a live /24: the two previously-invisible monitors now flag correctly (IMILAB → CAM, Bilian → MODULE), and I verified two OUI substring false positives ("Carlo Gavazzi", "Arlotto" both contain arlo) are excluded.

Files

  • scripts/scan.sh — OUI lookup + output (+38 lines, additive)
  • scripts/camera_ouis.txt — new offline vendor DB
  • SKILL.md, README.md — document the two flag types and the cloud-cam limitation

Totally fine to take, leave, or reshape any of this — thanks for open-sourcing the skill, it's a genuinely useful tool. 🙏


🤖 Generated with Claude Code

https://claude.ai/code/session_01RQuSmfvdk5Ge3Z28N5SyD7

The port scan only catches devices that run a *local* stream server
(RTSP/ONVIF/DVR on 554/8000/8554/34567/...). Most modern consumer
cameras — and cheap "spy cams" — are cloud/P2P: they dial out to a
vendor cloud and the phone app pulls the feed from there. They listen
on nothing locally, so scan.sh sees the host but never flags it.

Found this in practice: two WiFi baby monitors (IMILAB, and a no-name
cam on a Shenzhen Bilian module) showed up as [VENDOR] hosts with zero
open ports and were silently passed over.

This adds a second, independent detection path: match each host's MAC
OUI against a bundled offline vendor list (scripts/camera_ouis.txt,
247 blocks derived from the IEEE OUI registry via Wireshark's manuf).

- CAM tier    -> ">>> KNOWN CAMERA VENDOR"      (Hikvision, Dahua, IMILAB,
                                                 Wyze, Reolink, Arlo, Nanit...)
- MODULE tier -> ">>> CAMERA-CAPABLE MODULE"    (Shenzhen Bilian, Tuya — also
                 (verify)                        used in bulbs/plugs)

Notes:
- Offline by design: no network calls at scan time, no device MACs leave
  the machine — appropriate for a privacy tool and works on flaky/no
  internet (hotel/Airbnb).
- OUI is normalized (arp strips leading zeros: 20:b:cf -> 20:0B:CF).
- bash 3.2-safe (macOS default): plain grep against a TSV, no assoc arrays.
- Limitations documented: a cam using MAC randomization or an unlisted
  OUI still won't match — the physical lens sweep remains the backstop.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RQuSmfvdk5Ge3Z28N5SyD7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant