Hijacking cheap WiFi drones
It seems to be a growing problem: Drones flying in places they shouldn’t and even nearly missing planes. But by buying a very cheap (€25) WiFi enabled drone myself and experimenting with it i encountered what could be a completely different type of problem: Hijacking or taking down drones remotely.
The method described below imitates the controller app to try and hijack the drone. Sometimes the real controller will disconnect and you will have full control, but most of the time the drone will just fall from the sky by basically overwhelming the legitimate controller.
The drones WiFi network isn’t that strong but from my testing with a phone it has a range of about 100m to 150m. By using a laptop with an external antenna and a low-noise environment the drone could easelly be hijacked from more than half a kilometre away.
Remember that this is for demonstration purposes only, NEVER try this on drones you do not own.
Connecting to the drone
Immediately after turning on the drone it creates a wireless access point with a SSID consisting of the name of the app you’re supposed to use to connect to it (“RC Leading”) followed by a dash and 6 random hexadecimal characters. A simple google search for “RC Leading” will make it clear for everyone in the area that this network belongs to a drone.
The fact that the WiFi network is completely unsecured is the first in a series of clear red flags. Anyone can connect to this network, and because it’s not encrypted any data send or received from the drone can be monitored. This isn’t even to biggest problem though, since security clearly wasn’t the biggest concern when designing this drone.
Let’s dig a little deeper into how the drone is controlled. Running a simple
ip route will give us the default gateway, which is the IP of the drone itself.
With the IP known we can run a couple of quick scans to see what ports are open and what type of system is running. For example,
nmap -Pn -p- 172.16.10.1 -e wlan0 will try to connect to all TCP ports and print which ones replied (see below). It turns out that there’s only 1 open TCP port (8888) and no responding UDP ports.
The next step is to see how the app is controlling the drone. In this specific case i prefer to capture the packets on the phone itself instead of routing it through a man-in-the-middle server because this means i can connect the phone directly to the drone. I used the Packet Capture app, but any app that can capture TCP and UDP packets will do.
When looking at the resulting data a few things stand out:
- 4 different TCP connections are opened to the same port we found earlier.
- The first (122 bytes) and 3rd (244 bytes) send very little data but keep their connections open the whole time.
- The 4th sends a lot of data (646 KB) and almost all of that data comes from the drone, this is probably the video stream.
- There is a UDP port we missed while scanning, which means it only replies to valid packets or never replies.
The TCP packets all start with a curious 8 byte header. The first 2 bytes,
01001001 01010100 (IT in ASCII) are always the same. Then there’s a 4 byte value that always seems to start with a hex of either 64 or 74, but the switch between them is inconsistent. Finally, the last 4 bytes seem to identify the type of packet send.
Impersonating the app
By far the most important socket seems to be the 3rd one, because the data packet it sends will “wake up” the done. The lights will stop flashing and, even better, the UDP server on port 8895 will start listening for datagrams.
This socket only sends 1 packet and gets 1 in return and they are always the same. We can easily copy the packet (packet ID 58) and send it ourselves. There we go: The first step to controlling the drone is done.
The UDP packets are a whole different story: The app sends a 8 byte datagram every 50 milliseconds with a very simple structure. It always starts with
11001100 and terminates with the same but in reverse (
Byte 2 and 3 are very similar to each other, 2 controls the horizontal axis (right or left) and 3 controls the vertical axis (forward or backwards). They range from
00 is full power left/backwards and
FF is full power right/forward. The default value is
80, in which the drone should stay in the same position.
The 4th byte is the throttle, it’s at
00 by default but can go all the way up to
FF. The drone will not power up it’s engines when the throttle is under
20 and won’t take off under
Byte 5 and 6 don’t seem to do anything, but if they do it’s not crucial to flying the drone. The final data byte is a bit tricky: It’s an XOR checksum. It’s value is calculated by performing an XOR operation on bytes 2 to 6 sequentially.
Copying this structure is very easy and combined with the TCP socket magic packet we found earlier we can now write a quick script. It only has to connect to the TCP port, send the magic packet and then send the UDP datagram every 50 milliseconds and you’re in control.
Try it yourself
If you have a compatible drone you can try this for yourself, i’ve made the code i used to control mine available on github. Never use this code to actually hijack a drone, it was written for demonstrational purposes only.