Resumen
El fallo está en la app Android de Nextcloud (com.nextcloud.client), concretamente en la actividad com.owncloud.android.ui.activity.FileDisplayActivity. Esa actividad está exportada y declara varios intent-filter de tipo VIEW con host comodín, así que cualquier enlace o cualquier otra aplicación del dispositivo puede lanzarla con los datos que quiera.
Al arrancar, en onStart (FileDisplayActivity.kt:2784), el código llama a getAccountName() sobre el objeto User actual sin comprobar antes que exista. Cuando la actividad se abre desde fuera y ese objeto es nulo, salta un NullPointerException que nadie captura y Android cierra la app con el aviso "App has stopped".
HackerOne clasificó la debilidad como "Improper Null Termination"; en la práctica se trata de una desreferencia de puntero nulo por no validar la entrada externa ni el contexto de cuenta. El programa lo marcó como resuelto y la severidad publicada en HackerOne es "none", aunque el investigador lo propuso como media.
Datos del entorno de la prueba:
- App:
com.nextcloud.client, versión 30340090, variantegeneric. - Dispositivo: Samsung SM-T585 con Android 8.1.0 (SDK 27).
Pasos de reproducción
- Tener la app de Nextcloud instalada en un dispositivo Android con depuración ADB.
- Lanzar la actividad con un intent
VIEWque apunte a una URL externa cualquiera:
adb shell am start -a android.intent.action.VIEW \
-d "https://attacker.example.com/f/abcdef" \
-n com.nextcloud.client/com.owncloud.android.ui.activity.FileDisplayActivity
- La app se cierra de inmediato. En
logcataparece la excepción (extracto):
Exception in thread "main" java.lang.RuntimeException: Unable to start activity ComponentInfo{com.nextcloud.client/com.owncloud.android.ui.activity.FileDisplayActivity}: java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.String com.nextcloud.client.account.User.getAccountName()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2974)
...
Caused by: Exception in thread "main" java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.String com.nextcloud.client.account.User.getAccountName()' on a null object reference
at com.owncloud.android.ui.activity.FileDisplayActivity.onStart(FileDisplayActivity.kt:2784)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1342)
at android.app.Activity.performStart(Activity.java:7278)
...
Según el investigador, el cierre se reproduce de forma consistente cada vez que se ejecuta la orden.
Impacto
Una página web con un enlace preparado o una app maliciosa instalada en el mismo teléfono puede abrir la actividad exportada y tumbar la aplicación de Nextcloud cuando quiera: una denegación de servicio local contra el cliente.
El investigador apuntó además que, al aceptar los filtros cualquier host, otras rutas de código podrían llegar a hacer peticiones autenticadas a URLs arbitrarias (SSRF o inyección de contenido). Él mismo aclara que eso no se observó en esta prueba, porque la app se cae antes de llegar a ese punto.
Remediación
El reporte no detalla el parche aplicado por Nextcloud, solo que quedó resuelto. Las medidas que propuso el investigador fueron:
- Comprobar que el usuario actual no es nulo antes de usarlo y, si no hay sesión, ignorar el enlace o pedir inicio de sesión:
val user = getCurrentUserProvider().getCurrentUser().blockingGet()
if (user == null) {
Log.w(TAG, "Deep link received but no user logged in; ignoring deep link or prompting login")
return
}
- Quitar
host="*"de los filtros y usar una lista explícita de dominios permitidos, validandointent.datay los patrones de ruta. - No hacer peticiones autenticadas automáticas a URLs externas arbitrarias: solo a hosts permitidos, sin reenviar credenciales a otros dominios y bloqueando redirecciones a direcciones internas (RFC1918, link-local o endpoints de metadatos).
- Ante intents mal formados o inesperados, registrar el problema y salir en lugar de lanzar una excepción.