As of August 2020 the site you are on (wiki.newae.com) is deprecated, and content is now at rtfm.newae.com. |
Difference between revisions of "Tutorial A7 Glitch Buffer Attacks"
(→Bootloader Setup: Added build description) |
(→The Attack Plan) |
||
Line 58: | Line 58: | ||
= The Attack Plan = | = The Attack Plan = | ||
+ | Since we have access to the source code, let's take our time and understand how our attack is going to work before we dive in. | ||
+ | |||
== The Sensitive Code == | == The Sensitive Code == | ||
+ | Inside <code>bootloader.c</code>, there are two buffers that are used to store most of the important data. The source code shows: | ||
+ | <pre> | ||
+ | #define DATA_BUFLEN 40 | ||
+ | #define ASCII_BUFLEN (2 * DATA_BUFLEN) | ||
+ | |||
+ | uint8_t ascii_buffer[ASCII_BUFLEN]; | ||
+ | uint8_t data_buffer[DATA_BUFLEN]; | ||
+ | </pre> | ||
+ | This tells us that there will be two arrays stored somewhere in the target's memory. The AVR-GCC compiler doesn't usually try too hard to move these around, so we can expect to find them back-to-back in memory; that is, if we can read past the end of the ASCII buffer, we'll probably find the data buffer. | ||
+ | |||
+ | Next, the code used to print a response to the serial port is | ||
+ | <pre> | ||
+ | if(state == RESPOND) | ||
+ | { | ||
+ | // Send the ascii buffer back | ||
+ | trigger_high(); | ||
+ | |||
+ | int i; | ||
+ | for(i = 0; i < ascii_idx; i++) | ||
+ | { | ||
+ | putch(ascii_buffer[i]); | ||
+ | } | ||
+ | trigger_low(); | ||
+ | state = IDLE; | ||
+ | } | ||
+ | </pre> | ||
+ | This looks very similar to the example code given in the previous section, so it should be vulnerable to a glitching attack. The goal is to cause the loop to continue past its regular limit: <code>data_buffer[0]</code> is the same as <code>ascii_buffer[80]</code>, so a successful glitch should dump the data buffer for us. | ||
+ | |||
== Disassembly == | == Disassembly == | ||
+ | As a final step, let's check the assembly code to see exactly what we're trying to glitch through. Run the command | ||
+ | <pre> | ||
+ | avr-objdump -m avr -D bootloader.hex > disassembly.txt | ||
+ | </pre> | ||
+ | and open <code>disassembly.txt</code>. | ||
= Attack Script & Results = | = Attack Script & Results = |
Revision as of 10:09, 28 June 2016
This tutorial discusses a specific type of glitch attack. It shows how a simple printing loop can be abused, causing a target to print some otherwise private information. This attack will be used to recover a plaintext without any knowledge of the encryption scheme being used.
Contents
Background
This section introduces the attack concept by showing some real world examples of vulnerable firmware. Then, it describes the victim firmware that will be used in this tutorial.
Real Firmware
Typically, one of the slowest parts of an embedded system is its communication lines. It's pretty common to see a processor running in the MHz range with a serial connection of 96k baud. To make these two different speeds work together, embedded firmware usually fills up a buffer with data and lets a serial driver print on its own time. This setup means we can expect to see code like
for(int i = 0; i < number_of_bytes_to_print; i++) { print_one_byte_to_serial(buffer[i]); }
This is a pretty vulnerable piece of C. Imagine that we could sneak into the source code and change it to
for(int i = 0; i < really_big_number; i++) { print_one_byte_to_serial(buffer[i]); }
C compilers don't care that buffer[]
has a limited size - this loop will happily print every byte it comes across, which could include other variables, registers, and even source code. Although we probably don't have a good way of changing the source code on the fly, we do have glitches: a well-timed clock or power glitch could let us skip the i < number_of_bytes_to_print
check, which would have the same result.
How could this be applied? Imagine that we have an encrypted firmware image that we're going to transmit to a bootloader. A typical communication process might look like:
- We send the encrypted image ciphertexts over a serial connection
- The bootloader decrypts the ciphertexts and stores the result somewhere in memory
- The bootloader sends back a response over the serial port
We have a pretty straightforward attack for this type of bootloader. During the last step, we'll apply a glitch at precisely the right time, causing the bootloader to print all kinds of things to the serial connection. With some luck, we'll be able to find the decrypted plaintext somewhere in this memory dump.
Bootloader Setup
For this tutorial, a very simple bootloader using the SimpleSerial protocol has been set up. The source for this bootloader can be found in chipwhisperer/hardware/victims/firmware/bootloader-glitch
. The following commands are used:
-
pABCD\n
: Send an encrypted ciphertext to the bootloader. For example, this message is made up of the two bytesAB
andCD
. -
r0\n
: The reply from the bootloader. Acknowledges that a message was received. No other responses are used. -
x
: Clear the bootloader's received buffer. -
k
: Seex
.
The bootloader uses triple-ROT-13 encryption to encrypt/decrypt the messages. To help you send messages to the target, the script private/encrypt.py
prints the SimpleSerial command for a given fixed string. For example, the ciphertext for the string Don't forget to buy milk!
is
p516261276720736265747267206762206f686c207a76797821\n
This folder also contains a Makefile to create a hex file for use with the ChipWhisperer hardware. The build process is the same as the previous tutorials: run make
from the command line and make sure that everything built properly. If all goes well, the Makefile should print something like
---------------- Device: atxmega128d3 Program: 1706 bytes (1.2% Full) (.text + .data + .bootloader) Data: 248 bytes (3.0% Full) (.data + .bss + .noinit) Built for platform CW-Lite XMEGA -------- end --------
The Attack Plan
Since we have access to the source code, let's take our time and understand how our attack is going to work before we dive in.
The Sensitive Code
Inside bootloader.c
, there are two buffers that are used to store most of the important data. The source code shows:
#define DATA_BUFLEN 40 #define ASCII_BUFLEN (2 * DATA_BUFLEN) uint8_t ascii_buffer[ASCII_BUFLEN]; uint8_t data_buffer[DATA_BUFLEN];
This tells us that there will be two arrays stored somewhere in the target's memory. The AVR-GCC compiler doesn't usually try too hard to move these around, so we can expect to find them back-to-back in memory; that is, if we can read past the end of the ASCII buffer, we'll probably find the data buffer.
Next, the code used to print a response to the serial port is
if(state == RESPOND) { // Send the ascii buffer back trigger_high(); int i; for(i = 0; i < ascii_idx; i++) { putch(ascii_buffer[i]); } trigger_low(); state = IDLE; }
This looks very similar to the example code given in the previous section, so it should be vulnerable to a glitching attack. The goal is to cause the loop to continue past its regular limit: data_buffer[0]
is the same as ascii_buffer[80]
, so a successful glitch should dump the data buffer for us.
Disassembly
As a final step, let's check the assembly code to see exactly what we're trying to glitch through. Run the command
avr-objdump -m avr -D bootloader.hex > disassembly.txt
and open disassembly.txt
.
Attack Script & Results
Ideas
- Change hex file to use BRLT
- Use volatile loop variables