The McAfee Advanced Threat Research team (ATR) is committed to uncovering security issues in both software and hardware to help developers provide safer products for businesses and consumers. As security researchers, something that we always try to establish before looking at a target is what our scope should be. More specifically, we often assume well-vetted technologies like network stacks or the OS layers are sound and instead focus our attention on the application layers or software that is specific to a target. Whether that approach is comprehensive sometimes doesn’t matter; and it’s what we decided to do for this project as well, bypassing the Android OS itself and with a focus on the Peloton code and implementations. During our research process, we uncovered a flaw in the Android Verified Boot (AVB) process, which was initially out of scope, that left the Peloton vulnerable.
For those that are not familiar with Peloton, it is a brand that has combined high end exercise equipment with cutting-edge technology. Its products are equipped with a large tablet that interfaces with the components of the fitness machine, as well as provides a way to attend virtual workout classes over the internet. “Under the hood” of this glossy exterior, however, is a standard Android tablet, and this hi-tech approach to exercise equipment has not gone unnoticed. Viral marketing mishaps aside, Peloton has garnered attention recently regarding concerns surrounding the privacy and security of its products. So, we decided to take a look for ourselves and purchased a Pelton Bike+.
Attempting to Backup
One of the first things that we usually try do when starting a new project, especially when said projects involve large expenses like the Peloton, is to try to find a way to take a backup or a system dump that could be used if a recovery is ever needed. Not all of our research techniques keep the device in a pristine state (we’d be poor hackers if they did), and having the ability to restore the device to its factory settings is a safety net that we try to implement on our targets.
Because we are working with a normal Android device with only the Peloton customizations running at the application layer, many of the processes used to back up an Android phone would also work with the Peloton. It is common in the Android custom ROM scene to use a custom recovery image that allows the user to take full flash dumps of each critical partition and provides a method to restore them later. In such communities, it often also goes without saying that the device must first be unlocked in order to perform any of these steps. While the Android OS allows users to flash these critical partitions, there are restrictions in place that typically prevent an attacker from gaining access to the “currently” running system. If an attacker was able to get their hands on an Android device with the goal of installing a rootkit, they would have to jump through some hoops. The first step that an attacker would need to take is to enable “Original Equipment Manufacturer (OEM) Unlocking”, which is a user mode setting within the “developer options” menu. Even with physical access to the bootloader, an attacker would not be able to “unlock” the Android device unless this setting is checked. This option is usually secured behind the user’s password, PIN, or biometric phone lock, preventing an attacker from accessing it easily. The second security measure in place is that even with the “OEM Unlocking” setting on, issuing commands to the bootloader to perform the unlock first causes all data on the Android device, including applications, files, passwords, etc., to be wiped. This way, even if an attacker did gain access to the Android device of an unsuspecting victim, they wouldn’t be able to install a rootkit or modify the existing kernel without deleting all the data, which both prevents personal data from falling into the attacker’s hands and makes it obvious the device has been tampered with.
For this research effort, we resisted the urge to unlock the Peloton, as there are ways for apps to query the unlock status of a device within Android, and we wanted to ensure that any vulnerabilities we found weren’t the result of the device behaving differently due to it being unlocked. These discrepancies that arise from our research are usually identified by having two target devices: one to serve as the control and the other to serve as the test device. Unfortunately, we only had one Peloton to play with. Another issue was that the Peloton hardware is not very common and the developers of the aforementioned custom recovery images, like Team Win Recovery Project (TWRP), don’t create images for every device, just the most common ones. So, the easy method of taking a backup would not only require unlocking the device but also trying to create our own custom recovery image.
This left us as at a crossroads. We could unlock the bootloader and root the device, granting us access to the flash memory block devices (raw interfaces to the flash partitions) internally, which would allow us to create and restore backups as needed. However, as mentioned before, this would leave the bike in a recognizably “tampered” state. Alternatively, we could try to capture one of the bike’s Over-The-Air (OTA) updates to use as a backup, but we would still need to “unlock” the device to actually flash the OTA image manually. Both options were less than ideal so we kept looking for other solutions.
Android Verified Boot Process
Just as Secure Boot provides a security mechanism for properly booting the OS on Windows PCs, Android has implemented measures to control the boot process, called Android Verified Boot (AVB). According to Android’s documentation, AVB “requires cryptographically verifying all executable code and data that is part of the Android version being booted before it is used. This includes the kernel (loaded from the boot partition), the device tree (loaded from the dtbo partition), system partition, vendor partition, and so on.”
The Peloton Bike+ ships with the default settings of “Verity Mode” set to true, as well as “Device Unlocked” and “Device Critical Unlocked” set to false, which is intended to prevent the loading of modified boot images and provide a way to determine if the device has been tampered with. This information was verified by running
device-info on the Peloton, as demonstrated in Figure 1.
Figure 1: OEM device info showing verity mode and unlocked status.
To clarify, a simplified Android boot process can be visualized as follows:
Figure 2: Simplified Android Boot Process
If modified code is found at any of the stages in Figure 2, the boot process should abort or, if the device is unlocked, warn the user that the images are not verified and give the option to the user to abort the boot.
Given that we defined our scope of this project to not include the Android boot process as a part of our research and verifying that Peloton has attempted to use the security measures provided by Android, we again found ourselves debating if a backup would be possible.
In newer Android releases, including the Peloton, the update method uses Android’s Seamless System Updates (A/B). This update method no longer needs the “recovery” partition, forcing users who wish to use a custom recovery to use the
boot command which will download and boot the supplied image. This is a temporary boot that doesn’t “flash“ or alter any of the flash partitions of the device and will revert to the previous boot image on restart. Since this option allows for modified code to be executed, it is only available when the device is in an unlocked state and will error out with a message stating “Please unlock device to enable this command,” if attempted on a locked device.
This is a good security implementation because if this command was always allowed, it would be very similar to the process of booting from a live USB on your PC, where you can login as a root user and have full control over the underlying system and components.
Booting Modified Code
This is where our luck or maybe naïveté worked to our advantage. Driven by our reluctance to unlock the device and our desire to make a backup, we tried to boot a generic TWRP recovery image just to see what would happen. The image ended up leaving us at a black screen, and since each recovery image needs to contain a small kernel with the correct drivers for the display, touch digitizer, and other device–specific hardware, this was to be expected. What we didn’t expect, however, was for it to get past the
boot command. While we didn’t get a custom recovery running, it did tell us one thing; the system was not verifying that the device was unlocked before attempting to boot a custom image. Normally this command would be denied on a “locked” device and would have just errored out on the fastboot command, as mentioned previously.
It is also important to point out that despite having booted a modified image, the internal fuse had not been burned. These fuses are usually burned during the OEM unlocking process to identify if a device has allowed for a different “root of trust” to be installed. The burning of such a fuse is a permanent operation and a burnt fuse often indicates that the device has been tampered with. As shown in Figure 3, the “Secure Boot” fuse was still present, and the device was reporting a locked bootloader.
Figure 3: Secure boot enabled with fused protection
Acquiring an OTA Image
This discovery was unexpected and we felt like we had stumbled upon a flaw that gave us the ability to finally take a backup of the device and leave the Peloton in an “untampered” state. Knowing that a custom image could be booted even with a “locked” bootloader, we began looking at ways to gather a valid boot image, which would contain the correct kernel drivers to facilitate a successful boot. If we could piece together the OTA update URL and just download an update package directly from Peloton, it would likely contain a boot image that we could modify. Having the ability to modify a boot image would give us root and access to the blocked devices.
Even with just ADB debugging enabled we were able to pull the Peloton–specific applications from the device. We listed all the Peloton APKs and sought out the ones that could help us get the OTA path, shown in Figure 4.
Figure 4: Listing Peloton Specific Applications and Highlighting the one related to OTA Updates.
Finding the name OTAService promising, we pulled down the APK and began to reverse-engineer it using JADX. After some digging, we discovered how the app was building the download URL string for OTA updates, which would then be passed to
, as seen in Figure 5.
Figure 5: OTA image path being constructed as “key”
We also noticed quite a few Android log calls that could help us, such as the one right before the call to
(), so we used Android’s built–in logcat command and grepped the output for “OTA” as seen in Figure 6. Doing so, we were able to find which S3 bucket was used for the OTA updates and even a file manifest titled OTAConfig.json.
Figure 6: Relevant OTA logs in red
Combining the information obtained from OTAService.apk and the logs, we were able to piece together the full path to the OTA images manifest file and names for each OTA zip file, as shown in Figure 7.
Figure 7: Contents of OTAConfig.json
Our next step was to extract the contents of the OTA update to get a valid boot.img file that would contain all the specific kernel drivers for the Peloton hardware. Since the Peloton is using Android’s A/B partitions, which facilitate seamless updates, the update packages were stored in a “payload.bin” format. Using the Android payload dumper tool, we were able to extract all of the images contained in the bin file.
Modifying the Boot Image
Once the boot.img was extracted, we needed a way to modify the initial kernel to allow us to gain root access on the device. Although there are a variety of ways to accomplish this, we decided to keep things simple and just use the Magisk installer to patch the boot.img file to include the “su” binary. With the boot.img patched, we were able to use the
boot command again but this time passing it our patched boot.img file. Since the Verified Boot process on the Peloton failed to identify the modified boot image as tampered, the OS booted normally with the patched boot.img file. After this process was complete, the Peloton Bike+ was indistinguishable from its “normal” state under visual inspection and the process left no artifacts that would tip off the user that the Pelton had been compromised. But appearances can be deceiving, and in reality the Android OS had now been rooted, allowing us to use the “su” command to become root and perform actions with UID=0, as seen in Figure 8.
Figure 8: Booting modified boot.img and executing whoami as Root
As we just demonstrated, the ability to bypass the Android Verified Boot process can lead to the Android OS being compromised by an attacker with physical access. A worst-case scenario for such an attack vector might involve a malicious agent booting the Peloton with a modified image to gain elevated privileges and then leveraging those privileges to establish a reverse shell, granting the attacker unfettered root access on the bike remotely. Since the attacker never has to unlock the device to boot a modified image, there would be no trace of any access they achieved on the device. This sort of attack could be effectively delivered via the supply chain process. A malicious actor could tamper with the product at any point from construction to warehouse to delivery, installing a backdoor into the Android tablet without any way the end user could know. Another scenario could be that an attacker could simply walk up to one of these devices that is installed in a gym or a fitness room and perform the same attack, gaining root access on these devices for later use. The Pelobuddy interactive map in 9 below could help an attacker find public bikes to attack.
Figure 9: pelobuddy.com’s interactive map to help locate public Peloton exercise equipment.
Once an attacker has root, they could make their presence permanent by modifying the OS in a rootkit fashion, removing any need for the attacker to repeat this step. Another risk is that an attacker could modify the system to put themselves in a man-in-the-middle position and sniff all network traffic, even SSL encrypted traffic, using a technique called SSL unpinning, which requires root privileges to hook calls to internal encryption functionality. Intercepting and decrypting network traffic in this fashion could lead to users’ personal data being compromised. Lastly, the Peloton Bike+ also has a camera and a microphone installed. Having remote access with root permissions on the Android tablet would allow an attacker to monitor these devices and is demoed in the impact video below.
Disclosure Timeline and Patch
Given the simplicity and criticality of the flaw, we decided to disclose to Peloton even as we continue to audit the device for remote vulnerabilities. We sent our vendor disclosure with full details on March 2, 2021 – shortly after, Peloton confirmed the issue and subsequently released a fix for it in software version “PTX14A-290”. The patched image no longer allows for the “boot” command to work on a user build, mitigating this vulnerability entirely. The Peloton vulnerability disclosure process was smooth, and the team were receptive and responsive with all communications. Further conversations with Peloton confirmed that this vulnerability is also present on Peloton Tread exercise equipment; however, the scope of our research was confined to the Bike+.
Peloton’s Head of Global Information Security, Adrian Stone, shared the following “this vulnerability reported by McAfee would require direct, physical access to a Peloton Bike+ or Tread. Like with any connected device in the home, if an attacker is able to gain physical access to it, additional physical controls and safeguards become increasingly important. To keep our Members safe, we acted quickly and in coordination with McAfee. We pushed a mandatory update in early June and every device with the update installed is protected from this issue.”
We are continuing to investigate the Peloton Bike+, so make sure you stay up to date on McAfee’s ATR blogs for any future discoveries.