
Una colección de vulnerabilidades y exploits contra GCS modernos
Vectores de ataque, vulnerabilidades y exploits de Drone a Estación de Control en Tierra
Las flotas de drones hoy en día son un operador pilotando docenas o cientos de drones desde una única estación en tierra. Esto convierte a la estación de control en tierra en un objetivo valioso para los adversarios. Es donde normalmente se ubica el piloto, a menudo almacena datos de la misión, y es un vector principal para el movimiento lateral a través de redes UxS y otros drones en una flota.
La mayor parte de la investigación en seguridad de drones se ha centrado en atacar al dron. La investigación de Infected Drone adopta un enfoque alternativo y resalta cómo un único dron comprometido puede atacar estaciones en tierra que se conectan a él. Debido a que la mayoría del software de control en tierra confía en todo lo que el dron le envía, existe una falta de autenticación, validación y sanitización, lo que permite que los datos de un dron comprometido conduzcan a CRUD de archivos, ejecución de código o un crash en la máquina del operador.
Este repositorio documenta vulnerabilidades en el software de estaciones de control en tierra e incluye código de prueba de concepto funcional para ellas. Se publica únicamente con fines educativos y para que los operadores comprendan su exposición y los mantenedores puedan reproducir y corregir estos problemas.
Ejecute los PoC solo contra sistemas que posea o para los que tenga permiso escrito de prueba. Cada uno de ellos está escrito para un banco de pruebas: los payloads son marcadores benignos, y nada aquí está empaquetado para su uso contra la aeronave o estación en tierra de otra persona. Usar este material contra sistemas que no controla es probablemente ilegal dondequiera que se encuentre.
La sección de Reproducción de cada hallazgo indica qué necesita y qué hace. Léala antes de ejecutar cualquier cosa.
Leyenda:
La clase de entrega es lo que el atacante tiene que hacer en el enlace, y decide qué vectores funcionan. Los hallazgos de tipo Push solo necesitan que una trama llegue a la GCS, por lo que cualquier vector con capacidad de inyección es suficiente. Los hallazgos de tipo Handshake y request/response necesitan que el atacante sea, o controle completamente, al par conversacional, lo que favorece a un periférico en el bus, un companion comprometido, la cadena de suministro, o un MITM completo.
La columna Fix enlaza el pull request upstream donde se ha enviado uno. Diez de los quince hallazgos incluyen un parche presentado contra el propio repositorio del proveedor.
La matriz puntúa siete columnas por hallazgo: los cinco vectores a continuación, más los dos modos de radio SiK (telemetría RF), que reciben su propia mención a continuación dada la matiz de inyección vs MITM.
Controlador de vuelo infectado, conexión serial, o cadena de suministro. Un atacante local o un controlador de vuelo malicioso se conecta físicamente al host de la GCS o a la radio. El vehículo o firmware es algo que el operador no construyó: una unidad de demostración, alquiler, aeronave incautada, o nave de segunda mano, cuyo firmware está implantado para emitir MAVLink hostil en el momento en que una GCS se conecta. La propia GCS del operador es la víctima; el "vehículo" era hostil antes de siquiera encenderse. Aplica a todos los hallazgos, y es la forma más limpia de entregar exploits de handshake en tiempo de conexión. Esto se extiende a los analistas forenses que pueden conectarse directamente a o extraer datos de un vehículo infectado. Esos artefactos, si no se manejan adecuadamente, podrían infectar o propagarse a la computadora y red del analista.
Periférico MAVLink malicioso / falsificado en el propio bus del vehículo. Una cámara de terceros, gimbal, ADSB-in, telémetro, o cualquier dispositivo que hable MAVLink y sea él mismo el atacante. Es un participante legítimo en el enlace emitiendo tramas hostiles. Una "cámara inteligente" falsificada que anuncia mensajes envenenados está haciendo exactamente lo que hace una real, solo que con valores hostiles.
Companion computer comprometido a bordo (Raspberry Pi / Jetson ejecutando mavlink-router / MAVProxy). Una vez comprometido se convierte en el endpoint del vehículo, con acceso bidireccional completo al enlace y visibilidad de su estado en vivo. Puede responder cualquier handshake y emitir cualquier trama push, lo que lo hace viable para cada hallazgo de este conjunto.
Bridge de telemetría WiFi / UDP (ESP8266 / ESP32 "wifi telemetry"). Cualquiera en el punto de acceso o LAN puede inyectar datos MAVLink. Esto reduce el costo de los vectores de inyección a casi cero y, para un atacante que también puede interceptar (ARP/AP MITM), habilita también el control total del handshake.
Relay TCP / cloud (SITL, mavlink-router TCP, mavp2p, GCS en la nube 4G/LTE como servicios comerciales de UAV-cloud). MITM en el relay, o cualquiera que pueda alcanzar el puerto TCP expuesto, puede reescribir el stream. Los enlaces cloud/4G amplían enormemente el radio de impacto geográfico y con frecuencia carecen de autenticación mutua.
La ruta de telemetría RF real dominante para naves de hobby y prosumer de ArduPilot/PX4 es un par de radios SiK, un bridge serial transparente que no parsea ni valida MAVLink, por lo que no ofrece a la GCS ninguna protección contra contenido hostil. Un módulo SiK rogue se une o hace bridge a un enlace existente usando sikw00f. Dos modos de ataque, con muy diferente confiabilidad:
STATUSTEXT, PARAM_VALUE,
CAMERA_INFORMATION, etc.), sin necesidad de respuesta. Poco confiable para protocolos
de handshake (MAVFTP, descarga de param/log) ya que el inyector debe ganar una carrera
de tiempo de aire y coincidir con una sesión/secuencia que no controla.Nota: el cifrado SiK (AES-128, donde es compatible) se entrega desactivado por defecto con una clave compartida estática.
| ID | Producto | Sev | CWE | Clase de sink | Clase de entrega | ¿FC infectado / cadena de suministro? | ¿Periférico malicioso en el bus? | ¿Companion comprometido? | ¿Inyección WiFi/UDP? | ¿MITM TCP/cloud? | ¿Inyección SiKW00F? | ¿SiK full-MITM? | Fix |
|---|
| QGC-01 | QGroundControl | 🟠 HIGH | 22/73/170 | CAMERA_INFORMATION → escritura path-traversal (escritura zero-click al conectar) | push (CAMERA_INFORMATION) + contenido vía cam_definition_uri | ✅ | ✅ lo más natural (cámara) | ✅ | ✅ | ✅ | ✅ el trigger es push; campos de nombre inline | ✅ | PR #15083 |
| QGC-02 | QGroundControl | 🔴 CRITICAL | 22/73/494/918 | COMPONENT_METADATA uri → escritura arbitraria de archivos → RCE zero-click al conectar | request/response (fetch de URI sobre IP) | ✅ | ✅ emite metadata uri | ✅ | ✅ para el trigger | ✅ | ⚠️ trigger push sí; el fetch es sobre IP | ✅ | PR #15084 |
| QGC-03 | QGroundControl | 🟠 HIGH | 22/770 | Listado FTP → escritura traversal + llenado de disco por offset | handshake (listado/descarga MAVFTP) | ✅ | ✅ el par responde FTP | ✅ | ⚠️ inyección sí, handshake propio más difícil | ✅ | ⚠️ sesión/seq con condiciones de carrera | ✅ el bridge sirve el listado | PR #15085 |
| QGC-04 | QGroundControl | 🟡 MED | 191/125 | Parser de DataFlash .bin OOB read + underflow | handshake (descarga de log de un .bin malicioso) | ✅ | ✅ el par sirve DataFlash | ✅ | ⚠️ | ✅ | ⚠️ debe servir chunks de log | ✅ el bridge alimenta el .bin | PR #15086 |
| MP-01 | Mission Planner | 🟠 HIGH | 22→94 | Traversal MAVFTP → RCE del cargador de plugins | handshake (MAVFTP req/ack → RCE) | ✅ | ✅ el par responde al listado | ✅ control total del enlace | ⚠️ inyección fácil, pero hay que poseer el handshake | ✅ reescribir en el relay | ⚠️ debe ganar la carrera + coincidir sesión/seq | ✅ el bridge posee la conversación FTP | PR #3774 |
| MP-02 | Mission Planner | 🟠 HIGH | 94/78 | gst:// → gst_parse_launch (lectura/escritura de archivos + exfiltración) | push (VIDEO_STREAM_INFORMATION → gst) | ✅ | ✅ la cámara anuncia uri | ✅ | ✅ datagrama UDP | ✅ | ✅ trama de stream de un solo disparo | ✅ trivialmente | PR #3775 |
| MP-03 | Mission Planner | 🟠 HIGH | 74/601 | Markup de STATUSTEXT → Process.Start | push (STATUSTEXT → ShellExecute) | ✅ | ✅ cualquier componente emite | ✅ | ✅ | ✅ | ✅ texto fire-and-forget | ✅ | PR #3776 |
| MP-04 | Mission Planner | 🟡 MED | 248/20/1050 | RALLY_TOTAL/FENCE_TOTAL → int.Parse sin validar + O(n²) en el hilo de UI (zero-click al conectar) | push (PARAM_VALUE, automático post-conexión) | ✅ | ✅ emite PARAM_VALUE | ✅ | ✅ | ✅ | ⚠️ debe aterrizar el param en el dict de MP | ✅ | PR #3777 |
| MAVSDK-01 | MAVSDK | 🟡 MED | 918/749 | SSRF de curl de component-metadata + file:// (sin allowlist de protocolo) | request/response (fetch de COMPONENT_METADATA.uri sobre IP) | ✅ | ✅ emite metadata uri | ✅ | ✅ para el trigger | ✅ | ⚠️ trigger push sí; fetch sobre IP | ✅ | ninguno |
| MAVSDK-02 | MAVSDK | 🟠 HIGH | 22/73/918 | SSRF de cam-definition + traversal mftp:// → destrucción zero-click de un archivo fuera del sandbox | push (CAMERA_INFORMATION.cam_definition_uri, automático) | ✅ | ✅ lo más natural (cámara) | ✅ | ✅ | ✅ | ✅ push consumido automáticamente | ✅ | PR #3073 |
| MAVSDK-03 | MAVSDK | 🟠 HIGH | 409/400/770/459 | cam-definition .xz o COMPONENT_METADATA → descompresión sin límites → agotamiento persistente de disco | push (CAMERA_INFORMATION.cam_definition_uri, automático) — un simple HEARTBEAT lo inicia | ✅ | ✅ lo más natural (cámara) | ✅ | ✅ | ✅ | ✅ push consumido automáticamente; ~50 s de tiempo de aire a 57.6 kbps por cada 2 GiB | ✅ | PR #3074 |
| MAVPROXY-01 | MAVProxy | 🟠 HIGH | 502 | pickle.loads de asterix sobre UDP → RCE | canal lateral IP (UDP, NO el enlace RF de MAVLink) | ❌ no en el enlace MAVLink | ❌ socket UDP separado | ⚠️ solo si puede alcanzar :45454 | ✅ UDP a host:45454 | ❌ socket UDP propio, no relay | ❌ no en el enlace RF/MAVLink | ❌ no en el enlace RF/MAVLink | corregido upstream por #1728, sin publicar |
| MAVROS-01 | mavros | 🟡 MED | 345/770 | PARAM_VALUE → /parameter_events global falsificado + mapa sin límite | push/stream (inyectar PARAM_VALUE, sin handshake) | ✅ | ✅ emite PARAM_VALUE | ✅ | ✅ flood UDP | ✅ | ✅ flood de PARAM_VALUE | ✅ | ninguno |
| MAVROS-02 | mavros | 🟠 HIGH | 125/617/248 | write-ack de FTP → std::advance sin límites → divulgación de heap + aborto del proceso | handshake (envenenar respuesta FTP → crash) | ✅ | ✅ el par envía FTP malformado | ✅ | ⚠️ | ✅ | ⚠️ debe aterrizar la respuesta malformada | ✅ el bridge inyecta respuesta malformada | ninguno |
| DRONEKIT-01 | DroneKit | ⚪ INFO | 20 | traspaso de límite de confianza (param_id / STATUSTEXT) | push (telemetría → callbacks de la app; traspaso por diseño) | ✅ | ✅ cualquier componente | ✅ | ✅ | ✅ | ✅ cualquier trama push alcanza el callback | ✅ | n/a |