Redireccionamiento de intents

Categoría de OWASP: MASVS-PLATFORM: Interacción con la plataforma

Descripción general

El redireccionamiento de intents se produce cuando un atacante puede controlar de forma parcial o total el contenido de un intent que se usa para iniciar un componente nuevo en el contexto de una app vulnerable.

El intent que se usa para iniciar el componente nuevo se puede proporcionar de varias maneras, por lo general, como un intent serializado en un campo extras, o bien se puede ordenar en una cadena y analizar. El control parcial de los parámetros también puede generar el mismo resultado.

Impacto

El impacto puede variar. Un atacante podría ejecutar una funcionalidad interna en la app vulnerable o acceder a componentes privados, como objetos ContentProvider no exportados.

Mitigaciones

General

Trata de no exponer la funcionalidad relacionada con el redireccionamiento de intents anidados. Cuando no se pueda evitar, aplica los siguientes métodos de mitigación:

  • Limpia de manera correcta la información del paquete. Recuerda verificar o borrar las marcas (GRANT_URI_PERMISSIONS), así como verificar a dónde se redirecciona el intent. IntentSanitizer puede ayudarte con este proceso.
  • Usa objetos PendingIntent. Esto evita que el componente se exporte y hace que el intent de la acción objetivo sea inmutable.

Las apps pueden verificar los sitios a los que se redirecciona un intent con métodos como ResolveActivity:

Kotlin

val intent = getIntent()
// Get the component name of the nested intent.
val forward = intent.getParcelableExtra<Parcelable>("key") as Intent
val name: ComponentName = forward.resolveActivity(packageManager)
// Check that the package name and class name contain the expected values.
if (name.packagename == "safe_package" && name.className == "safe_class") {
    // Redirect the nested intent.
    startActivity(forward)
}

Java

Intent intent = getIntent()
// Get the component name of the nested intent.
Intent forward = (Intent) intent.getParcelableExtra("key");
ComponentName name = forward.resolveActivity(getPackageManager());
// Check that the package name and class name contain the expected values.
if (name.getPackageName().equals("safe_package") &&
        name.getClassName().equals("safe_class")) {
    // Redirect the nested intent.
    startActivity(forward);
}

Las apps pueden usar IntentSanitizer con una lógica similar a la siguiente:

Kotlin

val intent = IntentSanitizer.Builder()
     .allowComponent("com.example.ActivityA")
     .allowData("com.example")
     .allowType("text/plain")
     .build()
     .sanitizeByThrowing(intent)

Java

Intent intent = new  IntentSanitizer.Builder()
     .allowComponent("com.example.ActivityA")
     .allowData("com.example")
     .allowType("text/plain")
     .build()
     .sanitizeByThrowing(intent);

Errores comunes

  • Comprobar si getCallingActivity() muestra un valor no nulo. Las apps maliciosas pueden proporcionar un valor nulo para esta función.
  • Suponer que checkCallingPermission() funciona en todos los contextos o que el método genera una excepción cuando muestra un número entero.

Funciones de depuración

En el caso de las apps que se orientan a Android 12 (nivel de API 31) o versiones posteriores, puedes habilitar una función de depuración que, en algunos casos, te ayuda a detectar si la app realiza un lanzamiento inseguro de un intent.

Si la app realiza las siguientes dos acciones, el sistema detecta un lanzamiento de intent inseguro y se produce una infracción de StrictMode:

  • La app descomprime un intent anidado desde los valores adicionales de un intent entregado.
  • La app inicia inmediatamente un componente de la app con ese intent anidado, como cuando se pasa el intent a startActivity(), startService() o bindService().

Recursos

  • Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
  • Intents pendientes