Flash e-bike Part 7 (Cracking the code)
In part 1 of the series, I introduced the background of this particular exercise, and why we're embarking on it. I disassembled the bike and identified the major pieces of its systems in part 2. And in part 3 we looked at the mainboard, figured out what its primary components were, and how they worked. We reverse engineered the BMS, in particular the communication protocol, in part 4. In part 5, we discovered the make and model of the ESC, and figured out our plan for moving forward with the project. I was able to use the bike — as a bike — using the eggrider in part 6.
You might be asking what else there is to say about the flash. To that I say "shut up", but also "kind of a lot, actually". If you recall part 5, we had to get some sketchy windows software on a forum somewhere to program the electronic speed controller for the Eggrider. That kinda sucks, right? What if there was a way we could use some open source tool to program it instead?
Programming the ESC without BacDoor
As we've established, BacDoor uses ModBus to configure the ESC. Modbus is a well established and supported standard. What if we just ... implemented the register writes ourselves? It turns out that this is a completely trivial thing to do. I made a program in rust that will setup your speed controller for the Eggrider. It works on MacOS and Linux, and it probably works in windows, too.
Assuming you don't already have rust, you'd need to do the following steps (after hooking up the ESC to your computer, as loosely described in post 5):
|
That's really all there is to it. The program will set the necessary registers over Modbus and save the values to flash (that's what the -f
flag does.)
But what if it's locked?
There was one thing that got stuck in my head when I was reading about what registers had to be set for the Eggrider. What's up with that Flash parameter read access code
register? Why was it set to zero? Is it some kind of password? Intriguingly, ASI maintains a public knowledge base (even though they only want to work with OEMs) and they have an article about that. There are a few things in this article that are interesting.
Read lock prevents users from reading or modifying flash parameter values. Six parameters are used to control read access functionality in the BAC controller.
Ok, it's clear that this is a kind of password.
To remove or change Read Lock:
- Unlock the existing ‘Read Lock’ to enable reading/writing parameters.
- Change the Flash Parameter Read Access Code parameter(s) to your new desired value(s) to change the lock password, or set them all to 0 to disable/remove the feature.
- Save to flash.
- Power cycle the controller to update the read lock.
Ah... Ok. By setting Flash parameter read access code
to zero we unlock the registers so the Eggrider can function correctly.
But, what if you have an ESC that's locked? Are you screwed?
Cracking the access code
Turns out, no. The same knowledge base article gives us the possible range of values:
Enter a numerical integer code (-32,768 to 32,767) or 4-digit hex number(0-9, A-F) into one or more of the Flash Parameter Read Access Code parameters.
That's only 65534 possible values. This will not take a lot of time to brute-force.
Before we attempt it, though, it's probably a good idea to consider the consequences of trying this. The worst case scenario would be that they implement some kind of attempt counter and brick the device if you try too many times without succeeding. Or, less fatally, they could only let you attempt a certain number of times, but reset the counter upon power cycling.
I didn't want to brick my only ESC, and risk setting myself way back in the project. Also, at this point, my ESC was already installed in the bike. I thought to myself "I wonder if I can get one of these on eBay?" You absolutely can. It turns out that the assets from the Flash bike bankruptcy were purchased by someone in the bay area, and they're liquidating them on eBay. You can get a ton of Flash parts quite affordably.
With a new old stock ESC in hand, I went for it. There's nothing but good news. There is no attempt counter I can detect, and the response time for an attempt is fast enough that you can check all possible passcodes in less than an hour.
At this point, I decided to add the ability to brute-force crack the passcode to the program I wrote earlier. Cracking is likely necessary if the --eggrider
verb returns a failure when you try it, especially if it says:
Setting the assist source value failed (x != y).
Your ESC is likely locked.
The access code must be set on the command line if this is the case.
If you don't know the access code, you can try to crack it using this tool.
In this case, the --crack
verb is your friend:
It will run for a while, printing out a progress message after every 256 passcode attempts. Once it's complete, it will print the code you'll need for you. Let's say that code is 42, The output will be Found access code!: 42
. Now you can tell the program what the code is, and set the eggrider registers:
In the above command, the -a 42
is telling it what value to use to unlock the ESC, again -f
is telling it to write to flash, and --eggrider
sets the other registers.
User Access Level 1 granted
While researching all of this stuff, I came across another post on the knowledge base. In this one, they talk about another passcode, and another access restriction. This one, however, is a little different. In this case, the passcode isn't set by the user or OEM, it's set by ASI themselves, and it's provided to the OEM by their sales engineer.
I discovered that we can brute-force crack the user-provided passcodes, so can we crack this one?
Short answer: Yes.
It took me less time to add this feature to the program than it took the program to crack the code.
For my ESC, the code was 8684
.
Quick sidebar about threat modelling
Before we get up in arms about the poor security stance of the ESC, and how easy it was to crack these passcodes, let's briefly discuss my presumptions about ASI's threat modelling, and why I think they didn't bother implementing a more sophisticated system.
We have to first discuss why the passcodes even exist. Let's run down a partial list of typical things people are intending to protect when they implement access controls:
- Financial security
- data
- control
- instruments (i.e. money or investments)
- Information
- Personally-identifying
- health
- intimate
- Access to objects
- theft
- modification
Only one of these makes any sense at all. The simple answer is that it's a legal requirement to prevent modification of the ESC by the user. This is made clear in yet another knowledge base article. According to ASI, the passcodes are required to comply with ISO 13849. I'm not going to purchase the standard to back this up, but I'm pretty sure the standard expects you to protect access to safety-related parameters, while not providing any specific requirements for the specific implementation.
Going a little further, what's the upside to ASI for implementing security around these codes? There really isn't one. The worst case scenario is that some irritating person, like me, figured out that they haven't done a good job. That person could make a lot of noise about it, and potentially tarnish their reputation. I frankly don't think that's likely. If anything, it might make ASI controller more appealing because DIY'ers will be able to use them more effectively, and will purchase more of them.
Another worst case scenario would be someone setting a variable in a way such that they get themselves hurt. Again, I find this unlikely. Even if this were to happen, I suspect the argument "we implemented reasonable measures to prevent customers from being stupid, as required by the standard, and someone bypassed those measures to modify the system" would be compelling.
This is all to say that there's no upside to securing it better, and the risks to having minimal security are relatively low.
Independent discovery
After discovering the ability to brute-force these passcodes, and concerned with retribution from ASI, I decided to look harder for other people that may have done the same thing. I was able to find at least one other person (Xenodius) that had successfully implemented passcode brute-forcing in 2021, and published their tool in the Endless Sphere Forums.
The options pane has a button to brute-force unlock the access level codes of your controller, displaying them as they're unlocked and writing them to the controller and saving them to an 'access-codes.txt' file. Took about 90 minutes on my controller, max theoretical time is ~8 hours.
Wrapping up
Honestly, this effort was far, far, easier than I thought it would be. Frankly, I don't understand why it's necessary at all. The Eggrider should be able to set these registers on its own. Be that as it may, at least it's easy for us to do it on our own without BacDoor. Furthermore, it's no longer a problem if the ESC is locked.
I'm going to be at RustConf in New Mexico this week, and I may not get around to another post. I've done the research and experiments for it, so it is possible, but I may be too busy with travel to do anything else.
Let's check back on our list of next steps from the last post:
- Eliminate the need for BacDoor ✅
- people should be able to convert their bike to use the Eggrider without having to get sketchy windows-only software ✅
- Figure out whether it's possible to brute-force crack the parameter access codes of the ESC ✅
- Figure out the protocol used for the head and tail lamps 📆
- My bike has holes where the lamps used to be because they're still useless
- Ideally, I can use the existing, well-built, lamps for visibility and safety
- Figure out whether there's a bypass or brute-force method to the pin code used to "secure" the flash bike 💥
- Understand the binary protocol of the LCD
- Understand the I2C interface to the touchscreen digitizer
- Discover whether there's an attempt counter for the pin
- Figure out the duration of a pass code attempt
- There are only \(6^5\), or almost 8,000 possible pins
- If you can test a pin in less than 10 seconds, you could brute force them in less than a day
The "📆" emoji means that I've done the research for this task, and I'm planning it for the next post. The "💥" means that I've accidentally blown up my mainboard. I think I've found a replacement, but It'll be a while before I can get it.