From Zero to Hero in 5 mins - pingumacpenguin/FH86XX_Cameras GitHub Wiki

This page describes the process of getting root, setting your own root password and generally messing with the camera's mind thereafter.

I am assuming you are running Linux on your PC or laptop for this hack.

If not, you are on probably out of luck since this process relies on running shell scripts from your PC or laptop.

I'm also assuming you grabbed the shell scripts that are in the main repo, if not, grab them from the link below now, as you will need them in order to hack the camera.

Make sure you remember to chmod your copies of the shell scripts +x so you can run them.

https://github.com/pingumacpenguin/FH86XX_Cameras/tree/main/scripts

This procedure should give you full access to a brand new out of the box camera.

(or one that you have booted with the reset button pressed for 20 seconds to set it to defaults).

The whole process should only take a few minutes from removing the shrink wrap to pwning the camera, and all without needing to install the camera APP from some dodgy vendor, or send them your email address, or purchase their expensive "cloud storage" option.

Proceed as follows:-

Remove camera from box and plug in usb lead to the camera.

Plug in the other end of the USB lead to a suitable USB adapter or a spare USB port on your laptop.

Boot the camera

Wait for the second irritating startup message from the overly loud camera speaker.

Find camera AP network. It will have sone random SSID based on its serial number. It is completely open, no password.

For example CFETA-101444-TFXBZ

Connect to this SSID from your laptop or PC (with your alternative wifi card if you have one, but failing that just disconnect from your main WiFi and join the camera SSID)

Once you have an IP on the Camera WiFi run this on your laptop or PC.

route -n

.. or .. 

sudo route -n

This will show the router on the camera's subnet.

# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.55.1     0.0.0.0         UG    600    0        0 wlp4s0

In the case of the cameras I have the default router/gateway IP is 192.168.55.1

Your IP may be different (but probably isn't).

The Router is the camera, so this is the IP we are going to attack.

From the repo, grab the shell scripts, and use ...

use_vuln.sh

or

quickroot.sh

./quickroot.sh check 192.168.55.1

This will set the root password to root (or whatever password you called the script with. cat the script for details).

telnet to the camera as user root, with the aforementioned password.

$ telnet 192.168.55.1
Trying 192.168.55.1...
Connected to 192.168.55.1.
Escape character is '^]'.
(none) login: root
Password: 


BusyBox v1.26.2 (2023-08-17 14:38:28 CST) built-in shell (ash)
Enter 'help' for a list of built-in commands.

[/app]# 
 

You should be able to login and see the BusyBox shell prompt. Next we are going to set up our real WiFi network.

First run ifconfig on the camera and take a note of the mac address for wlan0

[/app]# ifconfig
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

wlan0     Link encap:Ethernet  HWaddr 68:8F:C9:F0:F2:FF  
          inet addr:192.168.55.1  Bcast:192.168.55.255  Mask:255.255.255.0
          inet6 addr: fdc0:eea2:f5b8:0:6a8f:c9ff:fef0:f2f5/64 Scope:Global
          inet6 addr: fdd7:fbbf:f96c:0:6a8f:c9ff:fef0:f2f5/64 Scope:Global
          inet6 addr: fdd5:73a0:5a83:0:6a8f:c9ff:fef0:f2f5/64 Scope:Global
          inet6 addr: fe80::6a8f:c9ff:fef0:f2f5/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:67142 errors:0 dropped:16 overruns:0 frame:0
          TX packets:126259 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:5154800 (4.9 MiB)  TX bytes:9546879 (9.1 MiB)

Next use the vi editor to modify the camera's icfonfig.wlan0 file to set up your real WiFi config.

vi /app/userdata/ifcfg.wlan0

Paste in your Actual WiFi credentials based on the example below ... You don't need the comments obviously.

DHCP=yes
WIFI_SSID=Wibble                         # <= Your SSID Goes Here 
WIFI_SECURITY=WPA2-PSK                   # ...or whatever is appropriate for your particular WiFi
WIFI_PSK=Wobble                          # <= Your WiFi Password goes here  

... Reboot the camera

reboot

It should join your main wifi. Once it has booted up, set your own wifi back to the main one too.

Find the new camera's mac address and IP in your router's DHCP pool, unless you have an easier way to figure this out.

Set this as a reservation in your routers DHCP pool. That way the camera will always show up on the same address on your network.

For example if your camera shows up on 192.168.7.8 then set that as a reservation, then

Run vuln.sh or quickroot.sh on your laptop or PC again, but this time on the new IP

./quickroot.sh check 192.168.7.8

telnet to the camera again.

Now we can permanently set the root password to root (or whatever you chose).

Run this on the camera not on your PC or laptop.

(NOTE: We are echoing user:password to the chpasswd command on the camera here. Be careful if you change any other password or run it on the wrong machine as stuff may break).

echo root:root | chpasswd; cp /etc/shadow /app/userdata/shadow; cd /app; /app/app_shadow.sh

You can now reboot the camera and you should see it re-appear on the network with the new root password.

NOTE: This password is just as insecure as the original, and is vulnerable to same the exploit we used to originally get access.

These cameras are inherently insecure. Don't use them for anything that needs to be truly secure, and don't expose them to the internet as they will be easily exploited.

The rtsp multicast stream(s) are on by default, example URL is below.

rtsp://admin:admin123456@[IP]:8554/profile0 # for full res (720p) and profile1 for lowres.

ONVIF on the other hand is not.

To switch ONVIF on, you will need to run the update_env.sh script from this repo on your PC or laptop.

Run it as follows.

./update_env.sh 192.168.7.8 1300 onvif=yes
<WRITEENV_ACK>ok</WRITEENV_ACK>
./update_env.sh 192.168.7.8 1300 onvif_port=6688
<WRITEENV_ACK>ok</WRITEENV_ACK>

To prove ONVIF is working, connect your onvif client and make a few requests.

There is a simple test_onvif.sh script with the other bash scripts in the repo.

The script should return the result of an ovif < GetProfiles/ > request.

It assumes you have curl and xmllint installed, so check and if necessary install those packages first.

You can run it as shown in the examples below.

test_onvif.sh 

...or...

./test_onvif.sh 192.168.7.4 6688

Typical output is as follows.


<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:e="http://www.w3.org/2003/05/soap-encoding" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:wsntw="http://docs.oasis-open.org/wsn/bw-2" xmlns:wsrf-rw="http://docs.oasis-open.org/wsrf/rw-2" xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2" xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl" xmlns:wsoap12="http://schemas.xmlsoap.org/wsdl/soap12" xmlns:http="http://schemas.xmlsoap.org/wsdl/http" xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:wsadis="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:tns1="http://www.onvif.org/ver10/topics" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" xmlns:tev="http://www.onvif.org/ver10/events/wsdl" xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" xmlns:tst="http://www.onvif.org/ver10/storage/wsdl" xmlns:dn="http://www.onvif.org/ver10/network/wsdl" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl" xmlns:axt="http://www.onvif.org/ver20/analytics" xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl" xmlns:ter="http://www.onvif.org/ver10/error">
  <s:Body>
    <tds:GetCapabilitiesResponse>
      <tds:Capabilities>
        <tt:Analytics>
          <tt:XAddr>http://192.168.7.4:6688/onvif/analytics_service</tt:XAddr>
          <tt:RuleSupport>true</tt:RuleSupport>
          <tt:AnalyticsModuleSupport>true</tt:AnalyticsModuleSupport>
        </tt:Analytics>
        <tt:Device>
          <tt:XAddr>http://192.168.7.4:6688/onvif/device_service</tt:XAddr>
          <tt:Network>
            <tt:IPFilter>false</tt:IPFilter>
            <tt:ZeroConfiguration>false</tt:ZeroConfiguration>
            <tt:IPVersion6>false</tt:IPVersion6>
            <tt:DynDNS>false</tt:DynDNS>
            <tt:Extension>
              <tt:Dot11Configuration>false</tt:Dot11Configuration>
            </tt:Extension>
          </tt:Network>
          <tt:System>
            <tt:DiscoveryResolve>false</tt:DiscoveryResolve>
            <tt:DiscoveryBye>true</tt:DiscoveryBye>
            <tt:RemoteDiscovery>false</tt:RemoteDiscovery>
            <tt:SystemBackup>false</tt:SystemBackup>
            <tt:SystemLogging>true</tt:SystemLogging>
            <tt:FirmwareUpgrade>true</tt:FirmwareUpgrade>
            <tt:SupportedVersions>
              <tt:Major>17</tt:Major>
              <tt:Minor>12</tt:Minor>
            </tt:SupportedVersions>
            <tt:SupportedVersions>
              <tt:Major>2</tt:Major>
              <tt:Minor>6</tt:Minor>
            </tt:SupportedVersions>
            <tt:SupportedVersions>
              <tt:Major>2</tt:Major>
              <tt:Minor>4</tt:Minor>
            </tt:SupportedVersions>
            <tt:SupportedVersions>
              <tt:Major>2</tt:Major>
              <tt:Minor>0</tt:Minor>
            </tt:SupportedVersions>
            <tt:Extension>
              <tt:HttpFirmwareUpgrade>true</tt:HttpFirmwareUpgrade>
              <tt:HttpSystemBackup>false</tt:HttpSystemBackup>
              <tt:HttpSystemLogging>false</tt:HttpSystemLogging>
              <tt:HttpSupportInformation>false</tt:HttpSupportInformation>
            </tt:Extension>
          </tt:System>
          <tt:IO>
            <tt:InputConnectors>0</tt:InputConnectors>
            <tt:RelayOutputs>0</tt:RelayOutputs>
            <tt:Extension>
              <tt:Auxiliary>false</tt:Auxiliary>
              <tt:Extension/>
            </tt:Extension>
          </tt:IO>
          <tt:Security>
            <tt:TLS1.1>false</tt:TLS1.1>
            <tt:TLS1.2>false</tt:TLS1.2>
            <tt:OnboardKeyGeneration>false</tt:OnboardKeyGeneration>
            <tt:AccessPolicyConfig>false</tt:AccessPolicyConfig>
            <tt:X.509Token>false</tt:X.509Token>
            <tt:SAMLToken>false</tt:SAMLToken>
            <tt:KerberosToken>false</tt:KerberosToken>
            <tt:RELToken>false</tt:RELToken>
            <tt:Extension>
              <tt:TLS1.0>false</tt:TLS1.0>
              <tt:Extension>
                <tt:Dot1X>false</tt:Dot1X>
                <tt:SupportedEAPMethod>0</tt:SupportedEAPMethod>
                <tt:RemoteUserHandling>false</tt:RemoteUserHandling>
              </tt:Extension>
            </tt:Extension>
          </tt:Security>
        </tt:Device>
        <tt:Events>
          <tt:XAddr>http://192.168.7.4:6688/onvif/event_service</tt:XAddr>
          <tt:WSSubscriptionPolicySupport>true</tt:WSSubscriptionPolicySupport>
          <tt:WSPullPointSupport>true</tt:WSPullPointSupport>
          <tt:WSPausableSubscriptionManagerInterfaceSupport>false</tt:WSPausableSubscriptionManagerInterfaceSupport>
        </tt:Events>
        <tt:Imaging>
          <tt:XAddr>http://192.168.7.4:6688/onvif/image_service</tt:XAddr>
        </tt:Imaging>
        <tt:Media>
          <tt:XAddr>http://192.168.7.4:6688/onvif/media_service</tt:XAddr>
          <tt:StreamingCapabilities>
            <tt:RTPMulticast>false</tt:RTPMulticast>
            <tt:RTP_TCP>true</tt:RTP_TCP>
            <tt:RTP_RTSP_TCP>true</tt:RTP_RTSP_TCP>
          </tt:StreamingCapabilities>
          <tt:Extension>
            <tt:ProfileCapabilities>
              <tt:MaximumNumberOfProfiles>10</tt:MaximumNumberOfProfiles>
            </tt:ProfileCapabilities>
          </tt:Extension>
        </tt:Media>
        <tt:PTZ>
          <tt:XAddr>http://192.168.7.4:6688/onvif/ptz_service</tt:XAddr>
        </tt:PTZ>
        <tt:Extension>
          <tt:DeviceIO>
            <tt:XAddr>http://192.168.7.4:6688/onvif/deviceIO_service</tt:XAddr>
            <tt:VideoSources>1</tt:VideoSources>
            <tt:VideoOutputs>0</tt:VideoOutputs>
            <tt:AudioSources>1</tt:AudioSources>
            <tt:AudioOutputs>1</tt:AudioOutputs>
            <tt:RelayOutputs>0</tt:RelayOutputs>
          </tt:DeviceIO>
        </tt:Extension>
      </tds:Capabilities>
    </tds:GetCapabilitiesResponse>
  </s:Body>
</s:Envelope>

This shows us amongst other things that the camera exposes the following servivces.

<tt:XAddr>http://192.168.7.4:6688/onvif/analytics_service</tt:XAddr>
<tt:XAddr>http://192.168.7.4:6688/onvif/deviceIO_service</tt:XAddr>
<tt:XAddr>http://192.168.7.4:6688/onvif/device_service</tt:XAddr>
<tt:XAddr>http://192.168.7.4:6688/onvif/event_service</tt:XAddr>
<tt:XAddr>http://192.168.7.4:6688/onvif/image_service</tt:XAddr>
<tt:XAddr>http://192.168.7.4:6688/onvif/media_service</tt:XAddr>
<tt:XAddr>http://192.168.7.4:6688/onvif/ptz_service</tt:XAddr>

The exact capabilities of these services are curently unknown, so I'll leave this as an excersise for the reader to figure out.

If I make significant progress on this myself, I'll document them here on the Wiki.

There are obviously more capable ways of controlling the camera, but it is up to you what you want to do with it.

For example if you are using ZoneMinder it has a test perl script called zmonvif-probe

We can use this to check the camera for profiles.. example below.

 zmonvif-probe.pl profiles http://192.168.7.8:6688/onvif/device_service 1.2 admin admin123456
PROFILE_000, PROFILE_000, H264, 1280, 720, 15, RTP-Unicast, rtsp://192.168.7.8:8554/profile0
PROFILE_000, PROFILE_000, H264, 1280, 720, 15, RTP-multicast, rtsp://192.168.7.8:8554/profile0
PROFILE_000, PROFILE_000, H264, 1280, 720, 15, RTP-Multicast, rtsp://192.168.7.8:8554/profile0
PROFILE_001, PROFILE_001, H264, 640, 360, 15, RTP-Unicast, rtsp://192.168.7.8:8554/profile1
PROFILE_001, PROFILE_001, H264, 640, 360, 15, RTP-multicast, rtsp://192.168.7.8:8554/profile1
PROFILE_001, PROFILE_001, H264, 640, 360, 15, RTP-Multicast, rtsp://192.168.7.8:8554/profile1

.. and that is it. Camera is completely pwned, and we didn't even have to take the lid off.

NOTE: It still attempts to ping some random Chinese ips, which it uses as a keepalive, and it may do other nefarious things, but you can poison its DNS to keep this kind of nonsense under control.

You may even be able to get the camera to speak to one of your local servers and send alerts and/or video clips. I leave this as an exercise for the future.

Message me if you have any clever ideas about doing this.

I poison the dodgy DNS requests on my OpenWRT router by pointing their Host records to a dummy IP on my subnet like this.

image

(The camera's apollo binary tries to speak to these hosts, there may be others, and the Android/Apple APP may speak to others too).

devpush-hapseemate.dayunlinks.cn
upgrade.hapsee.cn
user.hapseemate.cn
wechat.hapseemate.cn

⚠️ **GitHub.com Fallback** ⚠️