Mercury MIPC251C-4 Web Camera with ONVIF and PTZ Control
Jul 23, 2019
Use Charles JADX WireShark reverse engineering Mercury MIPC251C-4 Web Camera App and admin web page to write a control script.
Charles cannot capture packets. APK decompile but no luck, control CMD implemented in JNI. But WireShark can capture control packets for iOS app. Login logic can be found in admin web page.
The Script: https://github.com/likaci/mercury-ipc-control
Recently, I found a Mercury IPC on SMZDM. Apart from supporting PTZ and night vision features, it also claims to support the ONVIF protocol. So I decided to buy one and add it to HomeAssistant for monitoring. However, after getting my hands on it, I realized that things weren't as simple as it seemed. Here are my findings.
According to the HomeAssistant documentation on ONVIF Camera, integrating should be as simple as adding a couple of lines in the configuration file. But whether I used the default configuration or tried various ports on the backend page, I couldn't add the camera successfully.
Finally, using DSM Surveillance Station from Synology, I found the correct port. Later, I discovered that I could also find the correct port using iSpy. The port is 2020.
Here is the HomeAssistant configuration:
http://192.168.2.x:2020/onvif/device_serviceRTSP 1920x1080 URL:
rtsp://admin:firstname.lastname@example.org:554/stream1RTSP 640x480 URL:
After integrating with HomeAssistant and DSM Surveillance Station, I realized that PTZ control was not working. It seems that the claim of ONVIF support only applies to recording.
The rest of this article focuses on how to control the PTZ function.
I tried capturing packets using Charles, but the application didn't go through the configured proxy.
After unsuccessful attempts to capture packets using Charles, I tried decompiling the Mercury Security App. To my surprise, I found a lot of code related to
com.tplink.ipc, indicating that Mercury is indeed a sibling of TP-Link. The app is obfuscated, which makes it challenging to analyze.
- Adding Local LAN Devices:
com.tplink.ipc.ui.device.add.DeviceAddByDeviceDetailInputFragment#xcom.tplink.ipc.core.IPCAppContext#devReqAddDevice(java.lang.String, int, java.lang.String, java.lang.String, int, int). The
devReqAddDevicemethod calls a native function, and the actual implementation is found in
libIPCAppContextJNI.so. It seems that the network requests are made within the JNI code, making it difficult to capture them using Charles. Decompiling the
.solibrary is not worth the effort, so let's try a different approach.
rvictl, I can also capture packets over 3G/4G connections, which is useful for capturing packets related to issues that only occur in a 4G environment. Additionally, for devices that do not support setting up a proxy, I can enable the iPhone's personal hotspot and capture packets that way.
To capture packets, run the following command:
rvictl -s 0000xxxx-00xxxxxxxxxxxxxx
I discovered the network requests for the login and PTZ control steps:
Use the obtained
stokto send POST requests:
Currently, it seems that obtaining the
stokis the key to controlling the PTZ function. It can be obtained by capturing packets, but it seems to become invalid after the device restarts or after some time has passed (not confirmed).
Although this camera has a web interface, it does not support PTZ control through the web. Therefore, in the initial packet capture, I did not consider the web interface. However, after analyzing the web interface, I found that the login verification process uses the same logic.
Here are the steps:
- Retrieve the RSA public key and nonce (both change every time)
- Encrypt the password
tpPasswordusing TP-Link's universal encryption method
tpPassword:nonceusing the public key as
rsaPasswordas the password for camera verification
Regarding steps 2 and 3, here is the record:
A search for "RDpbLfCPsJZ7fiv" reveals various implementations of this encryption method.
In the image,
a = a.concat(":", $.authRltObj.nonce)appends the nonce.
c.setPublicKey($.authRltObj.key)sets the public key. The subsequent
sendAjaxReqis thecontinuation of the process.
Based on the analysis above, I have written a control script.