BadRecovery (formerly OlyBmmer) is an exploit for ChromeOS devices, leveraging a vulnerability in recovery images to get arbitrary code execution or to chain to other exploits.
BadRecovery unenrolls ALL devices that are EOL before 2024, and can unenroll current supported devices on kernel version 3 or lower.
The exploit and writeup were released to the public on October 5th, 2024.
You can read the writeup here.
You will need:
First, you must download an official recovery image for your device. You can download them from ChromiumDash or Chrome100. See modes of operation for which version you'll need, usually r124 or older. Be sure you've downloaded the correct image for your device.
Make sure to unzip the recovery image before proceeding to the next step!
Next, you must modify the recovery image using the script included with this repository. You can use the web version of the builder, though it is a fair bit slower.
To get the script, run these commands on a linux machine:
git clone https://github.com/BinBashBanana/badrecovery
cd badrecovery
To modify a recovery image using the script, run
sudo ./build_badrecovery.sh -i <image.bin>
(Replace <image.bin> with the path to your recovery image bin.)
The script may prompt you to install required dependencies.
You can specify the mode using the --type
argument (-t
for short). If left unspecified, the script will automatically determine the best option based on the version and features of the recovery image.
Example:
sudo ./build_badrecovery.sh -i image.bin -t postinst
The script would fail if it detected that the supplied recovery image does not meet the requirements for postinst mode (see table below).
The recovery image is now modified, and is ready to be flashed to a USB drive or SD card.
First, enter recovery mode. See this article for detailed instructions.
IMPORTANT On the unverified payload, you must also enter developer mode, and then enter recovery mode again for BadRecovery to work. On Cr50 devices (most devices manufactured in 2018 or later), you must NOT be in developer mode for unenrollment to work. Ensure you are in verified mode recovery. In any other case, you can use either verified or developer mode recovery.
Plug in the prepared USB drive or SD card. On the unverified payload, BadRecovery will start in only a few seconds if you've done everything correctly.
On any other payload, the system will recover first. This may take a while depending on the speed of your drive. On postinst and postinst_sym payloads, BadRecovery will start partway through the recovery process.
NOTE If using postinst_sym and BadRecovery does not start, the path to the internal drive is incorrect.
On basic or persist payloads, reboot into verified mode after recovery completes. Optionally, you can look at VT3 and reboot early to skip postinst and save some time.
On the persist payload, BadRecovery will start within a few seconds of ChromeOS booting. On basic, you must proceed through setup and the device will unenroll using cryptosmite.
When BadRecovery finishes, you will usually be able to skip the 5 minute developer mode delay by immediately switching back into recovery mode to get to developer mode. (This is not required.)
Mode | Requirements | Description |
---|---|---|
postinst | 86 ≤ version ≤ 124 AND disk layout v1 or v2 | ROOT-A (usb) overflows into ROOT-A (internal). Not supported on disk layout v3 (devices with minios). Replaces postinst with a custom payload and grants code execution in recovery. |
postinst_sym | 34 ≤ version ≤ 124 AND (kernel ≥ 4.4 OR year < 2038) |
ROOT-A (usb) overflows into STATE (internal).
Stateful installer copies payload (usb) to a symlink in STATE (internal) which points to ROOT-A (internal).
Replaces postinst with a custom payload and grants code execution in recovery.
Caveat: internal disk device path must be known. |
persist | 26 ≤ version ≤ 89 (untested below 68) | ROOT-A (usb) overflows into STATE (internal). Encrypted data persisted through cryptosmite, code execution given in ChromeOS through crx-import. |
basic | 26 ≤ version ≤ 119 (untested below 68) | ROOT-A (usb) overflows into STATE (internal). Standard cryptosmite unenrollment payload. |
unverified | version ≤ 41 / version ≤ 47 (WP off) / any version (developer mode NOT blocked) | Unverified ROOT-A, developer mode only! Use this for very old devices or for testing. This is an intended feature, not a bug. |
R125 recovery images and newer are not vulnerable to this (except unverified). To determine if you can use this, follow these in order:
Big thanks to the testers: