
Ferramenta de avaliação de segurança Bluetooth sem dongle e sem root para fones de ouvido sem fio afetados pela cadeia de vulnerabilidades do SDK Airoha (CVE-2025-20700/20701/20702)
Version 1.0.0
Ferramenta de avaliação de segurança Bluetooth para fones de ouvido sem fio afetados pela cadeia de vulnerabilidades do SDK Airoha (CVE-2025-20700 / CVE-2025-20701 / CVE-2025-20702). Escaneia dispositivos próximos, identifica chipsets Airoha conhecidos como afetados e testa acesso GATT não autenticado e acessibilidade do protocolo RACE - inteiramente através da pilha Bluetooth do sistema operacional (BlueZ) via bleak. Nenhum dongle Bluetooth externo é necessário e root não é necessário. Os resultados são relatados em linguagem simples junto com os detalhes técnicos, para que você possa agir sem conhecimento profundo de Bluetooth.
Esta ferramenta é para avaliar dispositivos que você possui ou para os quais tem autorização explícita para testar. Os testes GATT e RACE são operações ativas: eles conectam e enviam comandos ao dispositivo alvo. Não execute --gatt, --race, --firmware, --bd-address, --assess, --baseline, --check-drift ou --memory-read contra um dispositivo que não seja seu ou para o qual você não tenha permissão para testar. --scan é passivo e apenas escuta anúncios já transmitidos publicamente, portanto é seguro executar contra qualquer coisa ao alcance.
--memory-read vai um passo além das outras sondas ativas: ele recupera uma página real, somente leitura (256 bytes) do conteúdo real da flash do dispositivo, em um endereço fixo, como uma confirmação definitiva do CVE-2025-20702 quando a sonda --race (apenas de acessibilidade) não obtém resposta. É somente leitura (leituras de flash não apresentam risco de desgaste ou brick, ao contrário de comandos de gravação/apagamento/FOTA, que esta ferramenta nunca envia), opt-in, e requer sua própria confirmação separada além do prompt de propriedade padrão, descrevendo exatamente o que faz antes de executar qualquer coisa.
Sondar um dispositivo próximo arbitrário não é apenas uma questão de política - pode ter efeitos colaterais reais. --gatt tenta uma leitura ou inscrição de notificação em cada característica que encontra, e alguns dispositivos de consumo expõem serviços do tipo provisionamento (ex.: serviço Google Fast Pair) que reagem iniciando um handshake de emparelhamento real no dispositivo alvo, independentemente de qualquer coisa que esta ferramenta solicite explicitamente. Uma característica que requer criptografia pode desencadear a mesma coisa até mesmo contra seu próprio dispositivo, já que o BlueZ pode rotear silenciosamente essa solicitação de autenticação para qualquer agente que seu desktop tenha registrado (ex.: prompt de emparelhamento do KDE) - portanto, cada comando ativo também registra seu próprio agente BlueZ temporário que rejeita automaticamente qualquer solicitação desse tipo durante a sonda, para que nenhum prompt de emparelhamento possa aparecer. Cada comando ativo também ainda solicita confirmação de que o endereço alvo é seu antes de fazer qualquer coisa no rádio; passe --yes para pular o prompt para uso scriptado depois que você já confirmou que é seu dispositivo:
buds_audit.py --assess --target AA:BB:CC:DD:EE:FF --yes
--watch é passivo, como --scan - apenas escuta anúncios já transmitidos e nunca se conecta a nada, portanto não solicita confirmação.
python3 -m venv venv
venv/bin/pip install -r requirements.txt
Requer Python 3.10+ (desenvolvido contra 3.14) e um sistema Linux rodando BlueZ com um adaptador Bluetooth ligado.
Apenas Linux, e não automaticamente todo sistema Linux:
bleak tem um backend Windows, mas esta ferramenta não depende apenas do bleak - a descoberta Bluetooth Classic (core/scanner.py) e as verificações de estado de vinculação (core/gatt.py) ambos chamam diretamente bluetoothctl, uma ferramenta de linha de comando exclusiva do BlueZ que não existe no Windows. Esses caminhos de código simplesmente falhariam com 'comando não encontrado'.bluetoothctl no PATH, não apenas qualquer kernel Linux. A maioria das distribuições desktop inclui isso; uma imagem mínima ou servidor sem o pacote bluez instalado não terá isso de fábrica. Verificado sem root no BlueZ 5.86 - outras versões devem funcionar da mesma forma, já que bleak tem como alvo a API D-Bus padrão do BlueZ, mas isso não foi verificado independentemente novamente.usbipd-win, que apenas encaminha adaptadores conectados por USB. A maioria dos Bluetooth embutidos em laptops é conectada por um barramento não USB (SDIO/PCIe, junto com Wi-Fi), que usbipd-win geralmente não consegue encaminhar - portanto, isso depende inteiramente do hardware específico.Você não precisa de uma máquina Linux própria - você só precisa de Linux com acesso real a um rádio Bluetooth. Duas maneiras práticas de conseguir isso:
De qualquer forma, a regra é a mesma: a ferramenta em si não muda - ela só precisa de Linux com um adaptador Bluetooth que o BlueZ possa realmente alcançar.
Muitos fones de ouvido TWS param de anunciar (e encerram qualquer conexão ativa) após um período de inatividade para economizar energia, e alguns desligam completamente por conta própria. Se uma varredura não encontrar um dispositivo que encontrou há um minuto, ou uma sonda falhar no meio do caminho, geralmente é os fones entrando em espera, não um bug - tire-os do estojo ou pressione o botão de emparelhamento novamente e tente novamente.
Isso também afeta a estabilidade do endereço: a unidade de teste confirmada deste projeto (um Sony WF-1000XM3) manteve o mesmo endereço BLE em todos os ciclos de energia testados, o que é esperado para fones de ouvido projetados para reconexão via aplicativo complementar - eles geralmente usam um endereço BLE fixo/público em vez de um rotativo (diferente de telefones, que rotacionam endereços privados e não são um alvo adequado para esta ferramenta por esse motivo). Isso não é garantido para todos os modelos de fones, no entanto - alguns fabricantes usam endereços privados resolvíveis mesmo no modo de pré-emparelhamento/reconexão, o que apareceria como um endereço diferente após cada ciclo de energia para um scanner não pareado como esta ferramenta.
A sonda GATT (--gatt, e o estágio GATT do --assess) pode precisar de várias reconexões se o dispositivo tiver características que exigem emparelhamento - cada uma faz o BlueZ tentar (e o agente próprio desta ferramenta rejeitar) uma negociação de emparelhamento real antes de reconectar para retomar a varredura, e imprime um status de uma linha antes de cada tentativa para que uma varredura lenta não pareça travada. Quando tal inscrição é rejeitada, o BlueZ retém a intenção e a reemite em cada conexão posterior a esse dispositivo; para evitar que isso atrapalhe reconexões subsequentes, a sonda limpa o registro em cache do BlueZ para o dispositivo (equivalente a bluetoothctl remove) antes de cada reconexão, para que cada tentativa comece de um estado limpo. Com isso, varreduras repetidas consecutivas contra o dispositivo de teste confirmado retornam o mesmo resultado completo a cada vez. Uma observação anterior - a completude parecendo degradar ao longo de uma sessão de testes intensos e se recuperar após um descanso - não se repetiu desde então, e acredita-se que tenha sido o mesmo acúmulo de estado retido, e não fadiga do dispositivo.
buds_audit.py
Executá-lo sem nenhuma flag inicia um menu numerado em vez de exigir que você já saiba um endereço BLE ou qual flag faz o quê:
1) Full analysis (scan, run the full CVE audit, and save a baseline)
2) Check current state against a saved baseline
3) Scan for spoofed/impersonating devices
4) Exit
A opção 1 escaneia dispositivos próximos conhecidos como afetados e os lista para você escolher por número (em vez de digitar um endereço MAC), executa a auditoria completa de CVEs (igual a --assess, incluindo a consulta de endereço BD), e salva uma linha de base (igual a --baseline) para que execuções futuras possam detectar mudanças. Ela também faz a mesma pergunta de leitura de memória que --assess --memory-read responde através de seu prompt de confirmação - responder sim inclui a mesma leitura real de página flash RACE somente leitura descrita acima; responder não apenas executa a auditoria sem ela, não cancela toda a análise. A opção 2 lista dispositivos que você já estabeleceu linha de base e verifica novamente o escolhido para deriva (igual a --check-drift). A opção 3 é --watch. Cada opção ainda passa pela mesma confirmação de propriedade que a interface baseada em flags antes de tocar no rádio - o assistente é uma interface mais amigável sobre as mesmas verificações subjacentes, não um caminho separado e menos cuidadoso.
A interface baseada em flags abaixo ainda existe para uso scriptado ou para qualquer pessoa que já saiba o endereço que deseja mirar.
Todos os comandos são executados via venv/bin/python buds_audit.py.
buds_audit.py --help
Funciona a partir de um python3 buds_audit.py --help simples, mesmo sem venv e sem dependências instaladas - ele não importa bleak até que um comando que realmente precise do rádio seja executado.
buds_audit.py --scan
buds_audit.py --scan --flags-only # only show devices matching the known-affected catalog
buds_audit.py --scan --target AA:BB:CC:DD:EE:FF
Escaneia passivamente dispositivos BLE e Bluetooth Classic próximos, identifica chipsets Airoha a partir de dados do fabricante e prefixo de endereço, e faz referência cruzada com data/affected_devices.json.
Cada um destes requer --target ADDR e é uma operação ativa contra aquele dispositivo:
buds_audit.py --gatt --target AA:BB:CC:DD:EE:FF # CVE-2025-20700: unauthenticated GATT access
buds_audit.py --race --target AA:BB:CC:DD:EE:FF # CVE-2025-20702: RACE channel reachability
buds_audit.py --firmware --target AA:BB:CC:DD:EE:FF # CVE-2025-20701: passive firmware/pairing-bypass check
buds_audit.py --bd-address --target AA:BB:CC:DD:EE:FF # Classic BD address via RACE, informational
Todos os quatro pulam limpo (sem erro) se o dispositivo já estiver pareado - uma descoberta de 'acesso não autenticado' é sem sentido contra um dispositivo vinculado.
--gatt agora mostra o valor real retornado por cada leitura ou notificação não pareada bem-sucedida (codificado em hex), não apenas que a leitura foi bem-sucedida - o valor já estava sendo recuperado, então isso não é risco adicional, apenas não é mais descartado.
--race testa apenas a acessibilidade (uma consulta benigna de informações do SDK, sem acesso à memória) - um serviço RACE pode estar presente e aceitar a gravação limpa mas ainda assim não responder, o que é um resultado genuinamente inconclusivo, não evidência de que algo foi corrigido. Para uma resposta definitiva, veja --memory-read abaixo.
--bd-address é informacional, não uma descoberta de vulnerabilidade por si só: ele consulta o endereço Bluetooth Classic (BR/EDR) real do dispositivo através do mesmo canal RACE não autenticado, mesma forma de risco que a consulta de versão de build do --firmware (um comando de metadados com carga zero). Útil se você quiser prosseguir com testes ativos do CVE-2025-20701 por conta própria com um rádio/dongle compatível com Classic, já que esta ferramenta não tem transporte Classic próprio - veja a seção de requisitos de hardware abaixo.
buds_audit.py --memory-read --target AA:BB:CC:DD:EE:FF
Tenta uma leitura real de página flash RACE somente leitura (256 bytes, de um endereço fixo) para uma confirmação definitiva do CVE-2025-20702 - útil quando --race encontra o serviço RACE presente, mas sem resposta à sua consulta benigna. Isso é opt-in e separado de --race propositalmente: um sucesso aqui recupera conteúdo real do firmware do dispositivo, não apenas um sinal sim/não sobre se o canal está acessível. Nunca grava, apaga, extrai chaves de link ou lê RAM/registradores (apenas flash, que não tem efeitos colaterais de leitura) - consulte as seções Fase 8 e Fora do Escopo do ROADMAP.md para a fundamentação completa. Requer sua própria confirmação separada, descrevendo exatamente o que faz, além do prompt de propriedade padrão.
buds_audit.py --assess --target AA:BB:CC:DD:EE:FF
buds_audit.py --assess --target AA:BB:CC:DD:EE:FF --json result.json
buds_audit.py --assess --target AA:BB:CC:DD:EE:FF --memory-read
Executa as sondas GATT, RACE, firmware e BD-address acima contra um alvo e produz um único veredito: PASS, PARTIAL, VULNERABLE ou SUSPECTED_COMPROMISE. O veredito e cada descoberta individual são impressos com uma interpretação em linguagem simples ao lado do detalhe técnico, para que o resultado seja legível sem conhecimento profundo de Bluetooth - esta ferramenta é feita para qualquer pessoa verificando seus próprios dispositivos, não apenas especialistas em segurança. --json adicionalmente escreve o resultado completo (informações do dispositivo, veredito e sua explicação em linguagem simples, flags com evidência e seu glossário em linguagem simples, e notas de remediação) em um arquivo.
Adicionar --memory-read incorpora a confirmação de leitura de memória na mesma auditoria e veredito, com seu próprio prompt de confirmação separado primeiro. A consulta de BD-address é executada automaticamente como parte do --assess (nenhuma flag separada necessária, nenhum prompt de confirmação extra) já que é a mesma forma de consulta de metadados de baixo risco que a verificação de firmware.
--assess é deliberadamente apenas alvo único, igual às sondas individuais - não há modo 'avaliar todo dispositivo ao alcance', já que isso significaria sondar ativamente dispositivos que podem não ser seus.
buds_audit.py --baseline --target AA:BB:CC:DD:EE:FF
buds_audit.py --check-drift --target AA:BB:CC:DD:EE:FF
--baseline captura um instantâneo confiável para um dispositivo na primeira vez que você o avalia - identidade (nome e dados do fabricante), tabela GATT, versão de firmware RACE, e estado de vinculação local (apenas booleanos pareado/confiável/vinculado, nunca material de chave) - e o armazena em data/device_baselines.json. Nunca é capturado automaticamente; você tem que solicitá-lo explicitamente, e executá-lo novamente sobrescreve a linha de base existente.
--check-drift recaptura o mesmo instantâneo e o compara com a linha de base armazenada, produzindo um veredito a partir de qualquer deriva encontrada: IDENTITY_DRIFT, GATT_TABLE_DRIFT, FIRMWARE_DOWNGRADE ou BOND_STATE_DRIFT. Isso responde 'algo mudou desde que confiei neste dispositivo pela última vez,' não 'este dispositivo é vulnerável' - é um sinal heurístico de comprometimento, não prova forense. Um dispositivo com qualquer flag de deriva recebe um veredito SUSPECTED_COMPROMISE, que substitui tudo mais.
buds_audit.py --watch
Escaneia continuamente em janelas de comprimento fixo (Ctrl+C para parar) e correlaciona cada anúncio visto por nome e dados do fabricante. Se dois endereços diferentes transmitirem a mesma identidade com janelas de observação sobrepostas - significando que ambos estavam no ar com essa identidade ao mesmo tempo - ele sinaliza POSSIBLE_IMPERSONATION. Um único dispositivo físico rotacionando seu endereço BLE ao longo do tempo (visto sequencialmente, não concorrentemente) não é sinalizado; apenas um segundo transmissor genuíno é. Mapeia para a etapa final do modelo de ameaça: personificar os fones de ouvido para o telefone da vítima.
data/affected_devices.json é um catálogo curado, não uma lista exaustiva. Atualmente confirmados:
| Marca | Modelo | SoC Airoha | CVEs | Firmware corrigido |
|---|---|---|---|---|
| Sony | WF-1000XM3 | AB1562 | CVE-2025-20700, CVE-2025-20701, CVE-2025-20702 | Nenhum lançado |
De acordo com a divulgação da ERNW, outras marcas que usam SoCs da série Airoha AB1562/AB1565/AB1568 (incluindo Bose, Jabra, JBL, Marshall e modelos Beats anteriores ao patch) também são relatadas como afetadas, mas ainda não estão no catálogo porque seus prefixos de endereço exatos e detalhes de chipset não foram confirmados contra hardware real neste projeto. Um dispositivo fora do catálogo ainda pode ser sondado ativamente com --gatt/--race/--firmware/--assess - o catálogo afeta apenas a correspondência de --scan passivo e a ponderação do veredito, não o que as próprias sondas testam.
Esta ferramenta avalia o CVE-2025-20701 (falta de imposição de emparelhamento Bluetooth Classic) apenas passivamente, através da verificação da versão de build do firmware RACE. Testar ativamente se um handshake de emparelhamento silencioso pode ser concluído requer acesso HCI bruto via Bumble e um dongle Bluetooth USB dedicado compatível com Bumble - não alcançável através de BlueZ/bleak, razão pela qual esta ferramenta não tenta isso. Veja o race-toolkit da ERNW para uma implementação de referência interativa baseada em dongle cobrindo todos os três CVEs.
A cadeia de vulnerabilidades do SDK Airoha (CVE-2025-20700 / CVE-2025-20701 / CVE-2025-20702) foi descoberta e divulgada por Dennis Heinze e Frieder Steinmetz na ERNW. O race-toolkit deles é a implementação de referência ao lado da qual este projeto preenche uma lacuna sem dongle, e os UUIDs GATT exatos do protocolo RACE e o enquadramento de pacotes usados aqui foram lidos diretamente de seu código fonte, em vez de adivinhados - consulte core/race.py para detalhes. O race-toolkit não possui licença (nenhum arquivo LICENSE, verificado diretamente no repositório) - nada de seu código fonte é reutilizado aqui além dos fatos subjacentes do protocolo (UUIDs, estrutura de layout, códigos de comando), que descrevem o próprio protocolo da Airoha e não são a expressão original de seus autores para licenciar em primeiro lugar.
MIT - consulte LICENSE.
venv/bin/ruff check . --fix && venv/bin/ruff format .
venv/bin/python -m pytest tests/