Ledger HW.1 & Nano Security Keycard Bypass

Niv Yehezkel
5 min readJul 6, 2022

--

Ledger HW.1 / Nano is a hardware device that securely stores private keys for various blockchains including Bitcoin and Ethereum.

While working with one of our high-net worth partners, I recently had access to one of those devices and unfortunately, our partner lost the security keycard so he was unable to sign transactions.

In order to help our partner, I went on a small side project searching for a bypass for that security keycard to retrieve his funds. During so, I discovered a vulnerability in these devices (applicable to Ledger HW.1 and Nano) that bypasses the security keycard challenge when signing transactions. I thought of sharing the story and findings, also if it can help others retrieve their funds.

It is important to mention that this vulnerability only exists on Ledger HW.1 and Ledger Nano and not on newer ones (Nano X / S Plus / S).

Before diving into the details of the vulnerability, a brief explanation of how Ledger HW.1/Nano works –

The Ledger HW.1 / Nano devices are powered through USB and run Ledger’s OS to protect the user’s private keys.

These devices are set up using a Chrome App that is deprecated — this app was used to set up the device while also acting as a Bitcoin wallet. Today, this app is not needed for already set up Ledgers as Electrum and various other Bitcoin wallet apps also support these devices.

I had a test Ledger HW.1 which was not set up so I found the Chrome App on GitHub and installed it on an old Chrome version so I could set up the test Ledger and start playing around with it.

Another two small cards that are accompanied to the Ledger and must not be lost are the Recovery Card and the Security Keycard:

The security keycard in this picture is the card in the bottom-left containing letters and numbers that are used for signing transactions as a second layer of authentication.

The recovery sheet contains a barcode with a 16-byte long recovery phrase for the security keycard and is intended to be used in case the keycard gets lost.

When you open the Ledger, you must enter a 4-digit pin code in order to open it. Entering the wrong code 3 times erases the Ledger so that’s another factor that must not be lost or forgotten.

After you open the Ledger using the pincode, you are only able to view the public keys it holds but not transact.

When you transact, there is an additional 2FA challenge before the Ledger agrees to sign the transaction:

In this part — you have to match each character shown in bold to the matching character in the security keycard.

According to the docs, after 30 failing attempts to do so — the Ledger erases itself.

That means losing the security keycard or the recovery sheet also means losing the funds. As mentioned, our partner lost the security keycard and the recovery sheet and thus could not access the funds on the Ledger.

I then learned how the 2FA worked — the recovery sheet contains a seed which is a 16-bytes long seed that is used to generate the security keycard.

Using webarchive, I saw the code for how the keycard seed is used to generate the security keycard (view-source): https://web.archive.org/web/20210115165928/https://www.ledgerwallet.com/wallet/keycard

The way it derives the keycard is that 16-byte random is used as a key to DES-CBC which then encrypts all characters from 0x0 to 0x50.

Then, each encrypted character is matched to a character shown on the keycard.

After digging some more in the docs of the Ledger USB protocol, I found this interesting function that was not used in any GitHub repo I have seen (and particularly not in the official btchip-python GitHub): https://ledgerhq.github.io/btchip-doc/bitcoin-technical.html#_set_user_keycard

This function says that it is able to set a new keycard only after you successfully send a response to a challenge using the previous keycard.

The challenge is essentially a 4-byte that you have to respond with the right 4 characters in the security keycard.

The thing is that each character in the security keycard is translated into a 4-bit output (0–9, a-f). So for that 4-byte challenge (for four characters in a-z, A-Z, 0–9 letters), you would have to answer a 16-bit response (as each letter is translated into the encrypted 4-bit and we have 4 letters as a challenge)

The vulnerability in this function is that it allows you to issue the command as many times as you want without erasing the chip if failing to respond with the right challenge. Also, since the response is only 16-bit — we can enumerate possible responses. With only 16-bit to enumerate, we’d have an expectancy of 65536 attempts up until we’ll be successful in answering the right response.

As a matter of fact, since characters in the challenge can repeat, it means that the expectancy is that even after less than 65535 attempts we should be able to guess the right response.

Another vulnerability that exists in this function is that this function is susceptible to a timing-based attack that can reduce the time it takes to send a right response even further.

Since the ledger checks the response to the challenge byte-by-byte, monitoring the time it takes to check a response enables an attacker to figure if he got the first character right, and then the second and so on. Revealing the right response byte-by-byte reduces the number of attempts requires to bypass the 2FA down to approximately 4*256 or 1024 in an ideal setup.

For us to be able to enumerate, after sending a bad response to a challenge, this function requires us to power cycle the device in order to try again.

In order to programmatically restart the device I bought a Plugable USBC-HUB7BC device and used an open-source tool to power cycle the USB port.

It took me around 2 seconds for each iteration in the enumeration (w/o optimizing it or trying to make it any faster), and eventually, I managed in the course of a few hours to a day and a half to successfully reset the keycard seed and bypass the 2FA, multiple times.

You can find the official security bulletin in here.

Special thanks to Ledger for their professional cooperation throughout the process!

--

--