[Update: Second Vulnerability Patched] Two Critical OnePlus 3/3T Bootloader Security Flaws Discovered, One Patched and Other being Addressed

[Update: Second Vulnerability Patched] Two Critical OnePlus 3/3T Bootloader Security Flaws Discovered, One Patched and Other being Addressed

We may earn a commission for purchases made using our links.

Since this article was published, Oxygen OS version 4.0.3 has patched the second security vulnerability discussed in this article, namely the dm-verity one.

Before entering the wonderful world of Android rooting, custom ROMs, kernels, and other modifications, you first have to unlock the bootloader on your device.

On some devices (especially carrier branded ones), this poses a problem as users have to deal with significant technical hurdles before they can unlock the bootloader. Other devices such as Huawei phones require you to petition the OEM for a unique bootloader unlocking code – a minor barrier to entry, but not very difficult. Even better are the Google Nexus/Pixel series or OnePlus phones that only require you to tick an option in Developer Settings then send a few fastboot commands.

But no matter how difficult it may be to unlock your bootloader, one thing will always remain constant: the requirement to wipe the device upon unlocking. This is done for obvious security reasons, as your entire data partition can be easily extracted once the bootloader is unlocked. A malicious entity (with the technical know-how) could flash boot a custom recovery and extract a full backup of your device if they gain access to your data. That’s why unlocking your bootloader is considered a security risk, and is why your device is wiped after unlocking it. Assuming that everything goes as it should, a regular user should be safe from attackers unlocking the bootloader to bypass the standard Android lock methods. Not everything goes according to plan, however.


OnePlus 3/3T Bootloader Unlocking Vulnerability

A new set of vulnerabilities was just disclosed by Roee Hay (@roeehay), the first of which allows for the OnePlus 3/3T’s bootloader to be unlocked without user confirmation and without triggering a factory reset. This vulnerability, labeled CVE-2017-5625, is considered a critical severity vulnerability and it affects all OnePlus 3/3T devices running on OxygenOS 3.2-4.0.1. Users who have already upgraded to the incremental OxygenOS 4.0.2 update are not affected by this vulnerability, as Mr. Hay privately disclosed this flaw to OnePlus on January 23rd so they could patch the issue immediately.

The flaw works by sending a proprietary, hidden fastboot command: fastboot oem 4F500301. By sending this command, the user’s bootloader lock state is bypassed (even when “Allow OEM Unlocking” has not been enabled in Developer Settings). The device does not prompt the user nor does it wipe the device as it should be – in fact, the device will still report that the bootloader is locked! Another fastboot command, fastboot oem 4F500302, will reset some bootloader settings, and can be used to lock an already unlocked device.

Mr. Hay discovered that the first fastboot command sets what he has dubbed a “magicFlag” which overrides the check which determines the bootloader’s lock state when performing a flashing or erasing command.

// 'oem 4F500301' handler
int sub_918427F0()
{
  magicFlag_dword_91989C10 = 1;
  if ( dword_9198D804 != dword_9198D804 )
    assert(1, dword_9198D804, dword_9198D804);
  return sendOK((int)"", dword_9198D804);
}

Fastboot Flash Handler


// 'flash' handler
const char *__fastcall sub_91847EEC(char *partitionName, int *a2, int a3)
{
  char *pname; // [email protected]
...
  pname = partitionName;
  v4 = a2;
  v5 = a3;
  if ( returnTRUE1(partitionName, (int)a2) )
  {
    result = (const char *)sub_918428F0(pname, v6);
    if ( (result || magicFlag_dword_91989C10)
      && ((result = (const char *)sub_91842880(pname, v10)) != 0 || magicFlag_dword_91989C10) )
    {
      result = (const char *)sub_918428F0(pname, v10);
      if ( !result || magicFlag_dword_91989C10 )
        goto LABEL_7;
      v8 = dword_9198D804;
      if ( dword_9198D804 != dword_9198D804 )
        goto LABEL_28;
      v11 = "Critical partition flashing is not allowed";
    }
    else
    {
      v8 = dword_9198D804;
      if ( dword_9198D804 != dword_9198D804 )
        goto LABEL_28;
      v11 = "Partition flashing is not allowed";
    }
    return (const char *)FAIL2((int)v11, v10);
  }
LABEL_7:
  ...
    if ( *v4 != 0xED26FF3A )
    {
      if ( *v4 == 0xCE1AD63C )
        cmd_flash_meta_img(pname, (unsigned int)v4, v5);
      else
        cmd_flash_mmc_img(pname, (int)v4, v5);
      goto LABEL_10;
    }
    v7 = v4;
  }
  cmd_flash_mmc_sparse_img(pname, (int)v7, v5);
  ...
 }

Fastboot Erase Handler


// 'erase' handler
int __fastcall sub_91847118(char *partitionName, int a2, int a3)
{
 ...
  v3 = partitionName;
  v4 = returnTRUE1(partitionName, a2);
  if ( !v4 )
  {
LABEL_7:
    ...
    if ( v4 )
    {
      if ( dword_9198D804 == dword_9198D804 )
        return eraseParition(v3);
    }
    ...
  }
  v4 = sub_918428F0(v3, v5);
  if ( !v4 && !magicFlag_dword_91989C10 )
  {
    v6 = dword_9198D804;
    if ( dword_9198D804 == dword_9198D804 )
    {
      v7 = "Partition erase is not allowed";
      return FAIL2((int)v7, v5);
    }
    goto LABEL_23;
  }
  v4 = sub_91842880(v3, v5);
  if ( !v4 && !magicFlag_dword_91989C10 )
  {
    v6 = dword_9198D804;
    if ( dword_9198D804 == dword_9198D804 )
    {
      v7 = "Partition flashing is not allowed";
      return FAIL2((int)v7, v5);
    }
LABEL_23:
    assert(v4, v5, v6);
  }
  v4 = sub_918428F0(v3, v5);
  if ( !v4 || magicFlag_dword_91989C10 )
    goto LABEL_7;
  v6 = dword_9198D804;
  ...
  v7 = "Critical partition erase is not allowed";
  return FAIL2((int)v7, v5);
}

CVE-2017-5626 can be used to execute kernel code. An attacker can flash any boot image they want. Though, if they flash a modified boot image Verified Boot will kick in and warn the user that a modification has been detected. One way that this can be bypassed is to flash an older, unmodified boot image – one that contains older exploits which have since been patched. Even so, the “warning” that you are given only lasts for 5 seconds, and it automatically dismisses itself and boots into the verifiedboot state where the attacker’s code will still execute.

Mr. Hay mentions that there are a ton of ways that this flaw can be exploited in a malicious manner. For instance, he modified a boot image to set the SELinux mode to permissive as well as automatically include ADB access on boot. Then, after exploiting this vulnerability to flash his modified boot image, he was able to access a root shell before the user can even enter their credentials.

OnePlus3:/ # id
uid=0(root) gid=0(root) groups=0(root),1004(input),1007(log),1011(adb),
1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),
3003(inet),3006(net_bw_stats),3009(readproc) context=u:r:su:s0

OnePlus3:/ # getenforce
Permissive

Needless to say, this is fairly serious. A stolen or bricked device that you think is safe because of your typical security measures can be completely defeated using this exploit.


OnePlus 3/3T SELinux Vulnerability

The second vulnerability, labeled CVE-2017-5624, affects all versions of OxygenOS and allows one to disable dm-verity. Mr. Hay disclosed this vulnerability to the OnePlus Security team on January 16th, but it should be noted that XDA Senior Member th3g1z independently discovered this vulnerability on January 23rd. We have spoken to OnePlus who have confirmed that they have acknowledged and will fix this second vulnerability in a future update.

This attack is also fairly simple to perform. One only needs to issue a single fastboot command to disable (or enable) dm-verity: fastboot oem disable dm-verity. To enable it, simply issue fastboot oem enable dm-verity. The handler for this command, taken from a dump of the bootloader, is shown below.


// 'oem disable_dm_verity' handler
int sub_9183B8EC()
{
  int v0; // [email protected]
  int v1; // [email protected]

  dmVerity_dword_91960740 = 0;
  v0 = sub_91845E10("ANDROID-BOOT!");
  if ( dword_9198D804 != dword_9198D804 )
    assert(v0, v1, dword_9198D804);
  return sendOK((int)"", v1);
}

Issuing this command will set a flag, which Mr. Hay calls dmVerity, which is used by the bootloader to send a kernel command line argument which can enable or disable dm-verity.

This can be used in combination with the first vulnerability to execute highly privileged code on the OnePlus 3/3T without user consent – and with access to the user’s data. For instance, Mr. Hay was able to install an application to /system/priv-app which causes the application to be added to the priv-app domain. This allows a malicious application access to highly privileged functions on the device. Mr. Hay demonstrates both of these vulnerabilities being exploited simultaneously in the video below. As you can see, when he boots the device the application he built is shown to be already pre-installed.


Conclusion & Note from OnePlus

The potential abuses of these two security vulnerabilities is frightening. We commend Mr. Hay for disclosing these vulnerabilities privately and so quickly to OnePlus. Still, we can’t help but be alarmed that such fastboot commands are accessible on these devices. When we wrote a guide on how to discover hidden fastboot commands, our intention was to inform users that there may be some interesting commands they can use to enhance their experience. Never did we think that such highly privileged commands would be sitting in the bootloader code. As for “why” these fastboot commands are included in the firmware, we were given a “no comment.” 

For now, if you haven’t been updating your OnePlus 3/3T as soon as each Oxygen OS build has been released, we recommend you update immediately. Updating to Oxygen OS 4.0.2 will shield you from the first vulnerability, but we’ll have to wait until OnePlus rolls out an update that patches the second vulnerability before we can say you’re fully safe from these exploits. We’ll have to keep on the lookout for these kinds of exploits in the future.


Source: Roee Hay