
CVE-2026-12960 - Некорректный экспорт компонентов Android-приложения в приложении ASUS Router (com.asus.aihome). PoC, эксплойт APK, видео и отчёт вендору. Исправлено в версии 1.0.0.9.74.
Некорректный экспорт компонентов Android-приложения в приложении ASUS Router
Компонент, встроенный в Android-приложение ASUS Router (com.asus.aihome), был объявлен с android:exported="true" и без атрибута android:permission. Любое другое приложение на том же устройстве, не имеющее ни одного разрешения, могло отправить ему специально сформированный Intent и заставить приложение ASUS Router открыть подконтрольный атакующему URI от имени пользователя.
Сообщено в ASUS 2026-03-17. Исправлено компанией ASUS и опубликовано как CVE-2026-12960 2026-07-03.
Обнаружено и сообщено Седриком Луиссентом из Show Up Show Out Security.
| CVE | CVE-2026-12960 |
| Продукт | Приложение ASUS Router для Android (com.asus.aihome) |
| Затронуто | ≤ 1.0.0.9.71 |
| Исправлено в | 1.0.0.9.74 |
| Слабость | CWE-926: Некорректный экспорт компонентов Android-приложения |
| CVSS 4.0 | 6.0 Средний 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 |
| Рекомендация производителя | https://www.asus.com/security-advisory/ |
| Протестировано на | com.asus.aihome 1.0.0.9.71 (Google Play), эмулятор Android 11 |
В приложение встроен Baidu Push SDK, в котором объявляется:
<service
android:name="com.baidu.android.pushservice.CommandService"
android:exported="true" />
Атрибут android:permission отсутствует, поэтому контроль доступа на уровне компонентов Android не срабатывает. Любое установленное приложение может вызвать startService() для этого компонента.
CommandService.onStartCommand() извлекает Parcelable PublicMsg из extra public_msg входящего Intent и передаёт его в handlePrivateNotification(), которая выполняет ветвление по полю mOpenType, заданному атакующим:
mOpenType | Поведение |
|---|---|
1 | startActivity(ACTION_VIEW, Uri.parse(mUrl)) с mUrl атакующего |
Ни отправитель, ни полезная нагрузка не проверяются. Поскольку итоговая activity запускается из собственных UID и процесса приложения ASUS, всё, что появляется на экране, выглядит так, будто пришло из доверенного приложения управления роутером, которое пользователь только что открыл.
По сути, в этом нет ничего специфичного для Baidu. SDK поставляет экспортированный компонент, приложение-хост наследует его, и заимствуется именно идентичность приложения-хоста.
PublicMsg, соответствующий раскладке полей целевого объекта.mOpenType = 1, а mUrl — в подконтрольный атакующему URI.CommandService. Разрешений не требуется, SecurityException не возникает.onStartCommand() → handlePrivateNotification().startActivity(ACTION_VIEW, Uri.parse(mUrl)) запускается из процесса приложения ASUS.Порядок полей PublicMsg, восстановленный из writeToParcel в декомпилированном smali и повторно реализованный в 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
Ошибитесь в порядке — и Parcel распакуется в мусорные данные. Сделайте всё верно — и сервис примет сообщение так, будто его отправила собственная push-инфраструктура Baidu.
Шесть URI-схем, один экспортированный сервис, ноль разрешений:
media/poc_commandservice.mp4 — полная 31-секундная запись: сборка, установка, запуск и реакция эмулятора на каждую полезную нагрузку по очереди.
| Атака 1: фишинговая страница | Атака 2: редактор SMS | Атака 3: приложение набора номера | Разрешения PoC-приложения |
|---|---|---|---|
![]() |
Этот последний скриншот — и есть весь аргумент. Ни одного запрошенного разрешения. Приложение, которое только что выполнило шесть действий через приложение ASUS Router, вообще ничего не попросило у пользователя.
Требуются ADB, JDK и инструменты сборки Android SDK (aapt2, d8/dx, zipalign, apksigner), а также platforms;android-30.
./poc/poc_commandservice_exploit.sh <device_serial>
Скрипт выполняет три фазы:
CommandService из com.android.shell и сообщает, было ли отклонено хоть одно из них. Защищённый разрешением сервис выбросил бы здесь SecurityException. Этот принял все три.exploit_commandservice.apk и устанавливает его. Готовая копия лежит в poc/, если хотите пропустить этот шаг.Вывод фазы 1 на уязвимом устройстве:
[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
А также ServiceRecord из dumpsys activity services, в котором фиксируется вызывающий:
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
Фаза 3 — из реального непривилегированного приложения, а не из 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() вернул целевой ComponentName вместо null, а SecurityException выброшено не было. Android разрешил Intent и доставил его.
poc/
poc_commandservice_exploit.sh Automated three-phase reproduction script
ExploitCommandService.java PoC activity + broadcast receiver source
PublicMsg.java Parcelable matching the target's field layout
AndroidManifest_PoC.xml PoC manifest (note: no <uses-permission>)
exploit_commandservice.apk Prebuilt PoC, debug-signed, zero permissions
media/
poc_commandservice.mp4 Full PoC recording
attack1-browser.jpg Stills pulled from the recording
attack2-sms.jpg
attack3-dialer.jpg
poc-app-no-permissions.jpg
vendor/
asus-security-advisory-submission.pdf The report as filed with ASUS
Исходящий URL в PoC — это поддомен Burp Collaborator, с помощью которого подтверждалось, что переход действительно произошёл. Он давно не работает. Если воспроизводите атаку, подставьте свой.
Для производителя исправление — один атрибут:
<service
android:name="com.baidu.android.pushservice.CommandService"
android:exported="false" />
Либо, если компонент действительно должен быть доступен извне, защитите его разрешением с уровнем защиты signature и проверяйте десериализованный PublicMsg перед тем, как выполнять действия на его основе. ASUS выпустила исправление в версии 1.0.0.9.74.
Для пользователей: обновите приложение ASUS Router до версии 1.0.0.9.74 или новее.
Для всех остальных, кто выпускает Android-приложения: проверяйте, какие компоненты экспортируют ваши сторонние SDK. Выполните aapt dump xmltree base.apk AndroidManifest.xml для собственной релизной сборки и прочтите в ней каждый exported="true". Манифест, который вы поставляете, — это сумма всех объединённых манифестов, и вы отвечаете за него целиком.
| Дата | Событие |
|---|---|
| 2026-03-17 | Сообщено в ASUS с PoC APK, автоматизированным скриптом и видео |
| 2026-06-23 | CVE-2026-12960 зарезервирован ASUS как CNA |
| 2026-07-03 | CVE опубликован; исправление доступно в версии 1.0.0.9.74 |
| 2026-07-25 | Опубликованы публичный разбор и PoC |
Опубликовано после скоординированного раскрытия и выпуска исправления производителем, в защитных и образовательных целях. PoC нацелен на пропатченную версию и не делает ничего, кроме открытия URI. Не запускайте его на устройствах, которыми вы не владеете или на тестирование которых у вас нет письменного разрешения.
2 | Intent.parseUri(mPkgContent, 0) с последующим startActivity() / sendBroadcast() |
| # | Схема | Результат |
|---|
| 1 | https: | Браузер открывает фишинговую страницу, контролируемую атакующим |
| 2 | sms: | Редактор SMS предзаполнен сообщением для социальной инженерии |
| 3 | tel: | Приложение набора номера предзаполнено номером, контролируемым атакующим |
| 4 | mailto: | Редактор электронной почты предзаполнен для кражи учётных данных |
| 5 | market: | Перенаправление в Play Store для установки вредоносного ПО |
| 6 | geo: | Перенаправление в Карты на поддельный сервисный центр |
![]() |
![]() |
![]() |