Bottom Line: I got root on a WiFi Endoscope.
- Part 1: Introduction and Serial Debug Port to Get WiFi Password
- Part 2: Reading Flash to Get Telnet Password
- Part 3: Using WireShark to Decode UDP Protocol
- Part 4: Using Netcat to Decode Video Protocol
Part 4: Using Netcat to Decode Video Protocol
My primary objective with this project was to ensure that I could continue to use the endoscope even if the iOS app went unmaintained; after figuring out how to configure the endoscope’s settings, the last thing I needed was to be able to view the video feed without the app.
I’ve mentioned a few times that nmap showed port 7060 to be open, and that I suspected this was the video feed based on the fact that connecting to it yielded an unending stream of data.
Inspecting 30 seconds or so of its data, I found a few points of interest:
$ netcat 192.168.10.123 7060 > netcat_out $ strings netcat_out | head BoundaryS JFIF (:3=<9387@H\N@DWE78PmQW_bghg>Mqypdx\egc /cB8Bcccccccccccccccccccccccccccccccccccccccccccccccccc $3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz &'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz 1L@E ,%!4 Z@-8t
of those strings led me to believe it was using a JFIF image format (especially
since it includes
JFIF in the content). Eventually, I found a super helpful
SO answer suggesting that I
should look for
FFD8 to start and
FFD9 to end an image in the feed.
As a test, I tried to snip out a single image:
- Open the binary file in neovim:
nvim "+:setlocal display=uhex" netcat_out
- Delete until
- Find the next
- Advance 2 bytes:
- Delete until the end of the line:
- Go down a line:
- Delete until end of the file:
- Write the resulting data:
- Open the file:
The resulting file:
Clearly I was correct, this stream is the image data.
I tried a number of ways of viewing this stream in the browser without success, but I eventually found a Python method leveraging OpenCV that worked great. Below, I’m using OpenCV 4.0.1 installed via Homebrew and python 3.7.2.
import cv2 cap = cv2.VideoCapture("http://192.168.10.123:7060") while True: ret, frame = cap.read() cv2.imshow('Video', frame) if cv2.waitKey(1) == 27: exit(0)
The stream does have a strange line through the middle (like the image shown above), but other than that it seems to work well. If you have other suggestions on how to view this stream (especially if it gets rid of this artifact), feel free to let me know in the comments!
At this point, having read the firmware flash, discovered the telnet password for an administrative account, figured out how to configure the endoscope by sending commands over UDP, and figured out how to stream the video feed without requiring the app, I consider this project wrapped up. I hope you’ve enjoyed this writeup of my first adventure in reverse engineering an electronic device!
After many hours of fiddling, I finally figured out how to stream the video through VLC, and how to record video through ffmpeg, both of which may be more user-friendly than the python / opencv solution presented above.
After lots of experimenting with
tcp://, based on this SO
answer I finally came up with a
VLC command that works:
$ vlc 'tcp://192.168.10.123:7060/stream.mjpeg'
/stream.mjpeg, you can use
/file.mjpeg or even just
you want, the
.mjpeg just seems to be the prompting that VLC needs to get the
Alternatively, using the VLC GUI you can go to
Open Network and
To record to the file
out.mov instead, this seems to work:
$ ffmpeg -i 'tcp://192.168.10.123:7060' -c:v copy out.mov
A couple months ago, Matthew Plough emailed me to share further work he’s done with the video stream of a similar IOT device; notably, he’s found ways to clear up the video stream and has open-sourced code to help others do so. His write-up is a pleasure to read, fascinating, and demonstrates much better technical knowledge of this territory than I possess. I highly encourage you to read it!