
Uma coleção de vulnerabilidades e exploits contra GCS modernos
Vetores de ataque, vulnerabilidades e exploits de Estação de Controle em Solo para Drones
As frotas de drones hoje consistem em um operador pilotando dezenas ou centenas de drones a partir de uma única estação em solo. Isso torna a estação de controle em solo um alvo valioso para adversários. É onde o piloto geralmente está localizado, frequentemente armazena dados de missão e é um vetor privilegiado para movimento lateral em redes UxS e outros drones em uma frota.
A maior parte da pesquisa de segurança de drones tem se concentrado em atacar o drone. A pesquisa Infected Drone adota uma abordagem alternativa e destaca como um único drone comprometido pode atacar estações em solo que se conectam a ele. Como a maioria dos softwares de controle em solo confia em tudo que o drone envia, há uma falta de autenticação, validação e sanitização, permitindo que dados de um drone comprometido levem a CRUD de arquivos, execução de código ou uma falha na máquina do operador.
Este repositório documenta vulnerabilidades em softwares de estação de controle em solo e fornece código de prova de conceito funcional para elas. É publicado apenas para fins educacionais e para que operadores entendam sua exposição e para que mantenedores possam reproduzir e corrigir esses problemas.
Execute os PoCs apenas contra sistemas que você possui ou tem permissão escrita para testar. Cada um deles é escrito para um ambiente de teste: os payloads são marcadores benignos, e nada aqui é empacotado para uso contra a aeronave ou estação em solo de outra pessoa. Usar este material contra sistemas que você não controla é provavelmente ilegal onde quer que você esteja.
A seção Reprodução de cada achado declara o que ele precisa e o que ele faz. Leia antes de executar qualquer coisa.
Legenda:
Classe de entrega é o que o atacante precisa fazer no link, e isso decide quais vetores funcionam. Achados do tipo Push precisam apenas que um frame chegue à GCS, então qualquer vetor com capacidade de injeção é suficiente. Achados do tipo Handshake e request/response precisam que o atacante seja, ou controle totalmente, o par conversacional, o que favorece um periférico no barramento, um companion comprometido, a cadeia de suprimentos ou um MITM completo.
A coluna Fix vincula o pull request upstream onde um foi submetido. Dez dos quinze achados vêm com um patch registrado contra o próprio repositório do fornecedor.
A matriz pontua sete colunas por achado: os cinco vetores abaixo, mais os dois modos de rádio SiK (telemetria RF), que recebem seu próprio destaque abaixo dada a nuance de injeção vs MITM.
Controlador de voo infectado, conexão serial ou cadeia de suprimentos. Um atacante local ou um controlador de voo malicioso é fisicamente conectado ao host da GCS ou ao rádio. O veículo ou firmware é algo que o operador não construiu: uma unidade de demonstração, aluguel, airframe apreendido ou aeronave de segunda mão, cujo firmware é implantado para emitir MAVLink hostil no momento em que uma GCS se conecta. A própria GCS do operador é a vítima; o "veículo" era hostil antes mesmo de ser ligado. Aplica-se a todos os achados, e é a forma mais limpa de entregar exploits de handshake em tempo de conexão. Isso se estende a analistas forenses que podem se conectar diretamente a ou extrair dados de um veículo infectado. Esses artefatos, se não forem tratados adequadamente, podem infectar ou se espalhar para o computador e a rede do analista.
Periférico MAVLink malicioso / falsificado no próprio barramento do veículo. Uma câmera de terceiros, gimbal, ADSB-in, telêmetro ou qualquer dispositivo que fala MAVLink e é ele próprio o atacante. É um participante legítimo no link emitindo frames hostis. Uma "câmera inteligente" falsificada anunciando mensagens envenenadas está fazendo exatamente o que uma real faz, apenas com valores hostis.
Companion computer comprometido a bordo (Raspberry Pi / Jetson executando mavlink-router / MAVProxy). Uma vez comprometido, ele se torna o endpoint do veículo, com acesso bidirecional total ao link e visibilidade de seu estado ao vivo. Ele pode responder qualquer handshake e emitir qualquer frame push, o que o torna viável para todos os achados neste conjunto.
Bridge de telemetria WiFi / UDP (ESP8266 / ESP32 "wifi telemetry"). Qualquer um no ponto de acesso ou LAN pode injetar dados MAVLink. Isso reduz o custo dos vetores de injeção a quase zero e, para um atacante que também pode interceptar (ARP/AP MITM), permite controle total de handshake também.
Relay TCP / cloud (SITL, mavlink-router TCP, mavp2p, GCS em nuvem 4G/LTE como serviços comerciais de UAV-cloud). MITM no relay, ou qualquer um que consiga alcançar a porta TCP exposta, pode reescrever o stream. Links de nuvem/4G ampliam o raio de impacto geográfico enormemente e frequentemente carecem de autenticação mútua.
O caminho de telemetria RF real dominante para aeronaves ArduPilot/PX4 de hobby e prosumer é um par de rádios SiK, uma bridge serial transparente que não analisa nem valida MAVLink, então oferece à GCS zero proteção contra conteúdo hostil. Um módulo SiK rogue se junta ou faz bridge de um link existente usando sikw00f. Dois modos de ataque, com confiabilidade muito diferente:
STATUSTEXT, PARAM_VALUE,
CAMERA_INFORMATION, etc.), sem necessidade de resposta. Não confiável para protocolos
de handshake (MAVFTP, download de param/log) já que o injetor deve vencer uma corrida
de tempo de antena e corresponder a uma sessão/sequência que ele não controla.Nota: a criptografia SiK (AES-128, onde suportada) vem desativada por padrão com uma chave compartilhada estática.
| ID | Produto | Sev | CWE | Classe de sink | Classe de entrega | FC infectado / cadeia de suprimentos? | Periférico malicioso no barramento? | Companion comprometido? | Injeção WiFi/UDP? | MITM TCP/cloud? | Injeção SiKW00F? | SiK full-MITM? | Fix |
|---|
| QGC-01 | QGroundControl | 🟠 HIGH | 22/73/170 | CAMERA_INFORMATION → escrita path-traversal (escrita zero-click ao conectar) | push (CAMERA_INFORMATION) + conteúdo via cam_definition_uri | ✅ | ✅ mais natural (câmera) | ✅ | ✅ | ✅ | ✅ trigger é push; campos de nome inline | ✅ | PR #15083 |
| QGC-02 | QGroundControl | 🔴 CRITICAL | 22/73/494/918 | COMPONENT_METADATA uri → escrita arbitrária de arquivo → RCE zero-click ao conectar | request/response (busca de URI via IP) | ✅ | ✅ emite metadata uri | ✅ | ✅ para trigger | ✅ | ⚠️ trigger push sim; busca é via IP | ✅ | PR #15084 |
| QGC-03 | QGroundControl | 🟠 HIGH | 22/770 | Listagem FTP → escrita traversal + preenchimento de disco com offset | handshake (listagem/download MAVFTP) | ✅ | ✅ par responde FTP | ✅ | ⚠️ injeção sim, handshake próprio mais difícil | ✅ | ⚠️ sessão/seq instável | ✅ bridge serve listagem | PR #15085 |
| QGC-04 | QGroundControl | 🟡 MED | 191/125 | Parser DataFlash .bin leitura OOB + underflow | handshake (download de log de .bin malicioso) | ✅ | ✅ par serve DataFlash | ✅ | ⚠️ | ✅ | ⚠️ deve servir chunks de log | ✅ bridge alimenta .bin | PR #15086 |
| MP-01 | Mission Planner | 🟠 HIGH | 22→94 | Traversal MAVFTP → RCE via plugin-loader | handshake (MAVFTP req/ack → RCE) | ✅ | ✅ par responde listagem | ✅ controle total do link | ⚠️ injeção fácil, mas precisa controlar handshake | ✅ reescrever no relay | ⚠️ deve vencer corrida + corresponder sessão/seq | ✅ bridge controla conversa FTP | PR #3774 |
| MP-02 | Mission Planner | 🟠 HIGH | 94/78 | gst:// → gst_parse_launch (leitura/escrita de arquivo + exfiltração) | push (VIDEO_STREAM_INFORMATION → gst) | ✅ | ✅ câmera anuncia uri | ✅ | ✅ datagrama UDP | ✅ | ✅ frame de stream único | ✅ trivialmente | PR #3775 |
| MP-03 | Mission Planner | 🟠 HIGH | 74/601 | Markup STATUSTEXT → Process.Start | push (STATUSTEXT → ShellExecute) | ✅ | ✅ qualquer componente emite | ✅ | ✅ | ✅ | ✅ texto fire-and-forget | ✅ | PR #3776 |
| MP-04 | Mission Planner | 🟡 MED | 248/20/1050 | RALLY_TOTAL/FENCE_TOTAL → int.Parse não validado + O(n²) na thread da UI (zero-click ao conectar) | push (PARAM_VALUE, automático pós-conexão) | ✅ | ✅ emite PARAM_VALUE | ✅ | ✅ | ✅ | ⚠️ deve inserir o param no dict do MP | ✅ | PR #3777 |
| MAVSDK-01 | MAVSDK | 🟡 MED | 918/749 | SSRF curl de component-metadata + file:// (sem allowlist de protocolo) | request/response (busca de COMPONENT_METADATA.uri via IP) | ✅ | ✅ emite metadata uri | ✅ | ✅ para trigger | ✅ | ⚠️ trigger push sim; busca via IP | ✅ | nenhum |
| MAVSDK-02 | MAVSDK | 🟠 HIGH | 22/73/918 | SSRF cam-definition + traversal mftp:// → destruição zero-click de um arquivo fora do sandbox | push (CAMERA_INFORMATION.cam_definition_uri, automático) | ✅ | ✅ mais natural (câmera) | ✅ | ✅ | ✅ | ✅ push consumido automaticamente | ✅ | PR #3073 |
| MAVSDK-03 | MAVSDK | 🟠 HIGH | 409/400/770/459 | cam-definition .xz ou COMPONENT_METADATA → descompressão ilimitada → esgotamento persistente de disco | push (CAMERA_INFORMATION.cam_definition_uri, automático) — um HEARTBEAT simples inicia | ✅ | ✅ mais natural (câmera) | ✅ | ✅ | ✅ | ✅ push consumido automaticamente; ~50 s de tempo de antena a 57,6 kbps por 2 GiB | ✅ | PR #3074 |
| MAVPROXY-01 | MAVProxy | 🟠 HIGH | 502 | pickle.loads do asterix via UDP → RCE | canal lateral IP (UDP, NÃO o link RF MAVLink) | ❌ não no link MAVLink | ❌ socket UDP separado | ⚠️ apenas se conseguir alcançar :45454 | ✅ UDP para host:45454 | ❌ socket UDP próprio, não relay | ❌ não no link RF/MAVLink | ❌ não no link RF/MAVLink | corrigido upstream por #1728, não lançado |
| MAVROS-01 | mavros | 🟡 MED | 345/770 | PARAM_VALUE → /parameter_events global forjado + mapa sem limite | push/stream (injetar PARAM_VALUE, sem handshake) | ✅ | ✅ emite PARAM_VALUE | ✅ | ✅ flood UDP | ✅ | ✅ flood PARAM_VALUE | ✅ | nenhum |
| MAVROS-02 | mavros | 🟠 HIGH | 125/617/248 | FTP write-ack → std::advance ilimitado → divulgação de heap + aborto do processo | handshake (envenenar resposta FTP → crash) | ✅ | ✅ par envia FTP ruim | ✅ | ⚠️ | ✅ | ⚠️ deve inserir resposta malformada | ✅ bridge injeta resposta ruim | nenhum |
| DRONEKIT-01 | DroneKit | ⚪ INFO | 20 | transferência de fronteira de confiança (param_id / STATUSTEXT) | push (telemetria → callbacks do app; transferência por design) | ✅ | ✅ qualquer componente | ✅ | ✅ | ✅ | ✅ qualquer frame push alcança o callback | ✅ | n/a |