// HackTheBox  ·  writeup

AoTR 4: A Drone in the Snow

HackTheBox Easy Pythonpymavlink
DFIR

Scenario

In this Sherlock, your task is to analyze the drone’s mission file and flight telemetry logs. By correlating waypoints, timestamps, GPS tracks, and system events, you must extract concrete facts about the route, behavior at key points, and the final impact.

The scenario portrayed in this challenge is entirely fictional and created solely for educational and entertainment purposes. Any resemblance to actual persons, living or dead, organizations, or real events is purely coincidental and unintentional. All characters, scenarios, and data presented are products of imagination.

Executive Summary

A drone flew a pre-planned spline route around a hilltop landmark in Budapest, with a single 30 second hold, then crossed the Danube by a bridge toward the other half of the city. The flight log shows it disarmed in the air, lost control and hit the ground at about 13 m/s roughly ten and a half minutes after takeoff. Comparing the mission plan against the telemetry gives the planned route, the crash position and the launch point. The launch point is the useful intelligence: it is where the operator was standing.

Artifacts

Timestamp note: TimeUS is microseconds since boot, not wall-clock time. Durations are differences between two TimeUS values. The flight-time answer needs the hh:mm:ss.sss form, and coordinate answers need exactly seven decimals, trailing zeros included.

Flight Plan Analysis

Q1 — How many total mission items are defined in the flight plan, including Home, Takeoff, and Land commands?

The plan file lists 48 items under mission.items, and the home position is stored separately in plannedHomePosition. The flight controller counts Home as item 0, so the log’s CMD messages report CTot=49. That total, with Home included, is the number the question asks for.

import json;p=json.load(open('evidence/AOTR_Winter_Blackout.plan'));items=p['mission']['items'];print(len(items))
m=mavutil.mavlink_connection('evidence/log.bin');x=m.recv_match(type='CMD');print(x)

Gotcha: The plan JSON alone gives 48. The question says to include Home, which the controller counts as the first mission command.

Click flag to reveal 49
Q2 — How many spline waypoints are in the mission?

Count plan items whose command is 82 (MAV_CMD_NAV_SPLINE_WAYPOINT). They are contiguous, mission items 2 through 47, after the takeoff and before the landing.

import json;p=json.load(open('evidence/AOTR_Winter_Blackout.plan'));items=p['mission']['items'];print(sum(i['command']==82 for i in items))
Click to reveal answer 46
Q3 — Which landmark/building does the drone fly around during the planned route?

Plot the spline waypoints. The route is a loop tight around a hilltop on the Buda side of the Danube, centred near 47.4867, 19.0448. That position is Gellért Hill and the fortress on its summit. This answer was reasoned from the coordinates rather than read from a label in either artifact, since the plan carries no place names.

import json;p=json.load(open('evidence/AOTR_Winter_Blackout.plan'));items=p['mission']['items'];print([(i['params'][4],i['params'][5]) for i in items])

Hint: Drop the waypoint list into any map and look at what the loop encircles. Format mask is a single word.

Click flag to reveal Citadella
Q4 — At which mission item did the drone have a planned hold/loiter?

Scan the plan for an item with a non-zero hold time in params[0]. Only one item has it, item 18, a waypoint with a 30 second dwell in the middle of the spline run.

import json;p=json.load(open('evidence/AOTR_Winter_Blackout.plan'));items=p['mission']['items'];print([(n,i['command'],i['params'][0]) for n,i in enumerate(items,1) if i['params'][0]])
Click to reveal answer 18
Q5 — How long was the planned hold time at that mission item (seconds)?

Same item as Q4. Its first parameter, the hold time, is 30.

import json;p=json.load(open('evidence/AOTR_Winter_Blackout.plan'));items=p['mission']['items'];print(items[17]['params'])
Click flag to reveal 30
Q6 — Which bridge is the drone planned to pass by while crossing the Danube in order to reach the other part of the city? (English name)

Spline items 30 to 31 are the two waypoints that straddle the river, at about 47.491 N. At that latitude the crossing is the bridge between Buda and Pest just north of Gellért Hill, which is Elisabeth Bridge. Like Q3 this was reasoned from the coordinates, not read from an artifact.

import json;p=json.load(open('evidence/AOTR_Winter_Blackout.plan'));items=p['mission']['items'];print([(n,i['params'][4],i['params'][5]) for n,i in enumerate(items,1) if 29<=n<=32])
Click to reveal answer Elisabeth Bridge

Flight Telemetry Analysis

Q7 — What is the total flight time from takeoff to crash?

The log’s MSG text Mission: 1 Takeoff marks the start of the flight at TimeUS 48893768. The crash is the SIM Hit ground message from Q8 at 687813098. The difference is 638919330 µs, which is 10 minutes 38.919 seconds. This was derived from those two log events rather than read from a single field, and HTB accepted it.

m=mavutil.mavlink_connection('evidence/log.bin');[print(x.TimeUS,x.Message) for x in iter(lambda:m.recv_match(type='MSG'),None)]
print((687813098-48893768)/1e6)
Click flag to reveal 00:10:38.919
Q8 — What is the exact log timestamp of the crash event (TimeUS)?

Dump every MSG record. The last one is SIM Hit ground at 12.93254 m/s, and its TimeUS is the crash timestamp. The drone had been disarmed in flight about 676 s into the log and fell from there.

m=mavutil.mavlink_connection('evidence/log.bin');[print(x) for x in iter(lambda:m.recv_match(type='MSG'),None)]
Click to reveal answer 687813098
Q9 — What are the coordinates where the drone crashed (lat, lon)?

Take the last GPS sample before the impact message. It sits at TimeUS 687783943, about 30 ms ahead of the crash event. Filter on Status>=3 so only real fixes count.

m=mavutil.mavlink_connection('evidence/log.bin');[print(x.TimeUS,x.Lat,x.Lng) for x in iter(lambda:m.recv_match(type='GPS'),None) if 687600000<x.TimeUS<688000000]
Click flag to reveal 47.4903055, 19.0460476
Q10 — What was the ground impact speed reported at the moment of crash (m/s)?

The speed is in the same SIM Hit ground message as Q8, so there is nothing to compute.

m=mavutil.mavlink_connection('evidence/log.bin');print([x.Message for x in iter(lambda:m.recv_match(type='MSG'),None) if 'Hit ground' in x.Message])
Click to reveal answer 12.93254
Q11 — What was the maximum GPS altitude reached during the flight (meters)?

Take the maximum of the Alt field across GPS records with a 3D fix.

g=[x for x in iter(lambda:m.recv_match(type='GPS'),None) if x.Status>=3];print(max(x.Alt for x in g))
Click flag to reveal 377.07
Q12 — What was the fastest GPS ground speed recorded (m/s)?

Same GPS set as Q11, maximum of the Spd field.

print(max(x.Spd for x in g))
Click to reveal answer 10.24
Q13 — What are the coordinates where the drone took off from (lat, lon), and therefore a good location for the police raid to catch the gang member?

The first GPS fix and the home entry (CMD 0) agree on the launch point. Print the values with seven decimals.

print('%.7f, %.7f'%(g[0].Lat,g[0].Lng))

Gotcha: The longitude is 19.01916 with its trailing zeros dropped. The mask needs seven decimals, so pad it to 19.0191600.

Click flag to reveal 47.4819399, 19.0191600

Attack Summary

PhaseAction
PlanningMission of 48 items uploaded: takeoff, 46 spline waypoints looping a hilltop landmark, one 30 second hold at item 18, then land
LaunchTakeoff from a point on the Pest side, recorded as the home position
FlightRoute flown across the Danube past Elisabeth Bridge, reaching 377.07 m altitude and 10.24 m/s ground speed
FailureVehicle disarmed in flight at about 676 s into the log
ImpactGround contact at 12.93254 m/s, 10 min 38.919 s after takeoff

IOCs

TypeValue
Launch coordinates47.4819399, 19.0191600
Crash coordinates47.4903055, 19.0460476
Mission fileAOTR_Winter_Blackout.plan
Flight loglog.bin

Defender Takeaways

The takeoff point is the strongest lead in a recovered drone. A flight log records the home position and the first GPS fix, which place the operator at launch. Recovering the log from a downed drone should be a first step for any response aimed at the pilot.

Plan and log answer different questions. The plan shows intent (route, hold, landmark); the log shows what happened (disarm, crash, speed). Reading both and reconciling item counts, such as CTot including Home, avoids off-by-one errors.

Time in dataflash logs is relative. TimeUS is time since boot, so durations come from event differences, and pairing a GPS fix with an event needs the nearest sample, not an exact match.

Conclusion

The drone was disarmed in flight and fell about ten and a half minutes into its route, but its log kept both the crash site and the launch point. That launch position is where the operator can be found.