A porta já estava aberta: duas exposições críticas que não exigiram nenhum exploit

Telemetria de água e energia de dezenas de instalações. A localização em tempo real de quase mil veículos. Duas exposições críticas que não exigiram um 0-day, um exploit sofisticado nem sequer credenciais.
Durante um programa autorizado de bug bounty, encontrei duas exposições críticas dentro do mesmo provedor de conectividade IoT. A primeira permitia que qualquer pessoa na Internet lesse e escrevesse dados de telemetria associados a infraestruturas de água e energia. A segunda expunha a localização em tempo real e o histórico de trajetos de quase mil veículos pertencentes a diferentes organizações.
Não explorei uma versão vulnerável de nenhum software. Não precisei de um 0-day. Nem sequer precisei de credenciais. Os sistemas simplesmente me deixaram entrar. E ambos estavam em produção.
Um broker que confiava em todos
A primeira descoberta começou com um broker MQTT.
O MQTT é amplamente utilizado para transmitir telemetria entre sensores, medidores, controladores e outros dispositivos conectados. Em ambientes industriais, isso pode incluir desde o fluxo de água e os níveis de reservatórios até o consumo de energia elétrica. Esse broker específico estava exposto diretamente à Internet pela porta 1883, algo que já é incomum em produção. Então tentei me conectar sem usuário nem senha.
O broker respondeu: CONNACK, return code 0. Conexão aceita.
Isso, por si só, já era um problema sério. Desde o Mosquitto 2.0, o acesso anônimo não vem habilitado por padrão. Alguém havia configurado explicitamente esse broker para permiti-lo. Mas conseguir me conectar era apenas o começo.
O MQTT expõe estatísticas internas do broker por meio da árvore de tópicos $SYS. Sem me autenticar, consegui consultá-las e ver mais de dois milhões de mensagens processadas em produção, além de dezenas de mensagens retidas. Depois, assinei #, que no MQTT significa: envie tudo para mim.
Em poucos minutos, eu conseguia ver telemetria associada a dezenas de instalações. Fluxo de água, volume acumulado, níveis de reservatórios, medições de pH, tensão, corrente elétrica, consumo de energia. Os nomes dos tópicos permitiam associar os fluxos de dados a instalações individuais. Não eram dados de teste. Refletiam a operação de infraestruturas reais de água e energia em diferentes setores.
Então surgiu a pergunta mais séria: eu também conseguia escrever?
Enviei uma mensagem inofensiva para um tópico criado especificamente para o teste autorizado. PUBLISH rc=0. Aceita. Também não havia ACLs impedindo que um cliente anônimo publicasse em outros tópicos. Junto com o cliente, validamos que a telemetria pertencia a instalações realmente em operação e que era possível realizar escritas anônimas no mesmo ambiente.
Nesse momento, a descoberta deixou de ser apenas uma exposição de informações. O sistema estava disposto a confiar em dados provenientes de uma fonte não autenticada na Internet.
Uma descoberta técnica pode parecer muito diferente quando traduzida para um cenário real. Imagine um atacante publicando um valor de pH aparentemente normal enquanto a medição real está fora da faixa esperada. O dashboard continua mostrando um valor que parece normal, enquanto a condição real não é. Ou imagine alguém coletando, ao longo do tempo, informações sobre o consumo de água e energia, padrões que revelam quando uma instalação opera, quando a produção diminui e quando ela para. Dependendo de como essa telemetria alimenta outros sistemas, a manipulação desses valores também poderia interferir no monitoramento operacional ou em processos que dependem dessas medições.
Nenhum desses cenários começa com a exploração de uma vulnerabilidade de software. Eles começam com uma conexão a um serviço que nunca deveria ter confiado em um cliente anônimo na Internet.
Quase mil veículos em um mapa
A segunda descoberta era tecnicamente muito diferente.
Uma aplicação de gestão de frotas incluía uma chave de um serviço de busca de terceiros diretamente em seu JavaScript público. Ter uma chave no frontend não é automaticamente uma vulnerabilidade. Esses serviços podem usar chaves restritas, projetadas especificamente para funcionar no navegador. O problema era o que essa chave específica tinha permissão para acessar.
Ela permitia listar índices que nunca deveriam estar disponíveis para um cliente público. Um índice de usuários com aproximadamente 180 registros. Um índice de dispositivos com aproximadamente 880. Um índice de eventos com mais de 800 mil.
Usando a mesma chave, consultei o índice de dispositivos. A resposta continha quase mil veículos pertencentes a dezenas de organizações. Para cada um deles, os dados disponíveis incluíam latitude e longitude, velocidade, IMEI, identificador do SIM, organização e eventos históricos. Não havia isolamento entre tenants nessa camada. A credencial de frontend de um cliente podia acessar dados pertencentes a organizações completamente diferentes.
E, como o índice de eventos continha centenas de milhares de registros históricos, não era possível apenas saber onde um veículo estava em determinado momento. Também era possível reconstruir por onde ele havia passado.
Os índices expostos também continham informações pessoais e, em alguns casos, seeds de autenticação de segundo fator armazenadas em texto simples.
Novamente, não houve nenhum exploit complexo. A credencial já era enviada ao navegador de cada visitante. Ela simplesmente tinha muito mais permissões do que deveria.
Coordenadas em uma resposta de API podem parecer apenas mais um dado. Quando essas coordenadas são conectadas ao longo do tempo, o cenário muda. Uma localização em tempo real mostra onde um ativo está naquele momento. O histórico de localizações revela rotas e rotinas. Padrões recorrentes podem expor como uma organização opera. No nível individual, os dados de localização também podem revelar informações sobre as pessoas que utilizam esses veículos. O problema técnico era uma credencial com permissões excessivas. A exposição real era muito mais ampla: informações operacionais de várias organizações acessíveis por meio de uma credencial incluída em um JavaScript público.
O problema por trás dos dois problemas
Um broker MQTT e um serviço de busca utilizado por uma plataforma de gestão de frotas não têm muito em comum do ponto de vista técnico. Mas o problema de segurança por trás de ambos era muito parecido.
Nos dois casos, um serviço tinha uma exposição maior do que o previsto. As permissões eram mais amplas do que o necessário, os limites de confiança não estavam devidamente definidos e o resultado estava acessível pela Internet. Nenhuma das descobertas dependia de um CVE sem correção ou de uma vulnerabilidade desconhecida no software. Tudo estava funcionando. O problema era que funcionava com base em premissas equivocadas sobre quem deveria ter acesso a quê.
E essa diferença importa mais do que pode parecer.
As equipes de segurança dedicam muito tempo a acompanhar CVEs, aplicar patches e responder a vulnerabilidades recém-divulgadas. Tudo isso é necessário. Mas nem toda exposição crítica tem um CVE associado. Às vezes, o software está totalmente atualizado e funciona exatamente como foi configurado. O problema é a configuração.
As vulnerabilidades que ninguém precisa explorar
As duas descobertas começaram com algo simples: observar como um sistema se comunicava e me perguntar o que ele permitiria que um usuário externo fizesse.
Isso faz parte do que torna esse tipo de exposição interessante do ponto de vista de um pentester. Nem sempre existe uma função vulnerável esperando para ser explorada. Às vezes, o trabalho consiste em entender a arquitetura, identificar onde a confiança foi depositada de forma inadequada e testar as premissas por trás dela.
Todos os testes descritos aqui foram realizados com autorização. Atacantes não têm essa restrição.
Por isso, depois de encontrar exposições como essas, ficam algumas perguntas. Quantos serviços estão hoje expostos à Internet sem que ninguém saiba realmente o que eles permitem fazer? Quantas credenciais acumularam permissões que ninguém se lembra de ter concedido? Quantos sistemas confiam nos dados simplesmente porque eles chegaram pelo protocolo esperado, sem verificar quem os enviou?
Costumamos pensar em um ataque cibernético como alguém tentando encontrar uma forma de atravessar uma porta trancada. Nesses dois casos, não havia nenhuma fechadura para quebrar.
A porta já estava aberta.
Todos os testes descritos neste artigo foram realizados como parte de um programa autorizado de bug bounty e reportados pelos canais apropriados. Hosts, credenciais, organizações, identificadores e volumes exatos foram ocultados ou modificados para proteger as partes afetadas.
Por Matías Barrios, Sr. Pentest Operations Specialist na Strike



