
CVE-2026-12960 - ASUS Router 앱(com.asus.aihome)의 Android 애플리케이션 구성 요소 부적절한 내보내기. PoC, 익스플로잇 APK, 동영상 및 공급업체 보고서. 1.0.0.9.74에서 수정됨.
ASUS Router 앱에서 Android 애플리케이션 구성 요소의 부적절한 내보내기
ASUS Router Android 앱(com.asus.aihome)에 번들로 포함된 구성 요소가 android:permission 없이 android:exported="true"로 선언되었습니다. 같은 기기의 다른 앱은 권한이 전혀 없어도 조작된 Intent를 보내 ASUS Router 앱이 사용자를 대신하여 공격자가 제어하는 URI를 열게 할 수 있었습니다.
2026-03-17에 ASUS에 보고되었습니다. ASUS가 수정하여 2026-07-03에 CVE-2026-12960으로 공개했습니다.
Show Up Show Out Security의 Sedric Louissaint가 발견하고 보고했습니다.
| CVE | CVE-2026-12960 |
| 제품 | Android용 ASUS Router 앱 (com.asus.aihome) |
| 영향 범위 | ≤ 1.0.0.9.71 |
| 수정 버전 | 1.0.0.9.74 |
| 약점 | CWE-926: Android 애플리케이션 구성 요소의 부적절한 내보내기 |
| CVSS 4.0 | 6.0 Medium 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가 번들로 포함되어 있으며, SDK는 다음을 선언합니다:
<service
android:name="com.baidu.android.pushservice.CommandService"
android:exported="true" />
android:permission 속성이 없으므로 Android의 구성 요소 수준 접근 제어가 실행되지 않습니다. 설치된 어떤 앱이든 이 서비스에 대해 startService()를 호출할 수 있습니다.
CommandService.onStartCommand()는 수신 Intent의 public_msg extra에서 PublicMsg Parcelable을 읽어 handlePrivateNotification()에 전달하며, 이 메서드는 공격자가 제공한 mOpenType 필드에 따라 분기합니다:
mOpenType | 동작 |
|---|---|
1 | 공격자의 mUrl로 실행 |
발신자와 페이로드 모두 검증되지 않습니다. 결과 activity가 ASUS 앱 자체의 UID와 프로세스에서 시작되므로 화면에 표시되는 모든 것이 사용자가 방금 연 신뢰할 수 있는 라우터 관리 앱에서 온 것으로 보입니다.
실질적으로 이 문제는 Baidu에만 국한된 것이 아닙니다. SDK가 exported 구성 요소를 제공하고, 호스트 앱이 이를 상속하며, 도용되는 것은 호스트 앱의 정체성입니다.
PublicMsg Parcelable을 구성합니다.mOpenType = 1로 설정하고 mUrl을 공격자가 제어하는 URI로 설정합니다.CommandService에 전송합니다. 권한이 필요 없으며 SecurityException도 발생하지 않습니다.onStartCommand() → handlePrivateNotification().startActivity(ACTION_VIEW, Uri.parse(mUrl))가 실행됩니다.디컴파일된 smali의 writeToParcel에서 복구하여 poc/PublicMsg.java에 재구현한 PublicMsg 필드 순서:
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이 쓰레기 값으로 역마샬링됩니다. 순서가 맞으면 서비스는 마치 Baidu 자체 푸시 인프라가 보낸 것처럼 메시지를 수락합니다.
6가지 URI 스킴, 하나의 exported 서비스, 권한 0개:
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>
이 스크립트는 세 단계로 실행됩니다:
com.android.shell에서 세 가지 CommandService 액션을 보내 거부되는 것이 있는지 보고합니다. 권한으로 보호되는 서비스는 여기서 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
그리고 호출자를 기록하는 dumpsys activity services의 ServiceRecord:
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단계:
W PoCExploit: [OK] attack1_url_open → com.asus.aihome/com.baidu.android.pushservice.CommandService
W PoCExploit: [OK] attack2_sms_compose → ...
(all 6 succeed)
startService()는 null 대신 대상 ComponentName을 반환했고 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
PoC의 아웃바운드 URL은 탐색이 실제로 발생했는지 확인하는 데 사용된 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가 export하는 구성 요소를 감사하세요. 자신의 릴리스 빌드에 aapt dump xmltree base.apk AndroidManifest.xml을 실행하고 그 안의 모든 exported="true"를 확인하세요. 배포하는 매니페스트는 병합한 모든 매니페스트의 합이며, 그 모든 것에 대한 책임은 당신에게 있습니다.
| 날짜 | 이벤트 |
|---|---|
| 2026-03-17 | PoC APK, 자동화 스크립트, 동영상과 함께 ASUS에 보고 |
| 2026-06-23 | ASUS가 CNA 자격으로 CVE-2026-12960 예약 |
| 2026-07-03 | CVE 공개; 1.0.0.9.74에서 수정 제공 |
| 2026-07-25 | 공개 분석 문서(Write-up) 및 PoC 공개 |
조정된 공개(coordinated disclosure)와 공급업체 수정 이후 방어적·교육적 목적으로 공개되었습니다. PoC는 패치된 버전을 대상으로 하며 URI를 여는 것 외에는 아무것도 하지 않습니다. 소유하지 않았거나 테스트에 대한 서면 승인을 받지 않은 기기에서는 실행하지 마세요.
startActivity(ACTION_VIEW, Uri.parse(mUrl))2 | Intent.parseUri(mPkgContent, 0) 후 startActivity() / sendBroadcast() 실행 |
| # | 스킴 | 결과 |
|---|
| 1 | https: | 브라우저가 공격자가 제어하는 피싱 페이지를 엽니다 |
| 2 | sms: | SMS 작성기가 사회공학 메시지로 미리 채워집니다 |
| 3 | tel: | 다이얼러가 공격자가 제어하는 번호로 미리 채워집니다 |
| 4 | mailto: | 이메일 작성기가 자격 증명 유출용으로 미리 채워집니다 |
| 5 | market: | 악성코드 설치를 위한 Play Store 리디렉션 |
| 6 | geo: | 가짜 서비스 센터로 지도 리디렉션 |
![]() |
![]() |