On most unrooted, stock, Android phones, enabling tethering will run a “Provisioning Check” with your wireless provider to ensure that your data plan allows tethering. This post documents Tethr, a way to bypass the provisioning check on Android devices prior to version 7.1.2. After discovering this method I reported it to the Android bug bounty fixing the issue and receiving CVE-2017-0554.

Tethr Screenshot

Background

The ability to tether is controlled by your device’s build.prop file, usually located at /system/build.prop. The default is to require the provisioning check before enabling tethering, but it can by bypassed by adding the following line:

net.tethering.noprovisioning=true

Unrooted devices can’t edit /system/build.prop, so it is up to the ROM manufacturer to set this property. Some devices like the Google Nexus 6P default to net.tethering.noprovisioning=true. But this is an exception and not the norm. The Google Nexus 5X, Pixel, and Pixel 2 all perform provisioning checks.

Overview

When enabling tethering on Android, the OS will first do a provisioning check with the carrier to determine if the user’s plan allows tethering. If allowed, tethering is enabled, otherwise a message is displayed to the user.

If there is no sim card inserted then no provisioning check is performed, and tethering is allowed. Additionally, if tethering is enabled on a phone with no sim (not that this scenario would be of much use) and a SIM is then inserted, tethering is disabled as it should be.

However, if tethering is enabled while the radio is connecting, no provisioning check will be performed, and tethering will remain enabled after the radio connection is established.

The first issue I discovered is the ability for a user-installed application on a stock OS to reset the cellular modem. The second issue is the lack of a provisioning check once the cellular modem has finished reconnecting.

Together these bugs allow the Android OS to operate as if net.tethering.noprovisioning=true were specified in build.prop, even if it is not.

Tethr Demo

Before I dive into the details, observe the following video which demonstrates when enabling tethering in the Android system UI, a provisioning check is performed and tethering is not allowed. Then when using the Tethr demo app, the signal meter loses signal when the modem is resetting, and then tethering is successfully enabled.

Source code: github.com/lanrat/tethr

Compiled APK: Tethr.apk

Issue 1: Resetting radio via reflection

Java Reflection in Android can be used to allow application code to make calls to undocumented, or hidden APIs. This is not officially supported, and often strongly discouraged. It can however, allow app developers to do unsupported things, or in this case, bypass a permission check.

Resetting the cellular radio is performed in CellRefresh.java by calling CellRefresh.Refresh(). CellRefresh does a number of things to reset the cellular connection on most Android versions, but on Android 6+ the following reflections are used:

getSystemService(Context.TELEPHONY_SERVICE).getITelephony().setCellInfoListRate()
getSystemService(Context.CONNECTIVITY_SERVICE).mService.setMobileDataEnabled();

Older Android versions use the following reflections:

getSystemService(Context.CONNECTIVITY_SERVICE).mService.setRadio();
getSystemService(Context.TELEPHONY_SERVICE).getITelephony().disableDataConnectivity()
getSystemService(Context.TELEPHONY_SERVICE).getITelephony().enableDataConnectivity()

Solution

The methods used should require the application to have the system or privileged permissions.

Issue 2: Tethering provisioning check race condition

In order to exploit the race condition and bypass the tethering provisioning check an Android PhoneStateListener and AccessibilityService are used to programmatically enable the desired tethering mode at exactly the right time.

First the network is reset as described above. While the reset is being performed the PhoneStateListener (TetherPhoneStateListener.java) listens for when the cellular network is down and then starts the system’s settings tethering dialog where the AccessibilityService (TetherAccessibilityService.java) finds the correct UI switch and toggles it.

The AccessibilityService and PhoneStateListener are not strictly required for this exploit. The user can manually toggle tethering at the correct time to have the same effect. Automating the process with an AccessibilityService makes the process easier to reproduce.

Solution

The provisioning check should happen each time the radio is reset when tethering is enabled in addition to checking when enabling tethering.

Testing

Tested Wireless Carriers:

  • Verizon
  • AT&T

Tested phones (all stock, locked bootloaders, OEM OS):

  • Nexus 5X running Android 6.0.1
  • Nexus 5X running Android 7.0.0
  • Nexus 5X running Android 7.1.1
  • Samsung Galaxy S7 running Android 6.0.1

Untested but should also work on:

  • Pixel (XL)
  • Other non-nexus devices that perform a provisioning check

As the Nexus 6P already has net.tethering.noprovisioning=true set in its stock build.prop there is no need for this exploit.

Fixes

After submitting to the Android Bug Bounty Google created two patches for Android 7.1.2 which fixed this issue.

Patch 1: Added permission check for setCellInfoListRate

Patch 2: Fixed the logic for tethering provisioning re-evaluation

After fixing the issue Google was kind enough to give me a Pixel XL for reporting it to their bug bounty.

Tethr