Tag Archives: cryptocurrency

The software security argument why Ledger Recover is a security risk

Introduction

Ledger has rolled out a “feature” where users can store their Ledger Nano seed-phrase remotely against a payment of $10/month. The feature allows for extracting an encrypted seed-phrase of cryptocurrency outside the hardware wallet! This has led to too much controversy. Some people think it’s the cool thing to give Ledger a break after endangering people’s money to make money off its users. Besides that ledger admitted that a government Subpoena can lead to handing over cryptocurrency to government with this feature, there’s a technical argument why this is inexcusable.

It’s attractive to just say “I’m outside the hive-mind, and hence ledger did nothing wrong, or that the security model is unchanged”, but this misses the whole point of why Ledger Recover is a problem, from a software security point of view.

As a software engineer who deals with systems programming languages, there are lots of misconceptions about this whole debacle. Even the former Ledger’s chairman seems to skip this point and claim it’s just a trust issue. I’d like to explain the nuance as an expert who dealt with these issues and worked in this field for 15 years.

It’s not about trusting or not trusting ledger

Even if we trust ledger 100%, the problem I’m about to describe isn’t related to that. The problem is: We’re all humans, and human software engineers all do the same mistakes… we have over 50 years of experience in that.

All software has bugs, and that’s the problem

Over the course of humanity writing software, we learned how bugs happen, how bugs appear in the code, and how little control we have over them. The ledger software is most likely written in C, which is the language that’s most vulnerable to these kinds of issues. If you’d like to see how dumb, little bugs can lead to compromising the whole machine, I recommend PwnFunction’s video “Dangerous Code Hidden in Plain Sight for 12 years”. It’s an 18 minutes video with a great example in Linux and how a dumb mistake lead to exploits in Linux, including unprivileged root access. Doesn’t matter how arrogant software engineers are, they do dumb mistakes, because they’re human. We all do.

This problem is so bad, that there’s a (relatively) new programming language that advertises that it solves lots of the memory issues that programming languages like C and C++ easily allow. It’s called Rust, you probably heard about it. It’s not a silver bullet, but it tries to solve most of these issues… and we’re not done yet with this problem. That’s a topic for another day.

But how can an attacker exploit Ledger Recover?

We don’t know, and that’s the scary part. If we knew, we would’ve fixed it, right? But I’ll give you an introduction into how these bugs happen and how they’re exploited.

Here’s an example in the next section… in a nutshell, without going into too much details.

Programs are dumb counters, and bugs allow hackers to exploit them

When you start a program (whether in Ledger or on your PC or otherwise), the operating system maps your program to memory, and runs what’s called a Program Counter. The program is just a dumb counter that is incremented. If your system is 32-bits (CPU instructions are 4-bytes wide), and your program is mapped to start at byte number 10000 in the memory array, then the counter simply is incremented on every instruction: 10000, then 10004, then 10008, then 10012, etc. And on every increment, the CPU reads the instruction in memory and executes the instruction in there.

(for the “actually” people, I’m leaving out tons of details such as caching… but let’s keep this simple).

In all CPU architectures, there’s an instruction called the “jump” instruction. The jump instruction gives the CPU a new address in memory to “jump” to, where the program counter changes its value, so that different code is executed, like in conditional statements… “if this is larger than that, do this, or do that”.

Functions and jumps + bugs = disaster

A function, in programming, is defined as a group of instructions/functionality that’s grouped in one place in memory (again, simplification). This is one of the jobs of a jump instruction… to do “function calls”, and run a group of instructions when necessary.

What can happen is that a software has something called a buffer-overflow bug. Buffer-overflow basically gives the program access to other sections in memory it’s not supposed to access. This is, kind-of, the main cause of problems in C programming.

If you’re old enough in Cryptocurrency, remember when EOS had a bug that was discovered by a security company that allowed for remote code-execution? That was a buffer-overflow.

If a hacker discovers a buffer overflow, they can write jump instructions, for example, to force the program to call functions it’s not supposed to call… say… call the function that extracts the seed-phrase and pass it through USB? Or maybe skip the encryption function and make it an identity function that does nothing? That’s the problem.

“It’s a new attack vector”

When Ledger writes a function in the firmware that extracts the seed phrase, they basically gifted all hackers a function they can try to reverse-engineer, and see if they can abuse it due to some bug a ledger engineer created, just like all humans have been writing bugs for the last 50 years. That’s why people are saying “it’s a new attack vector”.

To Ledger staff: You’re not gods. You’re humans. Just like us. We all write bugs, and you’re not an exception.

That’s why a firmware without this functionality at all is valuable.