Porting Riscure 2016 CTF on Chipwhisperer
In 2015 I crowdfunded the Chipwhisperer-lite platform on Kickstarter which aims at providing a more or less generic but affordable glitching and side-channel attack platform. Since the campaign, the project has evolved and nowadays Chipwhisperer already has support for many platforms such as AVR, STMicro STM32 ARM processors, 8051, and even a small Intel x86 microcontroller. Adding support for a new processor will be part of an upcoming serie of articles on my blog, stay tuned! Although I owned that platform, I never got the chance to really play with it besides taking some of the straightforward tutorials and seeing that they work perfectly out-of-the-box.
I recently discovered a challenge that the company Riscure publishes every year called Riscure HackMe and more precisely its 2nd edition, RHME2016, including 3 challenges about side channel attacks where you had to recover an AES128 key in increasingly protected protected implementations. All the compiled firmware for those challenges are meant to run on an Arduino Nano board which uses the same microcontroller as the NOTDUINO kit that was included with my Kickstarter Chipwhisperer-lite.
Correlation power analysis
I’m not going to describe extensively what side channel attacks are as it would take too long. There’s a lot of literature on the topic if you’re interested to learn more. But to keep it simple, the idea behind a correlation power analysis, or CPA, is that there is a relationship between the current drawn by a microcontroller at each clock tick and the number of bits being set to 1 on its I/Os and/or registers, called Hamming weight. In order to attack an encryption algorithm and recover its key you need to find a point in time where a usable Hamming weight is leaked. Choosing this point should only depend on the encryption key bytes and on things that you know (constants, plaintext, etc.). Once you’ve found a fitting attack point, diversifying randomly the plaintext and capturing the matching consumption traces will enable you to perform a statistical attack on each individual byte of the key. This means that instead of attacking 2^128 possibilities through a traditional bruteforce attack, you can attack 16 times 8 bits in parallel! And even if you only partially recover the key, you may still crack the missing bytes by brute-forcing them.
I invite you to read more on attacking AES with CPA on the wiki of Chipwhisperer. The article about attacking TEA encryption algorithm is particularly good to understand how hard it could be to find the points of leakage for a given algorithm.
From Arduino Nano to NOTDUINO
Hardware modifications
As we cannot recompile the challenges due to missing source files, we need to check that the pins we need are available on the NOTDUINO board. By looking at the provided source excerpt for the easy challenge, Piece of SCAke, we know the trigger pin will be on pin B5 which, according to the NOTDUINO schematic, is typically used for SCK signal on the ISP port (pin 3 on the typical 6-pin AVR ISP header). This means we will have to use a jumper cable to wire pin B5 to the expected trigger pin. This is easy to achieve on the NOTDUINO board itself, connecting pin 3 of JP6 and pin 0 of JP3. I decided to use the Advanced Breakout board instead, having a wiring going from pin 3 of JP6 to pin 4 of JP4. This breakout board is very handy to protect the Chipwhisperer-lite thanks to its embedded level-shifters: Chipwhisperer doesn’t accept voltages above 3.3V and when wiring a target, it’s very easy to forget that and feed 5V into it, which would likely damage its FPGA.
Another big difference that we need to take care of is the clock: we need to make sure that the acquisition is happening precisely at each clock tick. The typical configuration is to have the Chipwhisperer generate the clock and feed it to the target chip. To put ourselves in the same conditions as the challenge, we need to add a 16MHz crystal and its associated pair of capacitors to the NOTDUINO board and have the Chipwhisperer sync on it. In order to get more flexibility, I decided to solder some female headers: this way I can choose to add or remove the crystal and the capacitors depending on what I want to have. By moving the jumper between JP8 and JP9 on the NOTDUINO, we can also choose whether we feed the clock from or to the Chipwhisperer.
The communication with the board is done through it’s serial port, which is exactly what the Chipwhisperer and the NOTDUINO are wired for. We don’t need to change anything here.
Fuses
Before being able to push a firmware to the chip, we need to program its fuses. The ATMega328 chip used on the NOTDUINO kit contains 4 fuses:
- The lockbit fuse (LOCK) protects memory regions. We don’t care about this one.
- The extended fuse (EFUSE) configures the brown-out detection. We don’t care about this one either.
- The high fuse (HFUSE) configures the boot address, the size of the boot area in flash as well as some other options. We would need to adjust this one if we wanted the NOTDUINO to behave like an Arduino Nano, which would imply pushing an Arduino bootloader on it. The only feature it provides is the ability to load the firmware through the serial port. Chipwhisperer has an embedded AVR program so we won’t touch this fuse.
- The low fuse (LFUSE) configures the clock source (internal RC, external quartz, etc.) as well as the s peed range and the time allowed to boot. This definitely needs to be adjusted in our case.
Chipwhisperer has its own integrated AVR programmer that can not only flash a firmware but also change the low fuse settings. This is exactly what we need, right? Wrong! After trying this approach at first, I spent quite some time figuring out that you need to download some extra files and manually change the firmware on Chipwhisperer before being able to flash a virgin ATMega chip due to clocking issues: by default Chipwhisperer goes too fast for a brand new ATMega chip as seen later. Everything is explained on the wiki, with links to the forum to guide you through the steps should you want to take that road (spoiler: it works). There is also a “Slow clock mode” button on the interface but regardless of what I tried, all it gave back to me was Python exceptions. I filed a bug and the Chipwhisperer team is going to have a look and hopefully fix that soon.
To program the fuses, I simply used an AVR-ISP-mk2 from Olimex.
However we encounter again an unexpected trap: the provided programming cable for AVR is a 10-pin header and you need to either buy their optional converter or use jumper wires to connect it to the NOTDUINO board. They also provide a 6-pin cable but it’s meant to program XMega chips and not ATMega! I personally think that this adapter should be included in the box instead by Olimex, instead of expecting people to realize it is missing.
Of course I could also have used my flash programmer here for the initial setup of the fuses.
First let’s use our AVR-ISP to read all the fuses from an Arduino Nano board:
$ avrdude -c avrispmkII -p m328p -U lock:r:-:h avrdude: Device signature = 0x1e950f (probably m328p) avrdude: reading lock memory: avrdude: writing output file "<stdout>" 0xcf avrdude: safemode: Fuses OK (E:FD, H:DA, L:FF)
It’s not easy to make sense of those fuses in their hex format but fortunately it’s pretty easy to find websites that will decode these values for you. The decoded configuration of the above low fuse is: External oscillator at 8MHz and above.
Let’s now put our new chip on the NOTDUINO board and read the fuses through our AVR-ISP, without connecting the Chipwhisperer yet (this implies configuring our AVR-ISP to power the target with 3.3V).
$ avrdude -c avrispmkII -p m328p -U lock:r:-:h avrdude: Device signature = 0x1e950f (probably m328p) avrdude: reading lock memory: avrdude: writing output file "<stdout>" 0xff avrdude: safemode: Fuses OK (E:FF, H:D9, L:62)
In comparison to our target, the chip is configured here for: Internal RC oscillator at 8MHz, divided internally by 8. This internal divider is the reason our Chipwhisperer cannot talk to the chip: the chip runs effectively at 1MHz and the Chipwhisperer cannot go that low to generate the programming clock.
It’s important to note here that we want the Chipwhisperer to synchronize its clock with the external crystal at 16MHz that we will mount on the NOTDUINO. If we keep the LFUSE set at 0xFF, this won’t work as we must choose the “Ext. Full Swing Crystal” option instead of “Ext. Crystal Osc.”, meaning programming LFUSE at 0xF7. Right after writing this value, we must put a crystal and the two associated capacitors on the NOTDUINO as well as move the jumper JP8 into JP9 in order to use the NOTDUINO.
$ avrdude -c avrispmkII -p m328p -U lfuse:w:0xf7:m avrdude: Device signature = 0x1e950f (probably m328p) [...] avrdude: safemode: Fuses OK (E:FF, H:D9, L:F7)
From now we should be able to use the Chipwhisperer to verify the fuses (but remember to disconnect the AVR-ISP before, especially if it is powering the board):
If anything goes wrong with the fuses, you may completely lose the ability to talk to the chip or to reprogram it. Don’t panic though, simply use a universal device programmer device to reprogram the fuses to a correct and known state. These devices know how to handle a chip that is in a bad state.
Firmware
Now that we’re done with the fuses, the next step is to flash a challenge. In order to do so, we need to configure the Chipwhisperer to synchronize on a 16MHz clock and lock the ADC to 4 times this clock signal:
Finally we will flash the challenge “Piece of SCAke” to ensure that we can capture traces later:
Software
The Chipwhisperer expects to talk to the target using the SimpleSerial protocol. This protocol is implemented in all provided firmware for targets they sell. It supports some very simple commands terminated by CRLF:
- “v” will answer with the version of the protocol (if supported otherwise after a timeout the software will assume version 1.0)
- “e” followed by a 32-byte string (16-byte hex-encoded) will answer with the hex-encoded encrypted version of the provided text
- “d” will work like “e” but for decryption (not supported with all firmware)
- “k” will set the encryption/decryption key
Riscure’s challenge only implements the “e” and the “d” commands followed directly by the bytes (no hex-encoding) and without the CRLF characters at the end. So we need to adjust Chipwhisperer to support that.
On his write-up, Balda quickly patched the SimpleSerial python implementation to cope with Riscure’s implementation but as we’re not under time pressure like in a CTF, we can just implement the protocol in a separated Python class.
My implementation can be found on Github. I copied the SimpleSerial.py file and modified it to remove unsupported commands but also to add a drop-down list of the 3 challenges with their expected keys. Selecting the challenge will take care of modifying all the relevant settings in the UI. For example, only the simple challenge provides a trigger on a pin. For the other two challenges we need to emulate it in software to start the capture. Note that these parameters might not be optimal, I still have to test and fine tune them for the medium (Still not SCAry) and the hard (eSCAlate) challenges.
Setting everything manually in the UI is a bit tedious so I also wrote another script for Chipwhisperer that will set everything up.
Putting things together
Now that we have all the required software modifications in place, we can wire and connect everything to the computer.
Here is the final setup I used with, from left to right, the Chipwhisperer, the Advanced breakout board and finally the NOTDUINO board:
You can clearly see on the above picture the trigger wire going from the NOTDUINO to the Advanced breakout board. This wire is only needed for the easiest challenge, Piece of SCAke, as the other challenges don’t provide a trigger signal.
Capturing traces works perfectly and we can check that the cryptography is working properly.
Finally, we can see that a first-order attack works perfectly on that target with less than 30 traces needed:
Next steps
Extending the Chipwhisperer software is not the best documented part of the project but that’s definitely something one should do as it is the best way to understand how the tool works. It’s also a good way to support this open-source project by issuing pull-requests once you have tested your modifications.
It’s also very nice to see companies like Riscure investing time and money to provide some very interesting challenges including shipping you the hardware platform! I was very excited to discover such challenge and even if I missed the 2017 edition pre-quals I hope I will have enough spare time next year to participate.
Finally you can expect to see more on this blog about the Chipwhisperer platform as I have a few more ongoing projects using this tool. As a teaser, one of my next software-related contribution that you see on my Github fork is to add the support of my Rigol DS4054 scope as an external capture device.
As always, don’t hesitate to leave comments and let me know what you think about this article.