This year the Donjon organized a Capture The Flag competition, where challengers had to solve many security-related challenges for three weeks. Now the competition is over, and it’s time for us to debrief!
This post is about the picoHSM challenge, which was a hardware challenge where reverse, exploitation and fault injection skills were necessary to get all the flags. In this blog post, we detail all the story behind this challenge and what problems we had to solve to make this possible. We won’t explain how to solve the challenge in details - for this, you might have a look at the excellent write-up from CryptoHackers.
In the Donjon, we love hardware, especially when dealing with side-channel or fault attacks, and we wanted to create an original challenge with real hardware to give a glimpse of those fields.
Performing fault injection usually requires a physical access to the targeted device. However, we wanted to demonstrate that such hardware attacks could eventually be performed remotely. Additionally, the advantage for us was that we could set up the challenge without sending hardware to the CTF players! Indeed, anyone registered to the CTF could try to break our precious boards at any time.
Obviously, we’re not the first to think about remote hardware attacks, as many publications have already shown (Plundervolt, ClkScrew, …), but still, we think our challenge was quite unusual for a CTF.
Building the story
Building a technical challenge for a CTF can be difficult, and making it realistic and immersive is even harder. We imagined a scenario in which a hardware engineer made a critical design mistake: to reduce the cost of a board, a crystal of a security processor has been removed, as the clock source of the main processor can be reused. Cost reduction indeed drives lots of design decisions in the hardware industry, and this may lead to critical side effects. Here this $1 cost reduction is smart and works pretty well, but from a security perspective this is a really bad decision… So here’s the big picture of this challenge:
- The board is connected to a network and provides data blob encryption and decryption as a service.
- The main processor can be compromised by exploiting a software vulnerability. However the sensitive secrets still remain somewhat safe as the secrets (PIN code and encryption keys) are held by the secondary security processor for better isolation…
- However, the main processor controls the clock of the security processor, and by modifying the clock parameters, the attacker can glitch the security processor in order to bypass security features!
Here was born the picoHSM!
Building the board
Once we had a good story, we needed to create the picoHSM boards. It is a lot of work, and there are lots of tiny important details to care about. The first one is choosing a good victim processor. From our experience at the Donjon, we know Atmel (now Microchip) ATMEGA devices can be clock-glitched, so we chose the ATMEGA1284P as the security processor.
Please understand that this is absolutely NOT a Secure Element. Secure Elements are protected against many hardware attacks. Not using a Secure Element is probably the first critical mistake the board designer made…
For the main processor, we chose the STMicroelectronics STM32F205 microcontroller. It features an ARM Cortex-M3 and is very easy to use. Mostly it is capable of routing it’s internal PLL output clock to an external PIN. That means it is able to drive the clock of the security processor, and even change its frequency on the fly.
Regarding the Ethernet connectivity, we selected the WIZnet W5500, an Ethernet chip embedding a TCP/IP stack. It makes easy the use of sockets from a SPI connection. Thanks to this component, we did not have to care much about the network, and this also means the TCP/IP stack won’t be in the STM32 processor binary, reducing the attack surface and probably making reverse for the challengers much easier!
The board has been designed and routed from scratch using the excellent KiCad software. We then produced 15 PCB from Eurocircuits, and as time was running up we decided to solder them ourselves to reduce delays, and hopefully be ready for the beginning of the CTF! The very last board has been soldered the day before…
PCB design with KiCad
Adjusting the difficulty
Performing fault injection remotely by executing a shellcode on a device with no debugging is for sure a difficult task. We did not want this challenge to be too frustrating, and we decided to divide it in three progressive steps, so challengers can still have fun and be rewarded points, even if they don’t manage to do the most difficult last step…
Step 1 - picoHSM Speed Dating
In this step, a buffer overflow vulnerability has to be found and exploited. We made the vulnerability really obvious, and the main difficulty was to write a shellcode and test it blindly. We even gave the symbols in the provided ELF file to make reverse engineering easy. Many challengers had a very hard time exploiting this very basic vulnerability. Actually, three difficulties were met most of the time:
Some ignored that the stack was executable, and considered doing ROP without trying shellcoding. This works well for the first step, but ROP is much harder for the second and third steps of the challenge as complex shellcodes must be written.
Targets run in ARM Thumb mode, and therefore jump addresses have to be odd. Some challengers tried to overwrite the link register with even addresses, leading to CPU crash and reset.
Many players did not find the initial stack pointer address, or assumed it was random… We don’t have any ASLR here!
$ arm-none-eabi-objdump -x release/firmware-mcu | grep stack 20002000 g *ABS* 00000000 stack_top
Step 2 - picoHSM Good Times
This step was an intermediate challenge, easier than the fault injection one. It was supposed to help setting up a good shellcoding toolchain for the target before jumping to something even more difficult. The vulnerability to exploit was a basic timing attack on a non-constant PIN verification routine performed by the security processor.
In the first place, we wanted to provide the firmware binary of the security processor. It turned out reversing AVR assembly was more difficult than we thought: lots of basic operation requires many instructions on a 8-bit processor, and there is not much (free) tooling available to disassemble AVR instructions other than avr-objdump… (Ghidra failed completely on our binary). So we decided to release the source code instead, but maybe it was too easy then.
Ghidra on the left / avr-objdump on the right
The first draft of this challenge was very difficult to exploit, as we observed the UART communication between the main processor and the security processor was introducing lots of jitter, and it was very difficult to observe timing differences between a correct digit and an invalid one. This jitter comes from the baudrate clock divider of the UART peripherals of both the STM32F205 and the ATMEGA1284P. By increasing the communication speed between the two microcontrollers to the maximum possible, we managed to reduce this jitter enough so the timing difference between a valid and a wrong digit can be observed with a single measurement. This way, a good shellcode should be able to recover all the 8 digits in a single execution.
Step 3 - picoHSM On Steroids
The most difficult part of this challenge! To glitch the ATMEGA1284P, we needed to provide a simple way to reconfigure the secure processor frequency. When studying the STM32F205 clock tree, we found out that the MCO1 clock divider was appropriate to quickly change the frequency without reconfiguring the PLL (which can be much slower as a PLL requires time to lock). With a system clock configured at 50 MHz, MCO1 output frequency can reach values from 10 MHz to 50 MHz, spanning across both valid and overclocking frequencies for the ATMEGA1284P.
One additional difficulty was to keep frequency settings compatible with the UART baudrate constraints to keep the timing attack of the step 2 possible!
Security processor operating frequency bounds - ATMEGA1284P datasheet on page 332
From external crystal, through system PLL, up to clock divider and MCO1 output...
Finally, we were wondering if challengers would discover they had to perform fault attacks for the very last step. Maybe we gave too many clues for this, as it was an obvious solution for all of the challengers.
Once they have exploited the software vulnerability of the main processor, players are able to run arbitrary code on the board. They most likely crash the boards when attempting to run exploits, and thus DoS our precious picoHSM… However, the challenge had to be available for 3 weeks! To solve this issue, we enabled the watchdog of the STM32 microcontroller, which resets the board after 15 seconds of unexpected activity. This is why a 15-second timeout message is displayed on the board welcome text…
But this is not enough! Exploits can purposely disable the watchdog. To tackle this, the boards were also reset regularly from our infrastructure through a USB debug port.
But this is not enough! Exploits can also rewrite the internal Flash memory, and modify / trap the challenge, or just brick the boards by writing trash in the firmware code itself (and from the discussions on our Discord channel, some have thought about it…). To limit this, the boards were also reflashed by the infrastructure every hour…
One more time, this is not enough! There was still a way the microcontrollers could be bricked forever… But we will keep that for us…
Finally, during the challenge, we encountered cases of crashed ATMEGA1284P which were not recoverable even after a hard reset. Fault injection can produce weird effects, and we did not anticipate this one. The only way to restore the boards stuck in such a state was to power cycle them - which requires a human intervention. Fortunately, that seldom happened.
A board being brute-forced... SEC LED blinking as the security processor gets reset...
Overall, the challenge worked well and was available all the time for the three weeks of the CTF. No boards died, though we’re not completely sure they now work 100% correctly… We know theses challenges frustrated some of you, but we know it also provided fun to many others! We want to particularly congratulate those who managed to successfully glitch the board!
Finally, we are releasing the hardware and software design of the picoHSM board in the CTF repository, so you can have a look at the C source code you tried to exploit!
And now we have to start thinking about next year’s challenges…