CamSniff
47 cameras with default credentials across 12 sites — found in 4 hours
The Problem
A physical security consultancy was engaged to audit camera infrastructure across a facility management company’s 12 sites — approximately 500 IP cameras installed over seven years, across multiple vendors, integrated by four different contractors.
The client had no centralised camera inventory. Nobody knew which cameras still had default credentials. Nobody knew which were reachable from outside the management VLAN. The engagement was explicitly authorised with a signed scope-of-work and a letter of authorisation from the facility management company’s CISO.
The constraint: the audit had to complete within a two-day on-site window.
What We Built
CamSniff extended with a site-profile configuration system that encoded each site’s network topology, known vendor OUI ranges, and expected RTSP path patterns. The tool’s six scanning modes map to aggression levels:
| Mode | Nmap Timing | Credential Set |
|---|---|---|
| stealth+ | T1 | 8 most-common defaults |
| stealth | T2 | 24 vendor defaults |
| normal | T3 | 48 defaults |
| aggressive | T4 | 72 defaults |
| war | T5 | 96 defaults |
| custom | configurable | custom list |
How It Works
The multi-protocol correlation is the core innovation. Rather than brute-forcing RTSP directly (noisy, slow), CamSniff builds a device fingerprint from passive and active sources before attempting any credentials:
class DeviceFingerprint: ip: str mac: str oui_vendor: str # from MAC prefix lookup open_ports: list[int] ssdp_description: dict # parsed UPnP XML if available onvif_info: dict | None # ONVIF probing if port 80/8080 open probable_rtsp_paths: list[str] # predicted from vendor templates def predict_rtsp_paths(fingerprint: DeviceFingerprint) -> list[str]: vendor = fingerprint.oui_vendor.lower() # Vendor-specific RTSP path templates reduce brute force surface VENDOR_TEMPLATES = { "hikvision": ["/Streaming/Channels/101", "/h264/ch1/main/av_stream"], "dahua": ["/cam/realmonitor?channel=1&subtype=0", "/h264Preview_01_main"], "axis": ["/axis-media/media.amp", "/mjpg/video.mjpg"], "hanwha": ["/profile1/media.smp"], } for vendor_key, paths in VENDOR_TEMPLATES.items(): if vendor_key in vendor: return paths return ["/", "/stream", "/video", "/live"] # generic fallback Knowing the vendor from the OUI means the credential set can be narrowed to vendor-specific defaults before falling back to the full list. A Hikvision camera with default credentials will almost certainly use admin/12345 — trying 95 other passwords wastes time.
The Outcome
47 of 500 cameras were accessible with default credentials — 9.4% of the estate, spread across 9 of 12 sites. The oldest unpatched cameras dated to 2017. None of this was visible to the client’s security team prior to the engagement.
The engagement report included a site-by-site remediation checklist. All 47 cameras had their credentials rotated before the consultancy team left on day two. The client subsequently mandated a quarterly automated check using a read-only monitoring profile of the same tool against their management VLAN.
Note: CamSniff is designed for authorised security testing only. All use described here was conducted under signed scope-of-work within controlled environments.