
CVE-2026-12960 - Exportation inappropriée de composants d'application Android dans l'application ASUS Router (com.asus.aihome). PoC, APK d'exploitation, vidéo et rapport du fournisseur. Corrigé dans 1.0.0.9.74.
Exportation inappropriée des composants d'application Android dans l'application ASUS Router
Un composant inclus dans l'application Android ASUS Router (com.asus.aihome) a été déclaré
android:exported="true" sans android:permission. Toute autre application sur le même
appareil, ne possédant aucune permission, pouvait lui envoyer un Intent malveillant et forcer
l'application ASUS Router à ouvrir une URI contrôlée par un attaquant au nom de l'utilisateur.
Signalé à ASUS le 2026-03-17. Corrigé par ASUS et publié sous le numéro CVE-2026-12960 le 2026-07-03.
Découvert et signalé par Sedric Louissaint de Show Up Show Out Security.
| CVE | CVE-2026-12960 |
| Produit | Application ASUS Router pour Android (com.asus.aihome) |
| Versions affectées | ≤ 1.0.0.9.71 |
| Corrigé dans | 1.0.0.9.74 |
| Faiblesse | CWE-926 : Exportation inappropriée des composants d'application Android |
| CVSS 4.0 | 6.0 Moyen 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 |
| Avis du fournisseur | https://www.asus.com/security-advisory/ |
| Testé sur | com.asus.aihome 1.0.0.9.71 (Google Play), émulateur Android 11 |
L'application intègre le SDK Baidu Push, qui déclare :
<service
android:name="com.baidu.android.pushservice.CommandService"
android:exported="true" />
Aucun attribut android:permission n'est présent, donc le contrôle d'accès au niveau des
composants d'Android ne s'exécute jamais. Toute application installée peut appeler
startService() contre lui.
CommandService.onStartCommand() lit un PublicMsg Parcelable depuis l'extra public_msg
de l'Intent entrant et le transmet à handlePrivateNotification(), qui effectue une
ramification selon le champ mOpenType fourni par l'attaquant :
mOpenType | Comportement |
|---|---|
1 | startActivity(ACTION_VIEW, Uri.parse(mUrl)) avec le mUrl de l'attaquant |
2 | Intent.parseUri(mPkgContent, 0) puis startActivity() / sendBroadcast() |
Ni l'expéditeur ni la charge utile ne sont validés. Comme l'activité résultante est lancée depuis le propre UID et processus de l'application ASUS, tout ce qui apparaît à l'écran semble provenir de l'application de gestion du routeur de confiance que l'utilisateur vient d'ouvrir.
Rien de tout cela n'est spécifique à Baidu en pratique. Le SDK fournit le composant exporté, l'application hôte l'hérite, et c'est l'identité de l'application hôte qui est empruntée.
PublicMsg Parcelable correspondant à la
disposition des champs de la cible.mOpenType = 1 et mUrl sur une URI contrôlée par l'attaquant.CommandService. Aucune permission requise, aucune
SecurityException.onStartCommand() → handlePrivateNotification().startActivity(ACTION_VIEW, Uri.parse(mUrl)) est déclenché depuis le processus de
l'application ASUS.L'ordre des champs PublicMsg, extrait de writeToParcel dans le smali décompilé et
réimplémenté dans 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 l'ordre est erroné, le Parcel est désérialisé en déchets. S'il est correct, le service accepte le message comme si la propre infrastructure push de Baidu l'avait envoyé.
Six schémas d'URI, un service exporté, zéro permission :
| # | Schéma | Résultat |
|---|---|---|
| 1 | https: | Le navigateur ouvre une page de phishing contrôlée par l'attaquant |
| 2 | sms: | Composer SMS pré-rempli avec un message d'ingénierie sociale |
| 3 | tel: | Numéroteur pré-rempli avec un numéro contrôlé par l'attaquant |
| 4 | mailto: | Composer email pré-rempli pour exfiltrer des identifiants |
| 5 | market: | Redirection vers le Play Store pour une installation de malware |
| 6 | geo: | Redirection Maps vers un faux centre de service |
media/poc_commandservice.mp4 est l'enregistrement complet
de 31 secondes : construction, installation, déclenchement, et l'émulateur réagissant à
chaque charge utile à son tour.
| Attaque 1 : page de phishing | Attaque 2 : composer SMS | Attaque 3 : numéroteur | Permissions de l'application PoC |
|---|---|---|---|
![]() | ![]() | ![]() | ![]() |
Cette dernière capture d'écran résume tout. Aucune permission demandée. L'application qui vient d'exécuter six actions via l'application ASUS Router n'a rien demandé à l'utilisateur.
Nécessite ADB, un JDK, et les outils de construction du SDK Android (aapt2, d8/dx,
zipalign, apksigner) ainsi que platforms;android-30.
./poc/poc_commandservice_exploit.sh <device_serial>
Le script exécute trois phases :
CommandService depuis
com.android.shell et rapporte si l'une d'elles est rejetée. Un service protégé par
permission lèverait SecurityException ici. Celui-ci les a toutes acceptées.exploit_commandservice.apk, et
l'installe. Une copie préconstruite est disponible dans poc/ si vous
préférez sauter cette étape.Sortie de la phase 1 sur un appareil vulnérable :
[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
Et le ServiceRecord de dumpsys activity services, qui enregistre l'appelant :
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
Phase 3, depuis une véritable application non privilégiée plutôt que le shell :
W PoCExploit: [OK] attack1_url_open → com.asus.aihome/com.baidu.android.pushservice.CommandService
W PoCExploit: [OK] attack2_sms_compose → ...
(all 6 succeed)