diff --git a/src/mobile-pentesting/android-app-pentesting/accessibility-services-abuse.md b/src/mobile-pentesting/android-app-pentesting/accessibility-services-abuse.md index 6bf2d5a383a..456b751f269 100644 --- a/src/mobile-pentesting/android-app-pentesting/accessibility-services-abuse.md +++ b/src/mobile-pentesting/android-app-pentesting/accessibility-services-abuse.md @@ -71,6 +71,36 @@ The companion XML defines how the fake dialog will look like: android:canRetrieveWindowContent="true"/> ``` +### Two-app sideload chain + staged loader handoff + +FvncBot shows a reusable **banking-trojan installation pattern**: a visible lure app first asks for **Install unknown apps**, then installs a second APK disguised as a system/update component, and finally deep-links the victim into that second app's setup flow to obtain Accessibility. + +Useful implementation details to hunt for during reversing: + +1. **Stage-0 lure** keeps operator strings and pre-wires the second package in `AndroidManifest.xml` via `` and provider lookups. +2. **Stage-1 loader** decodes bytes into an app-private path such as `/data/user/0//app_/.txt` and instantiates them with `DexClassLoader`, so the malicious logic is absent from the main `classes.dex`. +3. The runtime-loaded installer **drops an embedded APK from `assets/` to cache**, launches the package installer, then opens a deep link such as `core://setup` with `Intent.ACTION_VIEW` to continue the victim-guided flow. +4. Before re-prompting, the installer may query a **content provider** exposed by the second stage and wait for a value such as `"enabled"` to confirm that Accessibility was granted. +5. The visible second-stage APK can still be another loader: FvncBot stored the final payload inside `assets/qkcCg.jpg`, then applied an **RC4-like transform** to recover a ZIP containing the real `classes.dex`. + +Minimal patterns: + +```java +DexClassLoader cl = new DexClassLoader( + "/data/user/0//app_tell/tWyWeG.txt", + "/data/user/0//app_tell", + null, + getClassLoader()); +``` + +```java +Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("core://setup")); +i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); +startActivity(i); +``` + +This chaining separates the **lure**, **installer**, **Accessibility shell**, and **final RAT** into different runtime stages, which reduces static detections and makes the malicious behavior appear only after several victim-driven UI steps. + --- ## Remote UI automation primitives @@ -147,6 +177,16 @@ ClayRat upgrades the usual MediaProjection trick into a remote desktop stack: 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. +### 3.b Text-mode VNC: UI-tree capture + rich text interception +FvncBot highlights a common evolution from "simple ATS bot" to **text-mode VNC**: + +- Serialize the active Accessibility tree to JSON, including **text**, `viewIdResourceName`, `contentDescription`, bounds, class name, role, and child hierarchy. +- Ship screen metadata (`timestamp`, width, height) so the operator can align taps and overlays remotely. +- Treat `TYPE_VIEW_TEXT_CHANGED` as a keylogging source and keep the full event context: previous text, current text, added/removed counts, indexes, input type, package/class, and `isPassword()`. +- Mix **broadcast / FCM / WebSocket** control channels so high-level commands can trigger `dispatchGesture`, `performGlobalAction`, overlay rendering, clipboard injection, app launch, or session teardown. + +This is more reliable than raw video-only remote control because the attacker can search nodes by ID/text/description, render precise phishing overlays, and recover secrets from editable fields even when no full screen stream is active. + ### 4. Lock-screen credential theft & auto-unlock ClayRat subscribes to `TYPE_WINDOW_CONTENT_CHANGED` / `TYPE_VIEW_TEXT_CHANGED` events emitted by `com.android.systemui` (`Keyguard`). It reconstructs whatever guard is active: @@ -208,6 +248,8 @@ The **AccessibilityService** is the local engine that turns those cloud commands * `adb shell settings get secure enabled_accessibility_services` * Settings → Accessibility → *Downloaded services* – look for apps that are **not** from Google Play. * MDM / EMM solutions can enforce `ACCESSIBILITY_ENFORCEMENT_DEFAULT_DENY` (Android 13+) to block sideloaded services. +* Treat the sequence **Install unknown apps** → **new APK install** → **deep link into setup** → **Accessibility enablement** as a high-signal dropper pattern. +* During malware triage, grep for `DexClassLoader` reading from **app-private directories** or from files with misleading extensions (`.txt`, `.jpg`, `.dat`) and for staged APKs extracted from `assets/`. * Analyse running services: ```bash adb shell dumpsys accessibility | grep "Accessibility Service" @@ -327,5 +369,6 @@ Background and TTPs: https://www.threatfabric.com/blogs/ghost-tap-new-cash-out-t * [Android accessibility documentation – Automating UI interaction](https://developer.android.com/guide/topics/ui/accessibility/service) * [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) * [GhostTap/NFSkate – NFC relay cash-out tactic (ThreatFabric)](https://www.threatfabric.com/blogs/ghost-tap-new-cash-out-tactic-with-nfc-relay) +* [Analysis of FvncBot campaign](https://cert.pl/en/posts/2026/03/fvncbot-analysis/) -{{#include ../../banners/hacktricks-training.md}} \ No newline at end of file +{{#include ../../banners/hacktricks-training.md}}