DVRIP/Sofia dissector is part of a security assessment of an old and cheap Chinese IP camera (Besder 6024PB-XMA501), and, as previously mentioned, is based on existing dissector for Dahua’s DVRIP implementation. Although similar, DVRIP protocols between these vendors are not identical. For one, a single message on Dahua’s DVRIP implementation has 32 bit length header, while on Xiongmai-based IP cameras the header length of a message is observed to be 20 bits.
Main functionality of DVRIP/Sofia dissector is as follows and will be presented in subsequent sections:
/tmp directory for external multiplexing via ffmpeg.A DVRIP/Sofia message on Xiongmai-based devices has a 20 bit long header with the following structure:
Press enter or click to view image in full size
This header is taken from DVRIP keep alive request message that was sent to the IP camera for session maintenance. In Wireshark, DVRIP header bytes are saved in big-endian order, however when reading individual fields, byte order needs to be reversed to little-endian (LE) for correct parsing. The following is how the header is depicted in Wireshark:
10 fields in total were identified on this header:
0xff.0x00 for request messages and 0x01 for responses.0 when H.264 video codec is used (BIT4 = 0x02 on I-Frame header).1 when H.265 video codec is used (BIT4 = 0x12 on I-Frame header).128 when DVRIP/Sofia message contains audio frames.0 otherwise.Aside from DVRIP/Sofia message header, the aforementioned keep alive request includes a JSON payload:
{
"Name" : "KeepAlive",
"SessionID" : "0x00000006"
}IP camera responds with the following:
{
"Name" : "",
"Ret" : 100,
"SessionID" : "0x00000006"
}Return code 100 indicates a successful operation.
List with some of the documented command, response and return codes can be found in DVRIP_Sofia_reference_codes Github repository.
Join Medium for free to get updates from this writer.
For reassembling JSON objects, Wireshark has a JSON dissector built in:
-- Load JSON dissector
json = Dissector.get("json")Dissected DVRIP message with JSON payload is shown below:
The DVRIP/Sofia protocol has 5 distinct media frame types, each frame having unique header and a signature:
Schematics of DVRIP/Sofia media frame headers — taken from Xiongmai bitstream frame format document — are presented below:
Press enter or click to view image in full size
Additional details about each frame type are presented below.
I-Frame header is 16 bits in length and has seven fields identified:
Press enter or click to view image in full size
Each field can be described as follows:
Wireshark tree view of DVRIP/Sofia message with an I-Frame:
First 4 bits of an I-Frame payload (BITS 16–19) are equal to 0x00000001.
Header of a P-Frame is 8 bits long and has two identified fields:
Wireshark tree view of DVRIP message with (start of) a P-Frame:
First 4 bits of a P-Frame payload (BITS 8–11) are equal to 0x00000001.
Audio payload has 8 bit long header with four separate fields:
The fields can be explained as follows:
It gives the following view in Wireshark:
The information frame is 8 bits in length with four identified fields:
Used for information transmission. First byte after signature (byte 4):
Wireshark tree view of DVRIP message with E-Frame:
Another key addition to the dissector is the ability to reconstruct audio and video streams from a given .pcap file with collected streams being saved into /tmp directory. Each saved stream has it’s own key, which consists of:
As mentioned before, the streams are saved to /tmp directory in Linux:
Press enter or click to view image in full size
Combining separate audio and video streams into a single media file is not automated yet. However, for this purpose, the following ffmpeg command can be used from the CLI on Linux (Credits to kinsi55):
ffmpeg -i 192.168.1.103_0_0_video.h265 \
-f alaw \
-ar 8000 \
-ac 1 \
-i 192.168.1.103_0_128_audio.g711 \
-c:v copy \
-c:a mp3 \
-ar 44100 \
-f mp4 \
-y muxed.mp4A single stream containing both audio and video is saved as muxed.mp4 :
Press enter or click to view image in full size