daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

accessibility-services-abuse.md (21558B)


      1 ---
      2 title: "Android Accessibility Service Abuse"
      3 section: "Mobile"
      4 sectionSlug: "mobile-pentesting"
      5 sourcePath: "src/mobile-pentesting/android-app-pentesting/accessibility-services-abuse.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/mobile-pentesting/android-app-pentesting/accessibility-services-abuse.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Android Accessibility Service Abuse
     14 
     15 ## Overview
     16 
     17 `AccessibilityService` was created to help users with disabilities interact with Android devices.  Unfortunately, the same **powerful automation APIs** (global navigation, text input, gesture dispatch, overlay windows…) can be weaponised by malware to gain **complete remote control** of the handset _without root privileges_.<sup>[[4]](#references)</sup>
     18 
     19 Modern Android banking Trojans and Remote-Access-Trojans (RATs) such as **PlayPraetor, SpyNote, BrasDex, SOVA, ToxicPanda** and many others follow the same recipe:
     20 
     21 1. Social-engineer the victim into enabling a rogue accessibility service (the *BIND_ACCESSIBILITY_SERVICE* permission is considered "high-risk" and requires an explicit user action).
     22 2. Leverage the service to
     23    * capture every UI event & text that appears on screen,
     24    * inject synthetic gestures (`dispatchGesture`) and global actions (`performGlobalAction`) to automate any task the operator desires,
     25    * draw full-screen overlays on top of legitimate apps using the **TYPE_ACCESSIBILITY_OVERLAY** window type (no `SYSTEM_ALERT_WINDOW` prompt!),
     26    * silently grant additional runtime permissions by clicking on the system dialogs on the victim’s behalf.
     27 3. Exfiltrate data or perform **On-Device-Fraud (ODF)** in real-time while the user is looking at a perfectly normal screen.
     28 
     29 ---
     30 
     31 ### Packed Accessibility droppers
     32 
     33 ClayRat v3.0.8 couples its Accessibility RAT with a staged payload hidden under `assets/`. At runtime the host APK:<sup>[[1]](#references)</sup>
     34 
     35 1. Streams the encrypted blob from `assets/*.dat`.
     36 2. Decrypts it with a hard-coded AES/CBC key + IV embedded inside the Java/Kotlin loader.
     37 3. Writes the plaintext DEX to the app's private dir and loads it via `DexClassLoader`, exposing the actual spyware classes only in memory.
     38 
     39 ```java
     40 byte[] blob = readAsset("payload.enc");
     41 Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
     42 SecretKeySpec key = new SecretKeySpec(hex("A1..."), "AES");
     43 c.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
     44 byte[] dex = c.doFinal(blob);
     45 DexClassLoader cl = new DexClassLoader(writeTemp(dex), getCodeCacheDir().getPath(), null, getClassLoader());
     46 cl.loadClass("com.clayrat.Core").newInstance();
     47 ```
     48 
     49 This packing pattern (ATT&CK T1406.002) keeps the Accessibility module off-disk until the dropper executes, defeating static signature scans and Play Protect until the user already granted the dangerous permissions.
     50 
     51 Zimperium publishes a companion ClayRat v3 indicator set that defenders can use to correlate the analyzed samples and infrastructure.<sup>[[2]](#references)</sup>
     52 
     53 ---
     54 
     55 ## Requesting the permission
     56 
     57 ```xml
     58 <!-- AndroidManifest.xml -->
     59 <service
     60     android:name="com.evil.rat.EvilService"
     61     android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
     62     android:exported="false">
     63 
     64     <intent-filter>
     65         <action android:name="android.accessibilityservice.AccessibilityService" />
     66     </intent-filter>
     67 
     68     <meta-data android:name="android.accessibilityservice"
     69         android:resource="@xml/evil_accessibility_config"/>
     70 </service>
     71 ```
     72 
     73 The companion XML defines how the fake dialog will look like:
     74 
     75 ```xml
     76 <?xml version="1.0" encoding="utf-8"?>
     77 <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
     78     android:description="@string/service_description"
     79     android:accessibilityEventTypes="typeAllMask"
     80     android:accessibilityFeedbackType="feedbackGeneric"
     81     android:notificationTimeout="200"
     82     android:canPerformGestures="true"
     83     android:canRetrieveWindowContent="true"/>
     84 ```
     85 
     86 ---
     87 
     88 ## Remote UI automation primitives
     89 
     90 <details>
     91 <summary>Accessibility service automation skeleton</summary>
     92 
     93 ```java
     94 public class EvilService extends AccessibilityService {
     95     @Override
     96     public void onAccessibilityEvent(AccessibilityEvent event) {
     97         // harvest text or detect foreground app change
     98     }
     99 
    100     // Simulate HOME / BACK / RECENTS …
    101     private void navHome()     { performGlobalAction(GLOBAL_ACTION_HOME); }
    102     private void navBack()     { performGlobalAction(GLOBAL_ACTION_BACK); }
    103     private void openRecents() { performGlobalAction(GLOBAL_ACTION_RECENTS); }
    104 
    105     // Generic tap / swipe
    106     public void tap(float x, float y) {
    107         Path p = new Path(); p.moveTo(x, y);
    108         GestureDescription.StrokeDescription s = new GestureDescription.StrokeDescription(p, 0, 50);
    109         dispatchGesture(new GestureDescription.Builder().addStroke(s).build(), null, null);
    110     }
    111 }
    112 ```
    113 
    114 </details>
    115 
    116 With only these two APIs an attacker can:
    117 * Unlock the screen, open the banking app, navigate its UI tree and submit a transfer form.
    118 * Accept every permission dialog that pops up.
    119 * Install/update extra APKs via the Play Store intent.
    120 
    121 ---
    122 
    123 ## Abuse patterns
    124 
    125 ### 1. Overlay Phishing (Credential Harvesting)
    126 A transparent or opaque `WebView` is added to the window manager:
    127 
    128 ```java
    129 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
    130         MATCH_PARENT, MATCH_PARENT,
    131         TYPE_ACCESSIBILITY_OVERLAY,                      // ⬅ bypasses SYSTEM_ALERT_WINDOW
    132         FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL,       // touches still reach the real app
    133         PixelFormat.TRANSLUCENT);
    134 wm.addView(phishingView, lp);
    135 ```
    136 
    137 The victim types credentials into the fake form while the background app receives the same gestures – no suspicious "draw over other apps" prompt is ever shown.
    138 
    139 > Detailed example: the *Accessibility Overlay Phishing* section inside the Tapjacking page.
    140 
    141 ClayRat exposes this capability with the `show_block_screen` / `hide_block_screen` commands that download overlay templates from the C2. Operators can switch layouts on the fly to:<sup>[[1]](#references)</sup>
    142 
    143 - **Black out** the panel so the victim assumes the handset is off or frozen while automated gestures disable Play Protect or grant more permissions.
    144 - Display fake **system update / battery optimization** panels that justify why the device is “busy” while background automation continues.
    145 - Show an **interactive PIN pad** overlay that mirrors the system lock screen—the malware captures every digit and streams it to the operator as soon as a 4‑digit code is entered.
    146 
    147 Because TYPE_ACCESSIBILITY_OVERLAY windows never raise the `SYSTEM_ALERT_WINDOW` permission prompt, the victim only sees the decoy UI while the RAT keeps interacting with the real apps underneath.
    148 
    149 ### 2. On-Device Fraud automation
    150 Malware families such as **PlayPraetor** maintain a persistent WebSocket channel where the operator can issue high-level commands (`init`, `update`, `alert_arr`, `report_list`, …).  The service translates those commands into the low-level gestures above, achieving real-time unauthorized transactions that easily bypass multi-factor-authentication tied to that very device.<sup>[[3]](#references)</sup>
    151 
    152 ### 3. Screen streaming & monitoring
    153 ClayRat upgrades the usual MediaProjection trick into a remote desktop stack:<sup>[[1]](#references)</sup>
    154 
    155 1. `turbo_screen` triggers the MediaProjection consent dialog; the Accessibility service clicks “Start now” so the victim never intervenes.
    156 2. With the resulting `MediaProjection` token it creates a `VirtualDisplay` backed by an `ImageReader`, keeps a `ForegroundService` alive, and drains frames on worker threads.
    157 3. Frames are JPEG/PNG encoded according to the operator-supplied `set_quality` parameter (defaults to `60` when missing) and shipped over an HTTP→WebSocket upgrade advertising the custom `ClayRemoteDesktop` user-agent.
    158 4. `start_desktop` / `stop_desktop` manage the capture threads while `screen_tap`, `screen_swipe`, `input_text`, `press_home`, `press_back` and `press_recents` replay gestures against the live framebuffer.
    159 
    160 The result is a VNC-like feed delivered entirely through sanctioned APIs—no root or kernel exploits—yet it hands the attacker live situational awareness with millisecond latency.
    161 
    162 ### 4. Lock-screen credential theft & auto-unlock
    163 ClayRat subscribes to `TYPE_WINDOW_CONTENT_CHANGED` / `TYPE_VIEW_TEXT_CHANGED` events emitted by `com.android.systemui` (`Keyguard`). It reconstructs whatever guard is active:<sup>[[1]](#references)</sup>
    164 
    165 - **PIN** – watches keypad button presses until the locker reports completion.
    166 - **Password** – concatenates strings seen in the focused password field for each `AccessibilityEvent`.
    167 - **Pattern** – records the ordered node indices inferred from gesture coordinates across the 3×3 grid.
    168 
    169 Secrets plus metadata (lock type + timestamp) are serialized into `SharedPreferences` under `lock_password_storage`. When the operator pushes `auto_unlock`, the service wakes the device with `unlock_device` / `screen_on`, replays the stored digits or gestures through `dispatchGesture`, and silently bypasses the keyguard so subsequent ODF workflows can continue.
    170 
    171 ### 5. Notification phishing & harvesting
    172 A companion Notification Listener turns the shade into a phishing surface:<sup>[[1]](#references)</sup>
    173 
    174 - `get_push_notifications` dumps every currently visible notification, including OTP / MFA messages.
    175 - The `notifications` command toggles a `notifications_enabled` flag so each future `onNotificationPosted()` payload is streamed to the C2 in real time.
    176 - `send_push_notification` lets operators craft fake, interactive notifications that impersonate banking or chat apps; any text the victim submits is parsed as credentials and exfiltrated immediately.
    177 
    178 Because Accessibility can open/dismiss the notification shade programmatically, this method harvests secrets without touching the targeted apps.
    179 
    180 ### 6. Telephony & SMS command channel
    181 After coercing the user into setting the RAT as the default SMS app, the following commands provide complete modem control:<sup>[[1]](#references)</sup>
    182 
    183 - `send_sms` and `retransmishion` send arbitrary or replayed messages to attacker-controlled numbers.
    184 - `messsms` iterates over the entire contacts database to spam phishing links for worm-like propagation.
    185 - `make_call` initiates voice calls that support social-engineering workflows.
    186 - `get_sms_list` / `get_sms` and `get_call_log` / `get_calls` dump inboxes and call history so MFA codes or call metadata can be abused instantly.
    187 
    188 Combined with Accessibility-driven UI navigation, ClayRat can receive an OTP via notification/SMS and immediately input it inside the target banking or enterprise app.
    189 
    190 ### 7. Discovery, collection & proxying
    191 Additional ClayRat commands map the environment and keep C2 resilient:<sup>[[1]](#references)</sup>
    192 
    193 - `get_apps` / `get_apps_list` enumerate installed packages (ATT&CK T1418).
    194 - `get_device_info` reports model, OS version and battery state (T1426).
    195 - `get_cam` / `get_camera` capture front-camera stills, while `get_keylogger_data` serializes lock PINs plus passwords, view descriptions and hints scraped from sensitive fields.
    196 - `get_proxy_data` fetches a proxy WebSocket URL, appends the unique device ID and spins a job that tunnels HTTP/HTTPS over the same bidirectional channel (T1481.002 / T1646).
    197 
    198 ### 8. Region-scoped keypad interception and gesture replay
    199 
    200 Instead of drawing a fake banking form, an Accessibility RAT can locate the numeric-key nodes in the **real** application, union their `getBoundsInScreen()` rectangles, and place a touch-consuming overlay only over that keypad. For every victim tap, it records the coordinates and nearby node, temporarily stops intercepting touches, replays a tap at the same coordinates with `dispatchGesture()`, and restores the overlay. The legitimate application therefore receives the expected input and continues normally while the RAT reconstructs the PIN from the intercepted sequence.<sup>[[7]](#references)</sup>
    201 
    202 This differs from a pass-through overlay: the malicious window receives the original event and Accessibility injects a second event only after interception is disabled. During reverse engineering, look for `AccessibilityNodeInfo` bounds aggregation next to a small overlay window, coordinate hit-testing, rapid changes to touchability/visibility, and `dispatchGesture()` callbacks that re-arm the overlay.<sup>[[7]](#references)</sup>
    203 
    204 ### 9. Semantic Accessibility keylogging
    205 
    206 Raw `TYPE_VIEW_TEXT_CHANGED`, `TYPE_VIEW_CLICKED`, and window-content events become more useful when records are enriched with the source package, timestamp, target-list membership, and whether text came from Autofill or manual entry. The collector can then classify values such as lock-screen input, 4–6 digit OTPs, passwords, email logins, long messages, and possible wallet recovery phrases before upload, allowing operators to prioritize authentication material rather than reviewing an undifferentiated event stream.<sup>[[7]](#references)</sup>
    207 
    208 ### 10. Peer-assisted store-and-forward exfiltration
    209 
    210 An Accessibility RAT can keep collected files and command results in a durable queue, encrypt each package with AES-GCM, and relay it through nearby infected phones when direct C2 access is unavailable. One observed design tries an established Wi-Fi Direct peer first, then queries classic Bluetooth RFCOMM or BLE GATT peers for Internet reachability. A reachable peer accepts the encrypted package and forwards it toward C2; unroutable items remain queued for retry, and a hop counter (four hops by default in the observed implementation) bounds multi-device forwarding.<sup>[[7]](#references)</sup>
    211 
    212 Static and dynamic triage should correlate queue persistence and `AES/GCM/NoPadding` with `WifiP2pManager`, RFCOMM `BluetoothSocket`, `BluetoothGatt`, reachability probes, and decrementing hop/TTL fields. Containment must isolate local radios or physically separate suspected devices as well as blocking Internet access, because a nearby compromised peer may provide the egress path.<sup>[[7]](#references)</sup>
    213 
    214 ---
    215 
    216 ## PlayPraetor – command & control workflow
    217 
    218 1. **HTTP(S) heartbeat** – iterate over a hard-coded list until one domain answers `POST /app/searchPackageName` with the active C2.
    219 2. **WebSocket (port 8282)** – bidirectional JSON commands:
    220    * `update` – push new conf/APKs
    221    * `alert_arr` – configure overlay templates
    222    * `report_list` – send list of targeted package names
    223    * `heartbeat_web` – keep-alive
    224 3. **RTMP (port 1935)** – live screen/video streaming.
    225 4. **REST exfiltration** –
    226    * `/app/saveDevice` (fingerprint)
    227    * `/app/saveContacts` | `/app/saveSms` | `/app/uploadImageBase64`
    228    * `/app/saveCardPwd` (bank creds)
    229 
    230 The **AccessibilityService** is the local engine that turns those cloud commands into physical interactions.<sup>[[3]](#references)</sup>
    231 
    232 ---
    233 
    234 ## Detecting malicious accessibility services
    235 
    236 * `adb shell settings get secure enabled_accessibility_services`
    237 * Settings → Accessibility → *Downloaded services* – look for apps that are **not** from Google Play.
    238 * MDM / EMM solutions can enforce `ACCESSIBILITY_ENFORCEMENT_DEFAULT_DENY` (Android 13+) to block sideloaded services.
    239 * Analyse running services:
    240   ```bash
    241   adb shell dumpsys accessibility | grep "Accessibility Service"
    242   ```
    243 
    244 ---
    245 
    246 ## Hardening recommendations for app developers
    247 
    248 * Mark sensitive views with `android:accessibilityDataSensitive="accessibilityDataPrivateYes"` (API 34+).
    249 * Combine `setFilterTouchesWhenObscured(true)` with `FLAG_SECURE` to prevent tap/overlay hijacking.
    250 * Detect overlays by polling `WindowManager.getDefaultDisplay().getFlags()` or the `ViewRootImpl` API.
    251 * Refuse to operate when `Settings.canDrawOverlays()` **or** a non-trusted Accessibility service is active.
    252 
    253 ---
    254 
    255 ## ATS automation cheat-sheet (Accessibility-driven)
    256 Malware can fully automate a bank app with only Accessibility APIs. Generic primitives:
    257 
    258 <details>
    259 <summary>Helper methods for ATS automation</summary>
    260 
    261 ```java
    262 // Helpers inside your AccessibilityService
    263 private List<AccessibilityNodeInfo> byText(String t){
    264   AccessibilityNodeInfo r = getRootInActiveWindow();
    265   return r == null ? Collections.emptyList() : r.findAccessibilityNodeInfosByText(t);
    266 }
    267 private boolean clickText(String t){
    268   for (AccessibilityNodeInfo n: byText(t)){
    269     if (n.isClickable()) return n.performAction(ACTION_CLICK);
    270     AccessibilityNodeInfo p = n.getParent();
    271     if (p != null) return p.performAction(ACTION_CLICK);
    272   }
    273   return false;
    274 }
    275 private void inputText(AccessibilityNodeInfo field, String text){
    276   Bundle b = new Bundle(); b.putCharSequence(ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text);
    277   field.performAction(ACTION_SET_TEXT, b);
    278 }
    279 private void tap(float x, float y){
    280   Path p = new Path(); p.moveTo(x,y);
    281   dispatchGesture(new GestureDescription.Builder()
    282     .addStroke(new GestureDescription.StrokeDescription(p,0,40)).build(), null, null);
    283 }
    284 ```
    285 
    286 </details>
    287 
    288 Example flow (Czech → English labels):<sup>[[5]](#references)</sup>
    289 - "Nová platba" (New payment) → click
    290 - "Zadat platbu" (Enter payment) → click
    291 - "Nový příjemce" (New recipient) → click
    292 - "Domácí číslo účtu" (Domestic account number) → focus and `ACTION_SET_TEXT`
    293 - "Další" (Next) → click → … "Zaplatit" (Pay) → click → enter PIN
    294 
    295 Fallback: hard-coded coordinates with `dispatchGesture` when text lookup fails due to custom widgets.
    296 
    297 Also seen: pre-steps to `check_limit` and `limit` by navigating to limits UI and increasing daily limits before transfer.<sup>[[5]](#references)</sup>
    298 
    299 ## Text-based pseudo-screen streaming
    300 For low-latency remote control, instead of full video streaming, dump a textual representation of the current UI tree and send it to C2 repeatedly.
    301 
    302 ```java
    303 private void dumpTree(AccessibilityNodeInfo n, String indent, StringBuilder sb){
    304   if (n==null) return;
    305   Rect b = new Rect(); n.getBoundsInScreen(b);
    306   CharSequence txt = n.getText(); CharSequence cls = n.getClassName();
    307   sb.append(indent).append("[").append(cls).append("] ")
    308     .append(txt==null?"":txt).append(" ")
    309     .append(b.toShortString()).append("\n");
    310   for (int i=0;i<n.getChildCount();i++) dumpTree(n.getChild(i), indent+"  ", sb);
    311 }
    312 ```
    313 
    314 This is the basis for commands like `txt_screen` (one-shot) and `screen_live` (continuous).<sup>[[5]](#references)</sup>
    315 
    316 ## Device Admin coercion primitives
    317 Once a Device Admin receiver is activated, these calls increase opportunities to capture credentials and maintain control:<sup>[[5]](#references)</sup>
    318 
    319 ```java
    320 DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
    321 ComponentName admin = new ComponentName(this, AdminReceiver.class);
    322 
    323 // 1) Immediate lock
    324 dpm.lockNow();
    325 
    326 // 2) Force credential change (expire current PIN/password)
    327 dpm.setPasswordExpirationTimeout(admin, 1L); // may require owner/profile-owner on recent Android
    328 
    329 // 3) Disable biometric unlock to force PIN/pattern entry
    330 int flags = DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT |
    331             DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS;
    332 dpm.setKeyguardDisabledFeatures(admin, flags);
    333 ```
    334 
    335 Note: the exact availability of these policies varies by Android version and OEM; validate the device policy role (admin vs owner) during testing.
    336 
    337 ## Crypto wallet seed-phrase extraction patterns
    338 Observed flows for MetaMask, Trust Wallet, Blockchain.com and Phantom:<sup>[[5]](#references)</sup>
    339 - Unlock with stolen PIN (captured via overlay/Accessibility) or provided wallet password.
    340 - Navigate: Settings → Security/Recovery → Reveal/Show recovery phrase.
    341 - Collect phrase via keylogging the text nodes, secure-screen bypass, or screenshot OCR when text is obscured.
    342 - Support multiple locales (EN/RU/CZ/SK) to stabilise selectors – prefer `viewIdResourceName` when available, fallback to multilingual text matching.
    343 
    344 ## NFC-relay orchestration
    345 Accessibility/RAT modules can install and launch a dedicated NFC-relay app (e.g., NFSkate) as a third stage and even inject an overlay guide to shepherd the victim through card-present relay steps.<sup>[[6]](#references)</sup>
    346 
    347 Background and TTPs: https://www.threatfabric.com/blogs/ghost-tap-new-cash-out-tactic-with-nfc-relay<sup>[[6]](#references)</sup>
    348 
    349 ---
    350 
    351 ## References
    352 - [1] [Return of ClayRat: Expanded Features and Techniques](https://zimperium.com/blog/return-of-clayrat-expanded-features-and-techniques)
    353 - [2] [ClayRat v3 IoCs (Zimperium)](https://github.com/Zimperium/IOC/tree/master/2025-12-ClayRatv3)
    354 - [3] [PlayPraetor's evolving threat: How Chinese-speaking actors globally scale an Android RAT](https://www.cleafy.com/cleafy-labs/playpraetors-evolving-threat-how-chinese-speaking-actors-globally-scale-an-android-rat)
    355 - [4] [Android accessibility documentation – Automating UI interaction](https://developer.android.com/guide/topics/ui/accessibility/service)
    356 - [5] [The Rise of RatOn: From NFC heists to remote control and ATS (ThreatFabric)](https://www.threatfabric.com/blogs/the-rise-of-raton-from-nfc-heists-to-remote-control-and-ats)
    357 - [6] [GhostTap/NFSkate – NFC relay cash-out tactic (ThreatFabric)](https://www.threatfabric.com/blogs/ghost-tap-new-cash-out-tactic-with-nfc-relay)
    358 - [7] [Manic: Blend between Banking Malware & Spyware (ThreatFabric)](https://threatfabric.com/blogs/manic-blend-between-banking-malware-and-spyware)