Close

18th Sept 2021

A project log for Obtaining Control of JXD523 : the $20 drone

Obtaining access to a drone which is currently set to communicate with android application, allowing custom software to be built for it.

kynanKynan 09/18/2021 at 08:130 Comments

Hello to of you reading this.

Apologies in advance for a lack of in-code documentation.

However lets get on with the show.

___________________________________________________________________

To start being able to communicate with this device I determined that I would first need to identify what packets are being consumed by the device itself (JXD 523 Drone).

This proceeded the opening of Microsoft Network Monitor to obtain the contents shown in yes.cap in the download area and then focusing on the communication between 192.168.1.1(server\drone) and 192.168.1.101(Android\interfacing device).

As we can see we have an initial SIP request which also refers to an URL which may be the key to communicating with our device.

Using the details in this packet I then was able to construct these packets in python and began trying to interface with the device.(Format of code was assisted by looking at a similar project by https://hackaday.io/AJF1982.

___________________________________________________________________

import socket
import time
import sys

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.1.1', 7070))

package= b'OPTIONS rtsp://192.168.1.1:7070/webcam RTSP/1.0\r\nCSeq: 1\r\nUser-Agent: Lavf56.40.101\r\n\r\n'
print(package)
s.send(package)
print("package sent")
data = s.recv(106)
print("package recved")
print(data)

Once I ran this code I had received a response of the following.

b'OPTIONS rtsp://192.168.1.1:7070/webcam RTSP/1.0\r\nCSeq: 1\r\nUser-Agent: Lavf56.40.101\r\n\r\n'
package sent
package recved
b'RTSP/1.0 200 OK\r\nCSeq: 1\r\nPublic: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE\r\n\r\n'

With some more work I was able to then use the sequences above just by replacing the first keyword at the start of every line after the identifier of b'  and incremented the CSeq: number which worked well until I got to the play line which returned Session not found until I added an extra s.recv command and made the package line more modular on line 39. (please see RSTPcontrol.py)

With my code set to complete the entire output looks like this:

b'OPTIONS rtsp://192.168.1.1:7070/webcam RTSP/1.0\r\nCSeq: 1\r\nUser-Agent: Lavf56.40.101\r\n\r\n'
package sent
package recved
b'RTSP/1.0 200 OK\r\nCSeq: 1\r\nPublic: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE\r\n\r\n'
b'DESCRIBE rtsp://192.168.1.1:7070/webcam RTSP/1.0\r\nAccept: application/sdp\r\nCSeq: 2\r\nUser-Agent: Lavf56.40.101\r\n\r\n'
package sent
package recved
b'RTSP/1.0 200 OK\r\nCSeq: 2\r\nContent-Base: rtsp://192.168.1.1:7070/webcam/\r\nContent-Type: application/sdp\r\nCo'
b'SETUP rtsp://192.168.1.1:7070/webcam/track0 RTSP/1.0\r\nTransport: RTP/AVP/UDP;unicast;client_port=57795\r\nCSeq: 3\r\nUser-Agent: Lavf56.40.101\r\n\r\n'
package sent
package recved
b'ntent-Length: 122\r\n\r\nv=0\r\no=- 1 1 IN IP4 127.0.0.1\r\ns=Test\r\na=type:broadcast\r\nt=0 0\r\nc=IN IP4 0.0.0.0\r\nm=v'
b'ideo 0 RTP/AVP 26\r\na=control:track0\r\nRTSP/1.0 200 OK\r\nCSeq: 3\r\nTransport: RTP/AVP;unicast;client_port=57795-57796;server_port=55934-55935\r\nSession: 82838485868788898A8B8C8D8E8F90\r\n\r\n'
Session: 82838485868788898A8B8C8D8E8F90
['server_port', '55934-55935']
b'PLAY rtsp://192.168.1.1:7070/webcam RTSP/1.0\r\nRange: npt=0.000-\r\nCSeq: 4\r\nUser-Agent: Lavf56.40.101\r\nSession: 82838485868788898A8B8C8D8E8F90\r\n\r\n'
b'RTSP/1.0 200 OK\r\nCSeq: 4\r\nSession: 82838485868788898A8B8C8D8E8F90\r\n\r\n'
b'\x80\x1a\x81\x80\x7f~\xa0\xa4{zyx\x00\x00\x00\x00A\xffP<\x04\xb9\x81\x00\x00\x00\x00\x80\x17\x10\x11\x14\x11\x0e\x17\x14\x12\x14\x1a\x18\x17\x1b"9%"\x1f\x1f"F25)9RHWUQHPN[f\x83o[a|bNPr\x9bs|\x87\x8b\x92\x94\x92Xm\xa0\xac\x9f\x8e\xaa\x83\x8f\x92\x8d\x18\x1a\x1a"\x1e"C%%C\x8d^P^\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\xbe\xd0\xf3\xd2\x98b\xc7\xadj\x18j6\x84\xfaWj\xa8I\x9ab4\xd3\x11\x15\xa0`>\x95\x19\x83\xfd\x91V\xaa\x0c\xa0P\xfaSJ\x1a\xbeb\xff\x008\xa8\xcc>\xd5j`R*})\xa5O\xa5\\hi\x86\x1fJ\xb54\x05R(\xc5X1z\x81M1\x9fJ|\xc8\x08qF\rK\xb0\xd0P\xd3\xb8\x0c\x02\x8cS\xf6\xd1\x8aW\x02<R\xe2\x9f\x8a1E\xc7a\xa0R\xe2\x8cQ\x9a\x06\x19\xf5\xa6\x93A4\xd2i\xd8.)4\xd2i)*\xac+\x814\x94\xb8\xa3\x14\t\x858RQ@\x87\x03N\xcd34\xb9\xa4\x03\xb3J\rG\x9ap4\xac1\xf9\xa34\xda)X\x05\xa4\xa5\xa5\x02\x80\x10\n]\xbe\xd4\xe0\xb4\xf0\xb4\x9b\x19\x1e\xdar\xadH\x12\xa4X\xea\\\x861S\xda\xa5U4\xe5Oj\x95R\xb3r\x01\xaa\xb5"\xad9V\xa4\x0bY9\x00\xd5Z\x90-(\x14\xe0+6\xc5q\x02\xd1\x8aZ*n\x02b\x93\x14\xb4S\x00\xa2\x8a(\x00\x14\xb4QHAE\x14\xb4\x00R\xd0)i\x00QK\x8a\\R\x01\xb4\xb4\xb8\xa3\x14\x08)q@\x14\xb4\x80)h\xa2\x90\x05\x14Q@\xc2\x8a)i\x00RR\xd1@\x05\x14Q@\xc2\x8a(\xa0\x02\x8a(\xa0\x02\x8a(\xa0\x02\x8a(\xa0\x0f\xff\xd0\xea\xb6\x8aB\x99\xa7\xd1N\xe2\xb1\x11\x8f\xda\x98b\x1e\x95b\x93\x14\xd4\x98\x15LT\xc3\x00\xab\x98\x14\x85A\xabSb(4\x03\xd0~T\xc3\rh\x18\xc54\xc6*\xd5@3\x8c4\xc3\x0f\xa0\xad#\x18\xf4\xa6\x18\xbd\xaa\xd5A\x99\xa6/\xf3\x8a<\xafo\xd2\xaf\x98\xbd\xa9\x86\x1a\xa5Pe\x13\x154\xc7W\x8c5\x1bEV\xa6\x052\x94\xd2\xa7\xd2\xad\x98\xbd)\xa6#\x8e\xff\x00\x95R\x90\xca\xa5H\xedL`j\xd3&*6J\xa5 *\x9amX)\xedM\xd9Z&I\x15\x18\xa9vRl4\xee\x031I\x8a~)1E\xc46\x8a\\Q\x8a\x00m.h\xc5(Ri\x80\x80sO\x02\x95R\xa5\tR\xd8\xecE\x8apZ\x94%<E\xfeqP\xe4;\x10\x84\xa7\x88\xeaeOJxJ\x871\xa2\x15\x8f\xda\x9e#\xf6\xa9\x82{S\x82\xd49\x81\x12\xa5H\x16\x9e\x16\x9c\x16\xa1\xc8.4%H\xabJ\x05<\n\x86\xc4\x01i\xc0QFj\x00Z)3E!\x0bFi(\xa0\x05\xa4\xa2\x8a\x02\xe2\xd1E-\x00%\x14\xb8\xa5\xc5\x02lJ1N\xc5\x18\xa5p\xb8\x80S\x80\xa0\np\x14\x9b\x10\x01KF)jF&(\xc5-\x14\x00QE\x14\x00QE-!\x85\x14Q@\x05\x14Q@\xc2\x8a(\xa0\x02\x8a(\xa0\x02\x8a(\xa0\x02\x8a(\xa0\x02\x8a(\xa0\x02\x8a(\xa0\x0f\xff\xd1\xeb(\xa2\x8a\x00(\xa2\x8a\x00(\xa2\x8a\x00J1KE\x02\x1b\xb6\x90\xad>\x92\x9d\xc0\x8c\xa54\xa5Ji\xa6\xa91\x11\x14\xa8\xcaT\xe6\x9aj\x93`W()\x85*v\xc5FkD\xc6@\xc9\xedQ\xb4ud\xd3\x08\x15jB\xb9U\xa3\xa8\xccui\x850\x8a\xd1Hd\x1b=\xa96z\xd4\xd8\xa3\x15\\\xc1r\x0f/\xda\x9b\xe5\xd5\x82(\xdbO\x98\n\xc5)<\xb3V\x8a{Ryt\xf9\x86V\xd9\xedNX\xcf\xa5X\x11\x8apJ\x1c\xc0\x89c5"\xc7\x8e\xd5"\xa75(Z\xcd\xccdA)\xe2:\x93m8\n\xcd\xc8DA)\xe1i\xf8\xa5\xc5O0\\f(\x02\x9dE+\x80\x80S\x85%.h\x01\xc2\x96\x9a\r.jD;4f\x9bE\x00:\x8aJQHB\xd1E(\xa4 \xa5\xa0R\xd0\x02b\x97\x14\xa2\x9c\x05+\x80\xdcR\xe2\x9d\x8a1J\xe0&)qE- \x10\nu%\x14\x80Z(\xa2\x81\x85\x14Q@\x05\x14R\xd2\x18QE\x14\x0c(\xa2\x8a\x00(\xa2\x8a\x00(\xa2\x8a\x00(\xa2\x8a\x00(\xa2\x8a\x00(\xa2\x8a\x00(\xa2\x8a\x00(\xa2\x8a\x00\xff\xd2\xeb(\xa2\x8a\x00(\xa4\xcd\x19\xa0W\x16\x92\x90\x9aM\xd4\xec\x03\xa8\xcd3u!j,\x04\x99\xa4-Q\xee\xa6\x96\xa7`\x1eZ\x9aZ\x98Z\x98Z\xadDv\x1eZ\x98^\x98M4\x9a\xb5\x10\xb0\xac\xf4\xd2\xd4\xd2i\x84\xd5\xa4\x16\x1eZ\x9aZ\x98M&j\xac+\nM4\xd0M%U\x80(\xa3\x14\x01L,.)@\xa0\np\x14\x9b\x04\x84\xdbK\xb6\x9e\x05.*n1\x81i\xc1i\xd8\xa5\x02\x95\xc0EQN\xa0QR\x02\xd2\xd2QH\x05\xa2\x92\x96\x81\x05\x06\x8aJ\x00(\x14R\xd0+\x8a)E \xa7\x81I\x80\xdaZv)qJ\xe2\x1bJ)qF)\\\x00R\xd1\x8aZB\x01KE(\xa4\x02\x8ap\xa6\x8ap\xa9\x01h\xa2\x8aC\n(\xa2\x80\n(\xa2\x80\x16\x8a(\xa0aE\x14\xb4\x86\x14QE\x03\n(\xa2\x80\n(\xa2\x80\n(\xa2\x80\n(\xa2\x80\n(\xa2\x80\n(\xa2\x80\n(\xa2\x80\n(\xa2\x80\n(\xa2\x80?\xff\xd3\xea\xf3M-L-M\xddUa\x12\x16\xa4\xddQ\xee\xa35V\x0b\x0e-I\xba\x9aM&i\xd8v\x1f\x9a3L\xa5\xa2\xc1asM4\xb4b\x81\x8c4\xd2*LR\x11Uq\x91\xe2\x9aEJE0\xd5&"2)\x84T\xa4S\x08\xaaL\x08\x98S*R*2+D\x02QF)'

However attempts to play this using CV2 player have been unsuccessful as the data received is not recognizable. 

I am sure that that given some more time I will be able to decode this data to be played.

When it comes to sending commands I will need to make the first chip which has the camera attached then communicate to the chip with the STM32 microcontroller onboard.

My current theory is that these controls get sent to the server port (Found in the reply after the setup command) via UDP to the same IP address as seen on the following stream:

As when we open this to see all frames the source IP Address appears to be the android device being used to control the drone.

(as seen below)

Looking into these packets there is not much to read when we look at the payload as I am unsure on how to decode these messages or whether this is meant to be all hex.

All packets either have the above payload or the one below.

I then decided to connect to the port I received in the RSTP request using the following code.

s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s2.connect(('192.168.1.1', int(serverport[1])))

And then sent packets with the hex byte values replicated as below.

s2.send(bytes.fromhex('7F'))
s2.send(bytes.fromhex('19 FF FF FF FF 7F 7F E6'))

To which these looked identical to the packets I had captured in Microsoft Network Monitor. Alas no change in lights or action on the drone from these packets being sent.

Please feel free to reach out to me if you have any suggestions or anything at all to add to this project I will respond when I can.

Discussions