Lollipop Camera Reverse Engineering

Lollipop Camera is designed to monitor babys. For details regarding the product, visit https://www.lollipop.camera/ website. It is quite affordable, and working pretty well.

The camera itself has a very good picture quality in night-vision or daylight. It comes with a mobile app to configure and use it.

For fun and integration, I was looking for reverse engineering, and integrate it into my existing home automation setup (OpenHAB).

RTSP Flow

First good news: the camera supports and provides a direct RTSP flow! It is however not communicated officially. I discovered it by observing network traffic with Wireshark.

Only remark is that the address of the channel is not the same for all cameras, and has a variable part in the path:

rtsp://172.16.100.181:554/live/23a711d9d154733c4c432b959db25b09/ch00_0

Good news – it was easy to reverse and understand how to get this URL part!

When the camera is associated with an account during the setup phase – it gets associated a unique identifier. If you unregister and re-pair your camera, this ID will change. The number in the path is a simple MD5 hash of this pairing ID.

To compute the MD5 hash, one can use the following command under a Unix-like system:

echo -n '<id>' | md5sum

How to obtain this ID ? 2 solutions.

First solution, use the cloud API and retrieve the list of devices associated with your account.

Second solution, use the MQTT embedded broker (see next paragraph).

Once you get this unique ID, just get the MD5 hash of it and use your favorite tool such as VLC to access the video live feed:

The video itself is standard h264 encoded, full HD (1080p) and 30fps. It also has audio (AAC).

MQTT Broker

The camera hosts an MQTT broker on typical 1883 TCP port. One remark here – it is using TLS on the 1883 port – but without any authentication (I therefore wonder the goal of using TLS if no authentication is required…).

To connect to the broker and observe the trafic, you can either use a tool such as MQTT Explorer or mosquitto_sub in CLI. Mosquitto is slightly more complex as it forces you to provide a certificate authority for TLS – even if you don’t care about validating the certificate (use of –insecure).

I recommend, if you want to go with Mosquitto, to use stunnel to remove TLS layer:

[mqtt]
client = yes
accept = 127.0.0.1:1883
connect = 172.16.100.181:1883
verifyChain = no

Then, start stunnel, and run mosquitto:

~ stunnel stunnel.conf
~ mosquitto_sub -h 127.0.0.1 -p 1883 -t '#'
{"method":"liveNote","result":{"motion":0.000000,"noise":26.137789,"ircut":1,"timestamp":1644060875}}
{"method":"liveNote","result":{"motion":0.000000,"noise":25.692110,"ircut":1,"timestamp":1644060877}}
{"method":"liveNote","result":{"motion":0.000000,"noise":26.108130,"ircut":1,"timestamp":1644060879}}
{"method":"liveNote","result":{"motion":0.000000,"noise":30.808922,"ircut":1,"timestamp":1644060881}}
{"method":"liveNote","result":{"motion":0.000000,"noise":30.426422,"ircut":1,"timestamp":1644060883}}
{"method":"liveNote","result":{"motion":0.000000,"noise":29.092848,"ircut":1,"timestamp":1644060885}}
{"method":"liveNote","result":{"motion":0.000000,"noise":24.882603,"ircut":1,"timestamp":1644060890}}
{"method":"liveNote","result":{"motion":0.000000,"noise":24.503872,"ircut":1,"timestamp":1644060892}}
{"method":"liveNote","result":{"motion":0.000000,"noise":28.854191,"ircut":1,"timestamp":1644060896}}
{"method":"liveNote","result":{"motion":0.000000,"noise":24.972601,"ircut":1,"timestamp":1644060898}}
{"method":"liveNote","result":{"motion":0.000000,"noise":25.041418,"ircut":1,"timestamp":1644060902}}
{"method":"liveNote","result":{"motion":0.000000,"noise":24.836710,"ircut":1,"timestamp":1644060904}}
{"method":"liveNote","result":{"motion":0.000000,"noise":25.788094,"ircut":1,"timestamp":1644060906}}
{"method":"liveNote","result":{"motion":0.000000,"noise":31.351727,"ircut":1,"timestamp":1644060908}}
{"method":"liveNote","result":{"motion":0.000000,"noise":25.534382,"ircut":1,"timestamp":1644060910}}
{"method":"liveNote","result":{"motion":0.000000,"noise":24.672976,"ircut":1,"timestamp":1644060912}}
{"method":"liveNote","result":{"motion":0.000000,"noise":24.879845,"ircut":1,"timestamp":1644060914}}
{"method":"liveNote","result":{"motion":0.000000,"noise":25.365896,"ircut":1,"timestamp":1644060916}}
{"method":"liveNote","result":{"motion":0.000000,"noise":31.724693,"ircut":1,"timestamp":1644060920}}
{"method":"liveNote","result":{"motion":0.000000,"noise":37.207649,"ircut":1,"timestamp":1644060922}}
{"method":"liveNote","result":{"motion":0.000000,"noise":31.941177,"ircut":1,"timestamp":1644060924}}
{"method":"liveNote","result":{"motion":0.000000,"noise":29.046495,"ircut":1,"timestamp":1644060926}}
{"method":"liveNote","result":{"motion":0.000000,"noise":25.750412,"ircut":1,"timestamp":1644060928}}

Or using a graphical tool such as MQTT Explorer:

Topics

<camera registration ID>/liveNote

{
   "method":"liveNote",
   "result":{
      "motion":0.000000,
      "noise":26.714561,
      "ircut":1,
      "timestamp":1644054668
   }
}

Messages are frequently being sent (every 3 or 4 seconds). Value can for example be used in a Grafana panel:


<camera registration ID>/cameraStatus
<camera registration ID>/cameraStatus/return
<camera registration ID>/liveNoteEnable
<camera registration ID>/liveNoteEnable/return
<camera registration ID>/watchLive
<camera registration ID>/watchLive/return
<camera registration ID>/musicStatus
<camera registration ID>/musicStatus/return
<camera registration ID>/controlMusic
<camera registration ID>/controlMusic/return
<camera registration ID>/heartbeat/return
<camera registration ID>/camSettings
<camera registration ID>/camSettings/return


<camera registration ID>/prenotify

Messages on this channel are the notifications configured, such as noisy environment:

{
   "preNotify":true,
   "event_time":1644048361346.000000,
   "camera_id":"xxxxxxxx",
   "param":{
      "camera_name":"Lollipop",
      "baby_name":"My Baby",
      "event_params":[
         {
            "event_type":3,
            "threshold":80,
            "val":80.279999
         }
      ]
   }
}

event_type:
3: noisy environment. with this event type, val is the noise level in DB.

General thoughts

I liked the fact that the camera is relatively opened, allowing the integration in existing installation. However, it is kind of insecure: getting IP connectivity to the camera, no password nor credential is required to access the video (including sound), nor control the camera through the MQTT broker.

As such, my recommendation would remain as usual: do not expose them to the internet, and if possible put all your IoT devices on a separate VLAN / SSID, with relatively strong isolation with your main network/VLAN/SSID.

17 Replies to “Lollipop Camera Reverse Engineering”

  1. What a great write up! This was very helpful. I have a Lollipop camera and started down the path of observing the network traffic via Wireshark. I wasn’t too sure what to look for so I started to search online and found your blog. Now I am able to connect my lollipop camera to my existing camera system which is ultimately what I wanted to do!

  2. Thanks for this writeup!
    I was pitching to my wife to replace our Lollipop with an rtsp camera so we could use Scrypted for HomeKit compatibility. After reading this, i’m convinced I can get my lollipop feed to display on my apple TV.

    1. I did not try to use it with HomeKit, I used my Synology DSM “Surveillance Station”, but that’s actually a very good idea ! Will try right away 🙂

  3. This was super helpful! Thanks for publishing it. I used it to get our Lollipop cam onto HomeAssistant using the generic camera integration (and from there onto our Google Nest).

    Just a quick note – it seems there was a firmware update recently which introduced authentication on the MQTT and RTSP connections. Thankfully I was able to packet capture the lollipop app using PCAPDroid, and find the credentials on the initial RTSP request (since it’s still unencrypted) and add them to HomeAssistant to get it working again.

    Hopefully if anyone else has the same problem this will help them!

    1. What did you use for frame rate and username password as RSTP transfer protocol?

      I have the url and I am able to see in VLC but homeassistant is not happy

    2. Were they using HTTP digest authentication at this point in time? If so I’m not sure how you were able to get the password for your camera? I have the packet dump.

    3. Hi James – I’ve got PCAPDroid and tried what looked like the credentials but can’t seem to get this to work through MQTT. Could you walk through what it looks like / how you did this? thanks

  4. For anyone with HTTP digest auth that can’t get the login off a packet trace, the full URL (including username/password) is available if you have a rooted Android phone. In com.aoitek.lollipop\databases\LollipopProvider.db you’ll find the baby_camera table with a internal_live_url column.

    1. Hi Tyler,
      I do not find the com.aoitek.lollipop\databases\LollipopProvider.db
      Do you know if something changed in the internal architecture of the App and where to find the user/pass?

      Thanks!

Leave a Reply to ben Cancel reply

Your email address will not be published. Required fields are marked *