A toolkit for camera discovery and assessment during penetration tests using ONVIF and RTSP.
Contents:
- CamAmber: RTSP stream replacement and intercept
- CamAmber-Discover: Discover video-related components on a network
- CamAmber-SDP: SDP file manipulation
- CamAmber-ONVIF: gather information via ONVIF web service
- FAQ: Help with camamber and resources
Manipulate intercepted RTSP stream to duplicate it and/or replace it. The tool automates a few things, but you still have some work to do (the other scripts in the toolkit can help), see instructions below.
Here we consider that the stream was already running before our attack and that we do not have initialization information (no RTSP session establishment).
WARNING: This program could INTERRUPT the network stream. PLEASE DO NOT USE ON SENSITIVE ENVIRONMENTS.
The program is in C and requires gcc for compiling.
If you use the auto-MITM feature, arpspoof is required (apt install dsniff).
So far only Debian OS are supported. We rely on
sysctlandiptablesto change network settings at system level.
- Retrieve the destination port of the stream
- (Optional) Set up a MITM attack manually, or use
-Moption - Run CamAmber with either "redirect" or "replace" mode (replace also redirects)
- View the stream locally (requires additional, SDP-related steps)
This parameter is required for CamAmber to work. It will not find it itself (too many chances of false positive). You can retrieve it if you have access to the traffic of the source/destination or by running a first man-in-the-middle attack:
sudo ettercap -T -M arp:remote /<camera_ipaddr>// /<viewer_ipaddr>//- Quit when you have the destination port
CamAmber requires to be in a man-in-the-middle position between the camera and a
legitimate viewer (or anything else). Use option -M to let CamAmber do it
(uses arpspoof).
Note: if you want to run you own MITM attack, you need to use a technique that let the system handle IP forwarding (see detailed instructions)
Compile it with make.
Usage: ./camamber -m [mode] -i [iface] [network_info]
arguments:
-m mode Specify what CamAmber must do (redirect or replace)
-i iface Network interface to use.
-M Enable auto Man-in-the-middle attack (relies on arpspoof).
-s src IPv4 address of the stream (usually a camera)
-d dest IPv4 address of the original destination (e.g. a VMS or NVR)
-p port Destination port of the network stream
-r redir IPv4 address to send the duplicated stream to (e.g. 127.0.0.1)
-f frames Number of frames to record and loop (replace mode only)
-v Print additional information to terminal.
CamAmber must be run as sudo. It requires root privileges to play with iptables, nfqueues and sockets.
sudo ./camamber -m redirect -i <iface> -s <camera_ipaddr> -d <viewer_ipaddr> -p
<stream_dest_port>
When activated, the original stream will not be interrupted (hopefully), however the stream will be duplicated and sent to another IP. Default behavior is to send it to localhost to be able to open and view the network stream on your host (e.g. with VLC), but you can also send it somewhere else (why?).
Additional steps are required to be able to view the stream locally (you need information about the stream). Details are given below.
sudo ./camamber -m replace -i <iface> -s <camera_ipaddr> -d <viewer_ipaddr> -p
<stream_dest_port>
Replace mode will first record a short video sequence from the stream during a few seconds then send this sequence over and over again to the original viewer instead of the real stream. Stopping CamAmber will restore the stream without interrupting it (hopefully) but the "fake" stream may remain for a few seconds or minutes.
You don't need to view the stream locally for the attack to work. However, if you want to, redirect mode works as well in replace mode.
Additional steps are required to be able to view the stream locally (you need information about the stream). Details are given below.
For your media player (here, VLC) to be able to read the RTSP stream, you need to feed it with the video format. The format is be described in a SDP (Session Description Protocol, RFC 8866) file, usually sent during session initialization (which we may not have).
There are a few ways to retrieve a valid SDP file, or to create one:
-
Catch a RTSP session init and extract the SDP packet then store it in a file (can be done for instance with Wireshark, see detailed instructions).
-
Init a RTSP session yourself and extract the SDP packet. If the RTSP session requires authentication, you need valid credentials. Can be done with CamAmber-SDP.
-
Guess or bruteforce the correct parameters and generate a SDP yourself (low chances of success). CamAmber-SDP can be used to gather some of these details and to build a SDP file.
Please note that there are limitations and that crafted SDP files may not work for complex video formats such as H.264 and H.265.
Once you have your valid SDP file, open it with a media player:
vlc my_rtp.sdp
The correct local destination port of the stream must be supplied to make it work (line to change:
m=video <port> RTP/AVP XX).
Utility to discover video-related components on a network using the protocols SSDP and WS-Discovery, in multicast and/or unicast.
This is a Python 3.12+ script relying only on built-in libraries.
camamber-discover.py [-h] [-v] [-m protocol] [-t ip or range]
options:
-h, --help show this help message and exit
-v, --verbose Print additional information
-m protocol, --mode protocol
Only test with one protocol (default: test all)
-t ip or range, --target ip or range
Target IPv4 address or range to test via unicast.
Without argument, the script will run only multicast discovery using both
protocols (SSDP and WS-Discovery). If the target option is set (-t), a unicast
discovery will be performed on all IP adresses specified, for both protocols by
default.
SSDP and WS-Discovery are originally multicast protocols. We have added unicast support because of the limitations of multicast discovery (multicast requests are usually not transmitted outside of the VLAN you are in so you can only see devices on the same VLAN). Some devices supporting SSDP or WS-Discovery via multicast may not respond to SSDP or WS-Discovery via unicast.
-m(modes) can be used to choose the type of discovery : unicast, multicast, ssdp, wsdiscovery. Default is all types of discovery. Unicast discovery is done only if-tis set.-t(target) takes a single IPv4 address, a IPv4 range or a file containing a list of IP addresses.
Utility to retrieve, craft or manipulate SDP files.
This is a Python 3.12+ script relying only on built-in libraries.
camamber-sdp.py [mode] [additional parameters]
CamAmber-SDP currently supports three modes to get SDP or info to create one.
- Get: Establish a RTSP session to retrieve the SDP
- Listen: Listen to the incoming stream to gather a few info from RTP frames
- Forge: Create a SDP file from scratch with user-supplied data
When running with CamAmber, the SDP file needs to be updated with the actual
destination port in the m=video line. You can edit it directly or do it
with:
python camamber-sdp.py -i my_default_sdp.sdp -p <port>
Establish a legitimate RTSP session with the device to retrieve a valid SDP file.
usage: camamber-sdp.py [-h] [-v] [-o filename] [-s stream_uri] [-u username] [-p password]
[-d port]
options:
-h, --help show this help message and exit
-v, --verbose Print additional information
-o filename, --output filename
Filename to write the SDP file to
-s stream_uri, --stream stream_uri
RTSP stream URI
-u username, --user username
Username for RTSP connection (if any)
-p password, --passwd password
Password for RTSP connection (if any)
-d port, --dport port
Stream destination port to set in the SDP
The only mandatory argument is -s stream_uri with format rtsp://.... You can
find it by:
- Requesting the ONVIF webservice (see CamAmber-ONVIF)
- Find it in the device documentation
- Bruteforce it (ex: Cameradar)
Credentials are required if the RTSP stream establishment requires authentication.
This will not create any SDP file, however you can run it while the man-in-the-middle attack is running to extract useful data from the RTP frames to be able to build a SDP afterwards (Payload type and codec, RFC 6184).
usage: camamber-sdp.py [-h] [-v] [-o filename] [-d ip_addr] [-p port]
options:
-h, --help show this help message and exit
-v, --verbose Print additional information
-o filename, --output filename
Filename to write the SDP file to
-d ip_addr, --dest ip_addr
IP address on which RTP frames arrive
-p port, --port port Local port to listen to
Create a SDP file from scratch with info supplied in command line. As there are many possibilities, only "common" formats are proposed (e.g. we assume that a profile ID always use the same level ID, which is not certain).
If -i is provided, the SDP file will not be created from scratch but input
will be updated with user-supplied information (useful to update the port).
H.264 and H.265 require detailed video format info that cannot be created from scratch (RFC 6184 for H.264, RFC 7798 for H.265). So we build a SDP file that lack them. Media players may be able to read the stream without it (not always, unfortunately).
usage: camamber-sdp.py [-h] [-v] [-o filename] [-i sdp_file] [-d ip_addr] [-p port]
[-c codec] [-rp profile] [-pt pt] [-cr clockrate]
[-pm packetization mode] [-pi profileid]
options:
-h, --help show this help message and exit
-v, --verbose Print additional information
-o filename, --output filename
Filename to write the SDP file to
-i sdp_file, --input sdp_file
Existing SDP to adapt (if any)
-d ip_addr, --dest ip_addr
IP address on which the video stream arrives
-p port, --port port Port on which the video stream arrives
-c codec, --codec codec
Stream format
-rp profile, --rprofile profile
RTP profile (most common: RTP/AVP)
-pt pt, --payloadtype pt
Payload type (most common: 96)
-cr clockrate, --clockrate clockrate
Clock rate (most common: 90000)
-pm packetization mode, --packetmode packetization mode
Packetization mode (most common: 1)
-pi profileid, --profileid profileid
Profile ID (Baseline, Main, High)
Once you have your SDP file ready, you can use it while CamAmber is running to
read an intercepted RTSP video stream :) (vlc camamber.sdp)
This is a Python 3.12+ requiring package onvif-zeep for all modes.
python -m venv camamber
source camamber/bin/activate
pip install onvif-zeep
python camamber-onvif.py
VLC is required for screen mode.
camamber-onvif.py [mode] [additional parameters]
Three modes are available so far: test, rtsp, discover and screen. For
all modes:
targetis either an IPv4 address, an IPv4 range (A.B.C.D/X) or a file containing a list of IPv4 addresses (one per line).usernameandpasswordare optional but must be supplied if the remote ONVIF service has authentication enabled.
Check if the ONVIF service is running on a port and if it requires authentication. Standard ports 80, 8080, 8000 and 8899 are tested, you can add more by editing the code.
camamber-onvif.py test target
Retrieve useful data from a device using ONVIF.
camamber-onvif.py discover target port [username] [password]
Only retrieves the RTSP stream URL from the device using ONVIF.
camamber-onvif.py rtsp target port [username] [password]
Take a screenshot of the video stream (requires VLC to be installed).
camamber-onvif.py screen target port [username] [password]
Note : You may not need this feature as the discover function gives a link to access a snapshot from the camera (but this is not always supported).
If you want to run your own man-in-the-middle attack and not rely on CamAmber's
-M option:
You need to use a tool/option that does not perform its own packet forwarding, because it must be handled by your system like this:
- Enable IP forwarding (
sudo sysctl -w net.ipv4.ip_forward=1) - Change iptable rule for packet forward from DROP to ACCEPT (
sudo iptables -P FORWARD ACCEPT)
Example with ettercap and arpspoof:
sudo arpspoof -i <iface> -t <viewer_ipaddr> <camera_ipaddr> -r
sudo ettercap -T -M arp:remote /<camera_ipaddr>// /<viewer_ipaddr>// -o
-ois required for ettercap here, because it prevents it from doing its own forwarding.
Before running CamAmber, check that the MITM works with:
sudo tcpdump -ni <iface> host <viewer_ipaddr> and udp -vvv
If you are lucky enough to capture the RTSP session initialization frames, it is really easy to extract the SDP file and to save it for later use.
This method was discovered in the book Practical IoT Hacking, The Definitive Guide to Attacking the Internet of Things by Fotios Chantzis and Ioannis Stais. I encourage you to read this book, which contains many interesting tricks for IoT hacking :)
If you have captured the RTSP init in Wireshark, there should be a packet tagged
"RTSP/SDP". Right-click on it > Export Packet Bytes and save the file as
XX.sdp.
The SDP file should look like this (parameters may change):
v=0
o=- 0 0 IN IP4 127.0.0.1
s=CamAmber
c=IN IP4 127.0.0.1
t=0 0
m=video 0 RTP/AVP 96
a=rtpmap:96 H264/90000
a=recvonly
a=fmtp:96 packetization-mode=1;profile-level-id=640029;sprop-parameter-sets=Z2QAKawbGoBQBb/wFuAgICgAAB9AAAdTB0MAAX14AAB3NZXeXGhgAC+vAAAO5rK7y4U=,aO44MA==
The author of this toolkit is not a big fan of AI but it has still been used for the things listed below. All the information provided have been checked in RFCs and all the code samples have been rewritten:
- Code line required to access the RTSP Stream URI information in a response to
an ONVIF Web Server Get request using the library onvif-zeep
(
camamber-onvif.py:onvif_getstreaminfo) - Help to understand RFC 8866 and RFC 6184 for SDP format, especially the
a=fmtpline (camamber-sdp.py) - Help to understand netfilter queues and associated iptables rules (
camamber.c) - RTP frames parsing and checksum calculation in C (
camamber.c)
RFC:
- RFC 7826 - Real-Time Streaming Protocol Version 2.0
- RFC 6184 - RTP Payload Format for H.264 Video
- RFC 8866 - SDP: Session Description Protocol
Research material:
Tooling:
Handbooks and tutorials:
