|
|
Line 1: |
Line 1: |
− | {{Warningbox|This tutorial has been updated for ChipWhisperer 4.0.0 release. If you are using 3.x.x see the "V3" link in the sidebar.}} | + | {{Warningbox|This tutorial has been updated for ChipWhisperer 5 release. If you are using 4.x.x or 3.x.x see the "V4" or "V3" link in the sidebar.}} |
| | | |
| {{Infobox tutorial | | {{Infobox tutorial |
Line 13: |
Line 13: |
| }} | | }} |
| | | |
− | This advanced tutorial will demonstrate clock glitch attacks using the ChipWhisperer system. This will introduce you to many required features of the ChipWhisperer system when it comes to glitching. This will be built on in later tutorials to generate voltage glitching attacks, or when you wish to attack other targets.
| + | <!-- To edit this, edit Template:Tutorial_boilerplate --> |
| + | {{Tutorial boilerplate}} |
| | | |
− | '''If you're working on an STM32F3/CW303 Arm target, it's recommended that you have the latest updates from the develop branch. Recent firmware changes have made glitching far more reliable.''' | + | * Jupyter file: '''PA_Intro_2-Instruction_Differences.ipynb''' |
| | | |
− | == Background on Clock Glitching ==
| |
| | | |
− | Digital hardware devices almost always expect some form of reliable clock. We can manipulate the clock being presented to the device to cause unintended behaviour. We'll be concentrating on microcontrollers here, however other digital devices (e.g. hardware encryption accelerators) can also have faults injected using this technique.
| + | == XMEGA Target == |
| | | |
− | Consider a microcontroller first. The following figure is an excerpt the Atmel AVR ATMega328P datasheet:
| + | See the following for using: |
| + | * ChipWhisperer-Lite Classic (XMEGA) |
| + | * ChipWhisperer-Lite Capture + XMEGA Target on UFO Board (including NAE-SCAPACK-L1/L2 users) |
| + | * ChipWhisperer-Pro + XMEGA Target on UFO Board |
| | | |
− | [[File:mcu-unglitched.png|image]]
| + | https://chipwhisperer.readthedocs.io/en/latest/tutorials/fault_1-openadc-cwlitexmega.html#tutorial-fault-1-openadc-cwlitexmega |
| | | |
− | Rather than loading each instruction from FLASH and performing the entire execution, the system has a pipeline to speed up the execution process. This means that an instruction is being decoded while the next one is being retrieved, as the following diagram shows:
| + | == ChipWhisperer-Lite ARM / STM32F3 Target == |
| | | |
− | [[File:clock-normal.png|image]]
| + | See the following for using: |
| + | * ChipWhisperer-Lite 32-bit (STM32F3 Target) |
| + | * ChipWhisperer-Lite Capture + STM32F3 Target on UFO Board (including NAE-SCAPACK-L1/L2 users) |
| + | * ChipWhisperer-Pro + STM32F3 Target on UFO Board |
| | | |
− | But if we modify the clock, we could have a situation where the system doesn't have enough time to actually perform an instruction. Consider the following, where Execute #1 is effectively skipped. Before the system has time to actually execute it another clock edge comes, causing the microcontroller to start execution of the next instruction:
| + | https://chipwhisperer.readthedocs.io/en/latest/tutorials/fault_1-openadc-cwlitearm.html#tutorial-fault-1-openadc-cwlitearm |
| | | |
− | [[File:clock-glitched.png|image]]
| + | == ChipWhisperer Nano Target == |
| | | |
− | This causes the microcontroller to skip an instruction. Such attacks can be immensely powerful in practice. Consider for example the following code from `linux-util-2.24`: | + | This tutorial is not available for the ChipWhisperer Nano. |
− | | + | |
− | <pre>/*
| + | |
− | * auth.c -- PAM authorization code, common between chsh and chfn
| + | |
− | * (c) 2012 by Cody Maloney <cmaloney@theoreticalchaos.com>
| + | |
− | *
| + | |
− | * this program is free software. you can redistribute it and
| + | |
− | * modify it under the terms of the gnu general public license.
| + | |
− | * there is no warranty.
| + | |
− | *
| + | |
− | */
| + | |
− | | + | |
− | #include "auth.h"
| + | |
− | #include "pamfail.h"
| + | |
− | | + | |
− | int auth_pam(const char *service_name, uid_t uid, const char *username)
| + | |
− | {
| + | |
− | if (uid != 0) {
| + | |
− | pam_handle_t *pamh = NULL;
| + | |
− | struct pam_conv conv = { misc_conv, NULL };
| + | |
− | int retcode;
| + | |
− | | + | |
− | retcode = pam_start(service_name, username, &conv, &pamh);
| + | |
− | if (pam_fail_check(pamh, retcode))
| + | |
− | return FALSE;
| + | |
− | | + | |
− | retcode = pam_authenticate(pamh, 0);
| + | |
− | if (pam_fail_check(pamh, retcode))
| + | |
− | return FALSE;
| + | |
− | | + | |
− | retcode = pam_acct_mgmt(pamh, 0);
| + | |
− | if (retcode == PAM_NEW_AUTHTOK_REQD)
| + | |
− | retcode =
| + | |
− | pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
| + | |
− | if (pam_fail_check(pamh, retcode))
| + | |
− | return FALSE;
| + | |
− | | + | |
− | retcode = pam_setcred(pamh, 0);
| + | |
− | if (pam_fail_check(pamh, retcode))
| + | |
− | return FALSE;
| + | |
− | | + | |
− | pam_end(pamh, 0);
| + | |
− | /* no need to establish a session; this isn't a
| + | |
− | * session-oriented activity... */
| + | |
− | }
| + | |
− | return TRUE;
| + | |
− | }</pre>
| + | |
− | This is the login code for the Linux OS. Note that if we could skip the check of <code>if (uid != 0)</code> and simply branch to the end, we could avoid having to enter a password. This is the power of glitch attacks - not that we are breaking encryption, but simply bypassing the entire authentication module!
| + | |
− | | + | |
− | == Glitch Hardware ==
| + | |
− | | + | |
− | The ChipWhisperer Glitch system uses the same synchronous methodology as it's Side Channel Analysis (SCA) capture. A system clock (which can come from either the ChipWhisperer or the Device Under Test (DUT)) is used to generate the glitches. These glitches are then inserted back into the clock, although it's possible to use the glitches alone for other purposes (i.e. for voltage glitching, EM glitching).
| + | |
− | | + | |
− | The generation of glitches is done with two variable phase shift modules, configured as follows:
| + | |
− | | + | |
− | [[File:glitchgen-phaseshift.png|frame|none]]
| + | |
− | | + | |
− | The enable line is used to determine when glitches are inserted. Glitches can be inserted continuously (useful for development) or triggered by some event. The following figure shows how the glitch can be muxd to output to the Device Under Test (DUT).
| + | |
− | | + | |
− | [[File:glitchgen-mux.png|frame|none]]
| + | |
− | | + | |
− | === Hardware Support ===
| + | |
− | | + | |
− | The phase shift blocks use the Digital Clock Manager (DCM) blocks within the FPGA. These blocks have limited support for run-time configuration of parameters such as phase delay and frequency generation, and for maximum performance the configuration must be fixed at design time. The Xilinx-provided run-time adjustment can shift the phase only by about +/- 5nS in 30pS increments (exact values vary with operating conditions).
| + | |
− | | + | |
− | For most operating conditions this is insufficient - if attacking a target at 7.37MHz the clock cycle would have a period of 136nS. In order to provide a larger adjustment range, an advanced FPGA feature called Partial Reconfiguration (PR) is used. The PR system requires special partial bitstreams which contain modifications to the FPGA bitstream. These are stored as two files inside a "firmware" zip which contains both the FPGA bitstream along with a file called <code>glitchwidth.p</code> and a file called <code>glitchoffset.p</code>. If a lone bitstream is being loaded into the FPGA (i.e. not from the zip-file), the partial reconfiguration system is disabled, as loading incorrect partial reconfiguration files could damage the FPGA. This damage is mostly theoretical, more likely the FPGA will fail to function correctly.
| + | |
− | | + | |
− | If in the course of following this tutorial you find the FPGA appears to stop responding (i.e. certain features no longer work correctly), it could be the partial reconfiguration data is incorrect.
| + | |
− | | + | |
− | === Python GUI Interface ===
| + | |
− | | + | |
− | The portion of the GUI of interest to us is primarily located in this section:
| + | |
− | | + | |
− | [[File:prgui.png|frame|none]]
| + | |
− | | + | |
− | If the Partial Reconfiguration system has been disabled (due to missing PR files or files differing from the FPGA bitstream) the two fields marked that say (as % of period) will be disabled. Only the fields labeled (fine adjust) will be available.
| + | |
− | | + | |
− | == Setting up Glitch Example ==
| + | |
− | | + | |
− | === Firmware Setup ===
| + | |
− | For this example, we'll be using the <code>glitch-simple</code> firmware.
| + | |
− | {{CollapsibleSection
| + | |
− | |intro = ==== Building for CWLite with XMEGA Target ====
| + | |
− | |content= Building for XMEGA}}
| + | |
− | | + | |
− | {{CollapsibleSection
| + | |
− | |intro = ==== Building for CWLite with Arm Target ====
| + | |
− | |content= Building for Arm}}
| + | |
− | | + | |
− | {{CollapsibleSection
| + | |
− | |intro = ==== Building for Other Targets ====
| + | |
− | |content= Building for Other Targets}}
| + | |
− | | + | |
− | | + | |
− | You should also open the file <code>glitchsimple.c</code> which is the source code. The subroutine being glitched in this example looks like this:
| + | |
− | | + | |
− | <pre>void glitch_infinite(void)
| + | |
− | {
| + | |
− | char str[64];
| + | |
− | //Declared volatile to avoid optimizing away loop.
| + | |
− | //This also adds lots of SRAM access
| + | |
− | volatile uint16_t i, j;
| + | |
− | volatile uint32_t cnt;
| + | |
− | while(1){
| + | |
− | cnt = 0;
| + | |
− | for(i=0; i<500; i++){
| + | |
− | for(j=0; j<500; j++){
| + | |
− | cnt++;
| + | |
− | }
| + | |
− | }
| + | |
− | sprintf(str, "%lu %d %d\n", cnt, i, j);
| + | |
− | uart_puts(str);
| + | |
− | }
| + | |
− | }</pre>
| + | |
− | You should confirm that <code>glitch_infinite()</code> is actually called from the main subroutine. There are several glitch examples and it's possible the wrong subroutine has been setup previously:
| + | |
− | | + | |
− | <pre>int main(void){
| + | |
− | | + | |
− | platform_init();
| + | |
− | init_uart();
| + | |
− | trigger_setup();
| + | |
− | | + | |
− | /* Uncomment this to get a HELLO message for debug */
| + | |
− | putch('h');
| + | |
− | putch('e');
| + | |
− | putch('l');
| + | |
− | putch('l');
| + | |
− | putch('o');
| + | |
− | putch('\n');
| + | |
− | _delay_ms(20);
| + | |
− | | + | |
− | | + | |
− | while(1){
| + | |
− | glitch_infinite();
| + | |
− | }
| + | |
− | | + | |
− | return 1;
| + | |
− | }</pre>
| + | |
− | | + | |
− | === Hardware Setup ===
| + | |
− | {{CollapsibleSection
| + | |
− | |intro = ==== CW1173 (Lite) Hardware Setup ====
| + | |
− | |content= CWLite HW Setup}}
| + | |
− | | + | |
− | {{CollapsibleSection
| + | |
− | |intro = ==== CW1200 (Pro) Hardware Setup ====
| + | |
− | |content= CW1200 HW Setup}}
| + | |
− | | + | |
− | {{CollapsibleSection
| + | |
− | |intro = ==== CW308 (UFO) Hardware Setup ====
| + | |
− | |content= CW308 HW Setup}}
| + | |
− | | + | |
− | ==== Multi-Target Board, AVR (CW301) ====
| + | |
− | | + | |
− | The hardware is almost as in previous incarnations. The difference is the 'FPGAOUT' is bridged to the AVR clock. This example will use the CLKGEN feature.
| + | |
− | | + | |
− | The AVR is being used as the glitch target. The following figure shows the expected jumper settings:
| + | |
− | | + | |
− | [[File:glitchhw.jpg|image]]
| + | |
− | | + | |
− | === Programming the Target ===
| + | |
− | {{CollapsibleSection|intro = === Programming the XMEGA Target ===|content = Programming XMEGA}}
| + | |
− | {{CollapsibleSection|intro = === Programming the Arm Target ===|content = Programming Arm}}
| + | |
− | {{CollapsibleSection|intro = === Programming Other Targets ===|content = Programming Other}}
| + | |
− | | + | |
− | | + | |
− | === Software Setup ===
| + | |
− | Assuming you still have ChipWhisperer setup as described in the programming step (aka have run connect_simpleserial.py and the setup script for your target), there's only a few modifications we need to make to be able to glitch:<ol style="list-style-type: decimal;">
| + | |
− | <li><p>Under ''Scope Settings'', change ''CW Extra Settings>Target HS IO-Out'' to ''Glitch Module'' and ''Glitch Module>Clock Source'' to ''CLKGEN''. This routes the clock source for the microcontroller through the glitch module.</p></li>
| + | |
− | <li><p>From the ''Tools'' menu, select ''Open Terminal'', and press ''Connect'' on the terminal. This will allow us to see what's being sent to and from the microcontroller:</p><p>[[File:Termconn.png|frameless|371x371px]]</p></li><li><p>Reset the device. You can do this by going to ''Scope Settings'' and switching ''CW Extra Settings>Target IOn GPIO Mode> nRST: GPIO'' (or ''PDIC: GPIO'', for the XMEGA target) to ''Low'', then back to ''Default''. If you're using a target that can be programmed from ChipWhisperer, running ''Check Signature'' from the programming window will also reset the device.</p></li><li><p>You should see text populate the terminal:</p><p>[[File:Termhello.png|frameless|506x506px]]</p></li></ol>
| + | |
− | | + | |
− | We'll now look at glitching this routine. You should inspect the source code to determine that a simple series of calculations are performed:
| + | |
− | | + | |
− | <pre>void glitch_infinite(void)
| + | |
− | {
| + | |
− | char str[64];
| + | |
− | //Declared volatile to avoid optimizing away loop.
| + | |
− | //This also adds lots of SRAM access
| + | |
− | volatile uint16_t i, j;
| + | |
− | volatile uint32_t cnt;
| + | |
− | while(1){
| + | |
− | cnt = 0;
| + | |
− | for(i=0; i<500; i++){
| + | |
− | for(j=0; j<500; j++){
| + | |
− | cnt++;
| + | |
− | }
| + | |
− | }
| + | |
− | sprintf(str, "%lu %d %d\n", cnt, i, j);
| + | |
− | uart_puts(str);
| + | |
− | }
| + | |
− | }</pre>
| + | |
− | If the routine works as expected, we would expect it to print <code>250000 500 500</code>. If a glitch interrupts the program flow, we would expect some of those values to be incorrect. This could be because a loop was skipped, an addition done incorrectly, or the program flow was exited unexpectedly.
| + | |
− | | + | |
− | == Manual Glitch Trigger ==
| + | |
− | | + | |
− | To begin with, you'll simply use the manual glitch triggering. This works well in the examples where we have a simple loop we are breaking out of. Doing so requires modifying the glitch width and glitch offset experimentally. The exact values will vary for every device and setup.
| + | |
− | | + | |
− | It is recommended to only use the ''glitch width (as % of period)'' option, as the fine adjust is too small of a change for this lower-speed example. Other hardware may need the precision added by the fine adjust however!
| + | |
− | | + | |
− | The following figure shows several different settings for a 7.37 MHz clock. The width is set to 10%, which for the 136nS clock period of the 7.37 MHz clock means the glitch width is about 13.6 nS. When the offset is negative, the glitch is placed in-front of the clock. The glitch is XORd with the clock, meaning this becomes a small positive-going glitch in-front of the regular clock pulse.
| + | |
− | | + | |
− | If the offset is positive, the glitch occurs ''after'' the rising edge of the clock pulse. Because this glitch pulse is XORd with the clock, it becomes a negative-going glitch inserted in the 'middle' of the regular clock pulse.
| + | |
− | | + | |
− | <blockquote>[[File:clockglitch-examplesettings.png|image]]
| + | |
− | </blockquote>
| + | |
− | With some background, let's now check some glitches. Assuming you've setup the example as before, do the following:
| + | |
− | | + | |
− | <ol style="list-style-type: decimal;">
| + | |
− | <li><p>Adjust the settings for ''Glitch Width (as % of period)'' , ''Glitch Offset (as % of period)'', and ''Repeat'' based on your target and the following table for different targets:</p>
| + | |
− | {| class="wikitable"
| + | |
− | ! Parameter
| + | |
− | ! AVR on Multi-Target (CW301)
| + | |
− | ! CW-Lite XMEGA Board
| + | |
− | !CW-Lite Arm Board
| + | |
− | |-
| + | |
− | | Glitch Width (as % of period)
| + | |
− | | 7.5
| + | |
− | | 9.5
| + | |
− | | -10
| + | |
− | |-
| + | |
− | | Glitch Offset (as % of period)
| + | |
− | | -10
| + | |
− | | -2
| + | |
− | | -40
| + | |
− | |-
| + | |
− | | Repeat
| + | |
− | | 5
| + | |
− | | 105
| + | |
− | |105
| + | |
− | |}
| + | |
− | </li>
| + | |
− | <li>Ensure ''Glitch Trigger'' is ''Manual''</li>
| + | |
− | <li>Hit the ''Manual Trigger'' button</li>
| + | |
− | <li>See if you end up with either the target resetting (reprints <code>hello\n</code>), or if the loop count becomes wrong. You may need to press the ''Manual Trigger'' button several times quickly. The objective is to have an incorrect loop count, meaning you caused a glitch!</li>
| + | |
− | <li>To force a reset of the target, use the Signature Read option on the programmer.</li>
| + | |
− | <li>Adjust the glith width & offset as needed.</li>
| + | |
− | <li>You may also adjust the ''Repeat'' option, or cause it to glitch several instructions.</li></ol>
| + | |
− | | + | |
− | '''Be aware that you may crash the target!''' In the previous examples the target could have reset after each glitch. It may simply go into another infinite loop however, or even enter invalid states. Again force a hardware reset of the target in these cases. It may appear like the target was never glitched, whereas in reality it was glitched into some invalid state.
| + | |
− | | + | |
− | {{Warningbox|The boards are extremely sensitive to the glitch width and offset. You may have trouble finding settings that cause a glitch. Don't get too hung up on this; the following sections provide a more reliable method of glitching a target by determining the appropriate parameter settings.}}
| + | |
− | | + | |
− | == Automatically Resetting Target ==
| + | |
− | | + | |
− | If we are going to start with the target at a pre-determined state, we need to reset the target. There are two ways of automatically performing this. The method used here will use the existing programmer interface to reset the device by performing that "read signature" operation we have already been using. The other method is to toggle a GPIO pin, which is more generic for future use.
| + | |
− | | + | |
− | This was introduced in [[Tutorial_B3-1_Timing_Analysis_with_Power_for_Password_Bypass#Reset_via_Auxiliary_Module]].
| + | |
− | | + | |
− | To setup the automatic reset, perform the following:
| + | |
− | | + | |
− | <ol>
| + | |
− | <li> Scroll down the list of scripts, and you'll find one labeled "aux_reset_cw1173.py". Depending on your target, you may have to modify this script to change the reset pin. Most targets (except for the XMEGA) use ''nrst'', so if you're unsure, this is usually the correct choice . This script sets up the aux module that attempts to reset the target device. <b>Note: The aux module is only executed after capture is executed.</b>
| + | |
− | <br>
| + | |
− | [[File:auxreset_test1.png|600px]]
| + | |
− | </li>
| + | |
− | <li>Hit the "Run" button. If you switch to the "Auxilary Module" tab, you'll see it's been added to the list of modules at the specified location.:
| + | |
− | <br>
| + | |
− | [[File:auxreset_test2.png|400px]]
| + | |
− | </li>
| + | |
− | <li>Looking at the code of the script, you can see how this script is using an external module & linking it to a specific auxilary module trigger:
| + | |
− | <syntaxhighlight lang=python>
| + | |
− | from chipwhisperer.capture.auxiliary.ResetCW1173Read import ResetCW1173
| + | |
− | | + | |
− | # GUI compatibility
| + | |
− | try:
| + | |
− | aux_list = self.aux_list
| + | |
− | except NameError:
| + | |
− | pass
| + | |
− | | + | |
− | # Delay between arming and resetting, in ms
| + | |
− | delay_ms = 1500
| + | |
− | | + | |
− | # Reset XMEGA device
| + | |
− | Resetter = ResetCW1173(pin='pdic', delay_ms=delay_ms)
| + | |
− | # Reset STM32Fx device
| + | |
− | #Resetter = ResetCW1173(pin='nrst', delay_ms=delay_ms)
| + | |
− | # Reset AVR
| + | |
− | #Resetter = ResetCW1173(pin='nrst', delay_ms=delay_ms)
| + | |
− | | + | |
− | # Reset before arming
| + | |
− | # avoids possibility of false triggers
| + | |
− | # need delay in target firmware to avoid race condition
| + | |
− | #aux_list.register(Resetter.resetThenDelay, "before_trace")
| + | |
− | | + | |
− | # Reset after arming
| + | |
− | # scope can catch entire reset
| + | |
− | # avoids race condition
| + | |
− | # target reset can cause false triggers (usually not an issue)
| + | |
− | aux_list.register(Resetter.delayThenReset, "after_arm")
| + | |
− | </syntaxhighlight>
| + | |
− | <li>You can edit the values required such as reset time & location by changing the script (using an external editor). But an easier method is to insert it into our attack script itself. As a test we'll see if the default values work. We will later integrate this into a full example script.</li>
| + | |
− | </ol>
| + | |
− | | + | |
− | | + | |
− | We can now confirm the reset works with the "Capture 1" button. This requires us to disable the normal routing of the output data to a file for analysis, as we want to just dump data to the terminal emulator. To do this:
| + | |
− | | + | |
− | <ol style="list-style-type: decimal;">
| + | |
− | <li>Switch to the ''Target Settings'' tab.</li>
| + | |
− | <li><p>Remove all of the ''Load Key Command'', ''Go Command'', and ''Output Format'' options:</p>
| + | |
− | <p>[[File:targetsettings_clear.png|image]]</p></li>
| + | |
− | <li>Press the "Capture 1" button a few times, which should confirm on each "capture" the target device is resetting.</li>
| + | |
− | <li><p>Finally, we will switch the glitch target to give us a more realistic target to glitch. To do this open the file <code>chipwhisperer\hardware\victims\firmware\glitch-simple\glitchsimple.c</code> and modify the call in <code>main()</code>, such that we now call the <code>glitch1()</code> function. This means the following:</p>
| + | |
− | <pre>while(1){
| + | |
− | glitch_infinite();
| + | |
− | }</pre>
| + | |
− | <p>can be changed to:</p>
| + | |
− | <pre>while(1){
| + | |
− | glitch1();
| + | |
− | }</pre>
| + | |
− | <p>After which recompile (with <code>make</code>), and reprogram the target device. Note the new function being glitched looks like this:</p>
| + | |
− | <pre>void glitch1(void)
| + | |
− | {
| + | |
− | led_ok(1);
| + | |
− | led_error(0);
| + | |
− | | + | |
− | //Some fake variable
| + | |
− | volatile uint8_t a = 0;
| + | |
− | | + | |
− | putch('A');
| + | |
− | | + | |
− | //External trigger logic
| + | |
− | trigger_high();
| + | |
− | trigger_low();
| + | |
− | | + | |
− | //Should be an infinite loop
| + | |
− | while(a != 2){
| + | |
− | ;
| + | |
− | }
| + | |
− | | + | |
− | led_error(1);
| + | |
− | led_error(1);
| + | |
− | led_error(1);
| + | |
− | led_error(1);
| + | |
− | led_error(1);
| + | |
− | led_error(1);
| + | |
− | led_error(1);
| + | |
− | led_error(1);
| + | |
− | led_error(1);
| + | |
− | | + | |
− | uart_puts("1234");
| + | |
− | | + | |
− | led_error(1);
| + | |
− | led_error(1);
| + | |
− | led_error(1);
| + | |
− | led_error(1);
| + | |
− | led_error(1);
| + | |
− | led_error(1);
| + | |
− | led_error(1);
| + | |
− | led_error(1);
| + | |
− | | + | |
− | //Several loops in order to try and prevent restarting
| + | |
− | while(1){
| + | |
− | ;
| + | |
− | }
| + | |
− | while(1){
| + | |
− | ;
| + | |
− | }
| + | |
− | while(1){
| + | |
− | ;
| + | |
− | }
| + | |
− | while(1){
| + | |
− | ;
| + | |
− | }
| + | |
− | while(1){
| + | |
− | ;
| + | |
− | }
| + | |
− | }</pre></li>
| + | |
− | <li><p>When you perform a ''Capture 1'', the terminal should print <code>hello\nA</code>, based on the above source code. Note the objective will be to glitch past the infinite loop, such that <code>1234</code> is printed. If using the CW303 board, this will also light the red LED on the board up.</p>
| + | |
− | <blockquote><p>'''hint'''</p>
| + | |
− | <p>If the startup message isn't visible, it may be related to issues with the Capture software not being fast enough after reset to display the serial port contents on the terminal emulator. This happens often on the virtual machine environment, as can be seen in the demo video. You can ignore this error for now.</p></blockquote></li></ol>
| + | |
− | | + | |
− | == Automatically Triggering Glitch ==
| + | |
− | | + | |
− | The manual trigger used previously is suitable when the embedded system is waiting for further input. For example if the embedded system is waiting for a password, you could insert glitches without requiring accurate timing. We'll explore the use of the capture trigger for glitching here, which also improves the repeatability of your glitch attempts.
| + | |
− | | + | |
− | To use this system, you must first understand the routing of the trigger to the glitch module. The following figure shows the trigger routing, which is more basic than the power capture trigger:
| + | |
− | | + | |
− | <blockquote>[[File:triggerrouting.png|image]]
| + | |
− | </blockquote>
| + | |
− | Note in particular that if using an external IO pin, you only have a ''rising edge trigger''. The example glitch program includes a line which is set 'High' at critical moments, allowing you to experiment with this basic IO trigger.
| + | |
− | | + | |
− | Based on the source code loaded, we currently have a trigger to time the glitch. This is very useful during the characterization phase, where we wish to determine what sort of glitch affects this specific hardware. Once we know that, we can move onto glitching a more "realistic" routine.
| + | |
− | | + | |
− | Before doing that, we will actually enable the power analysis capture. To do this:
| + | |
− | | + | |
− | <ol style="list-style-type: decimal;">
| + | |
− | <li><p>Press ''Capture 1'', confirm some waveform is displayed. For example with the XMEGA Target on the ChipWhisperer-Lite, the waveform looks like this:</p>
| + | |
− | <p>[[File:basic_waveform.png|image]]</p></li>
| + | |
− | <li>If this does't work: check the trigger in use is the ''Target IO4'' pin.</li>
| + | |
− | <li><p>If this also does not work, and there are timeout issues, causing the trigger to be forced: create a copy of the "aux_reset_cw1173.py" script and change the
| + | |
− | <br></p>
| + | |
− | <pre>
| + | |
− | # Reset before arming - more stable
| + | |
− | aux_list.register(Resetter.resetThenDelay, "before_trace")
| + | |
− | # Reset after arming - scope can catch entire reset
| + | |
− | #aux_list.register(Resetter.delayThenReset, "after_arm")
| + | |
− | </pre>
| + | |
− | to
| + | |
− | <pre>
| + | |
− | # Reset before arming - more stable
| + | |
− | #aux_list.register(Resetter.resetThenDelay, "before_trace")
| + | |
− | # Reset after arming - scope can catch entire reset
| + | |
− | aux_list.register(Resetter.delayThenReset, "after_arm")
| + | |
− | </pre>
| + | |
− | by commenting out the second line and un-commenting out the fourth line changing the chronological position of the reset to after the scope is armed. This should remove the timeout issue as the scope can now detect the trigger as it is armed before the trigger line is activated.
| + | |
− | <b> Use this copy of the script instead of the original version by running the edited script once and disabling the aux module of the original script in ''Aux Settings'' under ''Before Trace''.</b>
| + | |
− | </li></ol>
| + | |
− | | + | |
− | Finally, we can enable the trigger of the glitch to occur based on this external trigger pin. This can be accomplished by:
| + | |
− | | + | |
− | <ol style="list-style-type: decimal;">
| + | |
− | <li><p>Switch the ''Glitch Trigger'' mode to ''Ext Trigger:Single-Shot'':</p>
| + | |
− | <p>[[File:singleshot.png|image]]</p></li>
| + | |
− | <li><p>Performing a ''Capture 1'', you'll notice that the waveform is now perturbed. This is due to the clock glitches causing odd power consumption behavior:</p>
| + | |
− | <p>[[File:basic_waveform_glitchy.png|image]]</p></li>
| + | |
− | <li>Play around a bit with the glitch width, offset, and repeat. You should see different effects in the power consumption traces.</li></ol>'''From this point on, you may want to disable displaying of traces, as this will speed up giltching significantly. To do this, go to ''Results>Trace Output Plot>Input'' and change it to ''None''.'''
| + | |
− | | + | |
− | == Using the Glitch Explorer ==
| + | |
− | | + | |
− | Now that we can automatically perform the glitching, we can use the ''glitch explorer'' to automatically vary glitch parameters while recording what the target device is doing. Before continuing with the tutorial, we'll go through an overview of the the glitch explorer.
| + | |
− | | + | |
− | === Glitch Explorer ===
| + | |
− | | + | |
− | We'll first introduce the Glitch Monitor ("Glitch Explorer") before we go ahead and show you how to use it. The main window of the glitch explorer looks like this:
| + | |
− | | + | |
− | [[File:ge_overview.png]]
| + | |
− | | + | |
− | Where you can see the following parts
| + | |
− | | + | |
− | <blockquote>
| + | |
− | # The top part is the output of the system combined with the parameters of the glitch is displayed (the 'output window').
| + | |
− | # In the bottom part you can adjust general parameters of the glitching system, such as what counts as a successful glitch or not.
| + | |
− | </blockquote>
| + | |
− | We'll be looking at each of these sections in more detail next.
| + | |
− | | + | |
− | ==== The Output Window ====
| + | |
− | | + | |
− | [[File:ge_top.png|image]]
| + | |
− | | + | |
− | The output window highlights different types of output. In this example we have an output |1| highlighted in green, which is flagged as a successful glitch. This example code was waiting for the ''rrrr'' sequence.
| + | |
− | | + | |
− | Glitches can also be flagged as 'normal', in which case there is no highlight as in |2|. Finally the glitch could be flagged as an error, in which case it will be highlighted in red.
| + | |
− | | + | |
− | In order for the glitch explorer to receive the output value, you must insert the special code <code>$GLITCH$</code> into the ''Target Settings'' --> ''Output Format'' settings. Data is still sent to the terminal emulator so you can monitor what is happening, but if you don't set the $GLITCH$ special string you won't see it in glitch explorer.
| + | |
− | | + | |
− | ==== The Main Settings ====
| + | |
− | | + | |
− | Details of the main settings:
| + | |
− | | + | |
− | [[File:ge4_middle.png|image]]
| + | |
− | | + | |
− | The response of the system during normal operation is set at ''Normal response''. This defines what happens when no glitching or unexpected behavior happened.
| + | |
− | | + | |
− | The desired response of the system if the glitch was successful is set at ''Successful response''.
| + | |
− | | + | |
− | The expected and desired responses are expected to be Python expressions, where <code>s</code> is a str-type variable which contains the response of the system. The expression must evaulate to <code>True</code> or <code>False</code>. For example, the following shows examples of what you could use as possible expressions:
| + | |
− | | + | |
− | {| class="wikitable"
| + | |
− | ! Desired Behavior
| + | |
− | ! Parameter Expression
| + | |
− | |-
| + | |
− | | Check for "hello\n" exactly.
| + | |
− | | s == "hello\n"
| + | |
− | |-
| + | |
− | | Check for "hello\n" at end of string.
| + | |
− | | s.endswith("hello\n")
| + | |
− | |-
| + | |
− | | Check for hex 0xAF in last byte position.
| + | |
− | | ord(s[-1]) == 0xAF
| + | |
− | |}
| + | |
− | | + | |
− | Note that there is sometimes garbage in the first position. This occurs because if the target device is being reset before the glitch, you may see the serial lines floating. These floating lines may cause invalid characters to be recorded.
| + | |
− | | + | |
− | ==== Parameter Settings ====
| + | |
− | | + | |
− | The actual parameters to change are set via a simple Python script. You will register this script to an appropriate section in the system using the "auxiliary module". Using a script makes it easy to define all sorts of various settings you might find of interest.
| + | |
− | | + | |
− | For example the following script would insert code to cycle through width and offset settings:
| + | |
− | | + | |
− | <syntaxhighlight lang=python>
| + | |
− | class IterateGlitchWidthOffset(object):
| + | |
− | def __init__(self, ge_window):
| + | |
− | self._starting_offset = -40
| + | |
− | self._starting_width = 5
| + | |
− | self.ge_window = ge_window
| + | |
− | | + | |
− | def reset_glitch_to_default(self, scope, target, project):
| + | |
− | """ Set glitch settings to defaults. """
| + | |
− | self.offset = self._starting_offset
| + | |
− | self.width = self._starting_width
| + | |
− | | + | |
− | def change_glitch_parameters(self, scope, target, project):
| + | |
− | """ Example of simple glitch parameter modification function. """
| + | |
− | # This value is minimum clock offset/width increment
| + | |
− | self.offset += 0.390625
| + | |
− | | + | |
− | if self.offset > 40:
| + | |
− | self.offset = self._starting_offset
| + | |
− | self.width += 0.390625
| + | |
− | | + | |
− | if self.width > 40:
| + | |
− | self.width = self._starting_width
| + | |
− | | + | |
− | # Write data to scope
| + | |
− | scope.glitch.width = self.width
| + | |
− | scope.glitch.offset = self.offset
| + | |
− | | + | |
− | #You MUST tell the glitch explorer about the updated settings
| + | |
− | if self.ge_window:
| + | |
− | self.ge_window.add_data("Glitch Width", scope.glitch.width)
| + | |
− | self.ge_window.add_data("Glitch Offset",scope.glitch.offset)
| + | |
− | | + | |
− | glitch_iterator = IterateGlitchWidthOffset(self.glitch_explorer)
| + | |
− | self.aux_list.register(glitch_iterator.change_glitch_parameters, "before_trace")
| + | |
− | self.aux_list.register(glitch_iterator.reset_glitch_to_default, "before_capture")
| + | |
− | | + | |
− | </syntaxhighlight>
| + | |
− | | + | |
− | Note you can quickly cause very long captures to occur! To run the glitch explorer, you need to set the appropriate number of traces on the ''General Settings'' tab, and use the ''Capture Multi'' to run the glitch explorer.
| + | |
− | | + | |
− | The ChipWhisperer system has no idea how many iterations are required with your code - it still uses a fixed number of captures by default. Later versions of the API will support an exit signal.
| + | |
− | | + | |
− | === Example Running the Glitch Explorer ===
| + | |
− | | + | |
− | ==== XMEGA ====
| + | |
− | This example will attempt to break out the loop in <code>glitch1()</code>. Moving ahead from where you were in [[#Automatically Triggering Glitch]], we will see how we can view the output of the target device in the glitch explorer.
| + | |
− | | + | |
− | <ol style="list-style-type: decimal;">
| + | |
− | <li><p>Switch to the ''Target Settings'' tab, and set the ''Output Format'' to be <code>$GLITCH$</code>:</p>
| + | |
− | <p>[[File:output_glitch.png|image]]</p></li>
| + | |
− | <li>From the ''Tools'' menu select ''Glitch Monitor'' to open the glitch explorer.</li>
| + | |
− | <li><p>Press the ''Capture 1'' button a few times, and you should see the table populated with outputs:</p>
| + | |
− | <p>[[File:ge_setup1.png|image]]</p>
| + | |
− | <p>We want to mark them as "normal" or "glitch successful" to get the color-coding working appropriately.</p></li>
| + | |
− | <li>Double-click on a normal response, and copy the text. In the ''Normal Response'' field, we need to compare the magic variable <code>s</code> with that copied text. Do this by setting the ''Normal Response'' to be: <code>s == '\x00hello\nA'</code>.</li>
| + | |
− | <li>We want to mark a string ending with <code>1234</code> as a pass. Thus in the ''Successful Response'' field, set the test to be <code>s.endswith('1234')</code> (remember in Python both <code>'</code> and <code>"</code> are valid for string start/end characters).</li>
| + | |
− | <li><p>Press ''Capture 1'' a few more times, and check the color-coding has changed:</p>
| + | |
− | <p>[[File:ge_setup2.png|image]]</p></li></ol>
| + | |
− | | + | |
− | The next step is to tune the glitch offset to attempt to get a successful clock glitch. These steps are listed as follows:
| + | |
− | | + | |
− | <ol style="list-style-type: decimal;">
| + | |
− | <li>Make a new file called '''ge_adjustment.py'' with these contents:
| + | |
− | | + | |
− | <syntaxhighlight lang=python>
| + | |
− | class IterateGlitchParameters(object):
| + | |
− | def __init__(self, ge_window):
| + | |
− | self._starting_offset = -10
| + | |
− | self.ge_window = ge_window
| + | |
− | | + | |
− | def reset_glitch_to_default(self, scope, target, project):
| + | |
− | """ Set glitch settings to defaults. """
| + | |
− | self.offset = self._starting_offset
| + | |
− | | + | |
− | def change_glitch_parameters(self, scope, target, project):
| + | |
− | """ Example of simple glitch parameter modification function. """
| + | |
− | # This value is minimum clock offset/width increment
| + | |
− | self.offset += 0.390625
| + | |
− | | + | |
− | if self.offset > 40:
| + | |
− | self.offset = self._starting_offset
| + | |
− | | + | |
− | # Write data to scope
| + | |
− | scope.glitch.offset = self.offset
| + | |
− | | + | |
− | #You MUST tell the glitch explorer about the updated settings
| + | |
− | if self.ge_window:
| + | |
− | self.ge_window.add_data("Glitch Offset",scope.glitch.offset)
| + | |
− | | + | |
− | glitch_iterator = IterateGlitchParameters(self.glitch_explorer)
| + | |
− | self.aux_list.register(glitch_iterator.change_glitch_parameters, "before_trace")
| + | |
− | self.aux_list.register(glitch_iterator.reset_glitch_to_default, "before_capture")
| + | |
− | </syntaxhighlight>
| + | |
− | </li>
| + | |
− | <li><p>Assuming you still have the "Capture" working, you can simply find where you stored that script and hit ''Run''. You should see it execute successfully on the command line.:</p>
| + | |
− | <p>[[File:ge_step1_register.png|1000px]]</p></li>
| + | |
− | <li><p>Confirm you see the modules loaded in the ''Aux Settings'' tab:</p>
| + | |
− | <p>[[File:ge_step2_checkregister.png]]</p></li>
| + | |
− | <li><p>On the main GUI in the ''Scope Settings'' tab, change the following values for the ''Glitch Module'':</p>
| + | |
− | <ol style="list-style-type: lower-alpha;">
| + | |
− | <li>''Repeat'' set to 105.</li>
| + | |
− | <li>''Glitch Width (as % of period)'' set to 8.0.</li></ol>
| + | |
− | <p>These values will be used during the glitch explorer run. We have not specified anything for the tuning, so they will not be changed from whatever is already in the GUI.</p></li>
| + | |
− | <li><p>On the ''General Settings'' tab:</p>
| + | |
− | <ol style="list-style-type: lower-alpha;">
| + | |
− | <li>Set the ''Number of Traces'' to 121.</li></ol>
| + | |
− | </li>
| + | |
− | <li><p>With any luck, at least one of the glitches will be successful:</p>
| + | |
− | <p>If you get a reset (prints 'hello' again), you might need to reduce the "repeat" value. If you have no successful glitches, double-check all settings. You can continue to the next step anyway, as in that step we will also tune the "glitch width".</p></li></ol>
| + | |
− | | + | |
− | We may also need to tune the "Glitch Width". We can use knowledge of the successful glitch from the previous step to reduce our search space. In this case, assume we had a successful glitch with a width of 8.0 and offset of -2. We'll search around those values to see if we can achieve a more successful glitch performance.
| + | |
− | | + | |
− | ==== Arm ====
| + | |
− | This example will attempt to break out the loop in <code>glitch1()</code>. Moving ahead from where you were in [[#Automatically Triggering Glitch]], we will see how we can view the output of the target device in the glitch explorer.<ol style="list-style-type: decimal;">
| + | |
− | <li><p>Switch to the ''Target Settings'' tab, and set the ''Output Format'' to be <code>$GLITCH$</code>:</p>
| + | |
− | <p>[[File:output_glitch.png|image]]</p></li>
| + | |
− | <li>From the ''Tools'' menu select ''Glitch Monitor'' to open the glitch explorer.</li>
| + | |
− | <li><p>Press the ''Capture 1'' button a few times, and you should see the table populated with outputs:</p>
| + | |
− | <p>[[File:ge_setup1.png|image]]</p>
| + | |
− | <p>We want to mark them as "normal" or "glitch successful" to get the color-coding working appropriately.</p></li>
| + | |
− | <li>Double-click on a normal response, and copy the text. In the ''Normal Response'' field, we need to compare the magic variable <code>s</code> with that copied text. Do this by setting the ''Normal Response'' to be: <code>s == '\x00hello\nA'</code>.</li>
| + | |
− | <li>We want to mark a string ending with <code>1234</code> as a pass. Thus in the ''Successful Response'' field, set the test to be <code>s.endswith('1234')</code> (remember in Python both <code>'</code> and <code>"</code> are valid for string start/end characters).</li>
| + | |
− | <li><p>Press ''Capture 1'' a few more times, and check the color-coding has changed:</p>
| + | |
− | <p>[[File:ge_setup2.png|image]]</p></li></ol>
| + | |
− | | + | |
− | The next step is to tune the glitch offset to attempt to get a successful clock glitch. These steps are listed as follows:
| + | |
− | | + | |
− | <ol style="list-style-type: decimal;">
| + | |
− | <li>Make a new file called '<nowiki/>''ge_adjustment.py'' with these contents:
| + | |
− | | + | |
− | <syntaxhighlight lang="python">
| + | |
− | class IterateGlitchParameters(object):
| + | |
− | def __init__(self, ge_window):
| + | |
− | self._starting_offset = -45
| + | |
− | self.ge_window = ge_window
| + | |
− | | + | |
− | def reset_glitch_to_default(self, scope, target, project):
| + | |
− | """ Set glitch settings to defaults. """
| + | |
− | self.offset = self._starting_offset
| + | |
− | | + | |
− | def change_glitch_parameters(self, scope, target, project):
| + | |
− | """ Example of simple glitch parameter modification function. """
| + | |
− | # This value is minimum clock offset/width increment
| + | |
− | self.offset += 0.390625
| + | |
− | | + | |
− | if self.offset > 40:
| + | |
− | self.offset = self._starting_offset
| + | |
− | | + | |
− | # Write data to scope
| + | |
− | scope.glitch.offset = self.offset
| + | |
− | | + | |
− | #You MUST tell the glitch explorer about the updated settings
| + | |
− | if self.ge_window:
| + | |
− | self.ge_window.add_data("Glitch Offset",scope.glitch.offset)
| + | |
− | | + | |
− | glitch_iterator = IterateGlitchParameters(self.glitch_explorer)
| + | |
− | self.aux_list.register(glitch_iterator.change_glitch_parameters, "before_trace")
| + | |
− | self.aux_list.register(glitch_iterator.reset_glitch_to_default, "before_capture")
| + | |
− | </syntaxhighlight>
| + | |
− | </li>
| + | |
− | <li><p>Assuming you still have the "Capture" working, you can simply find where you stored that script and hit ''Run''. You should see it execute successfully on the command line.:</p>
| + | |
− | <p>[[File:ge_step1_register.png|1000px]]</p></li>
| + | |
− | <li><p>Confirm you see the modules loaded in the ''Aux Settings'' tab:</p>
| + | |
− | <p>[[File:ge_step2_checkregister.png]]</p></li>
| + | |
− | <li><p>On the main GUI in the ''Scope Settings'' tab, change the following values for the ''Glitch Module'':</p>
| + | |
− | <ol style="list-style-type: lower-alpha;">
| + | |
− | <li>''Repeat'' set to 1.</li>
| + | |
− | <li>''Glitch Width (as % of period)'' set to -10.</li></ol>
| + | |
− | <p>These values will be used during the glitch explorer run. We have not specified anything for the tuning, so they will not be changed from whatever is already in the GUI.</p></li>
| + | |
− | <li><p>On the ''General Settings'' tab:</p>
| + | |
− | <ol style="list-style-type: lower-alpha;">
| + | |
− | <li>Set the ''Number of Traces'' to 121.</li></ol>
| + | |
− | </li>
| + | |
− | <li><p>With any luck, at least one of the glitches will be successful:</p>
| + | |
− | <p>If you start getting ADC timeouts and the device stops responding, you may have to reduce ''Glitch Width (as % of period)'' to be closer to 0.</p></li></ol>
| + | |
− | | + | |
− | ==== Finishing the Tutorial ====
| + | |
− | We may also need to tune the "Glitch Width". We can use knowledge of the successful glitch from the previous step to reduce our search space. In this case, assume we had a successful glitch with a width of 8.0 and offset of -2. We'll search around those values to see if we can achieve a more successful glitch performance.
| + | |
− | | + | |
− | To continue the tutorial, the following steps will be taken:
| + | |
− | | + | |
− | <ol style="list-style-type: decimal;">
| + | |
− | <li>Modify the glitch parameter script to also loop through the Glitch Width. If you get stuck you can look at the example script earlier (in section [[#Parameter_Settings]]).</li>
| + | |
− | <li>To make glitching more likely, you'll also want to change the range of ''Glitch Offset'' to use values around successful ones. For example, positive glitch offsets typically work well for the XMEGA target, while negative ones work better for the CW303 Arm target.</li>
| + | |
− | <li>On the main GUI in the ''Scope Settings'' tab, adjust the ''Glitch Module'' repeat parameter to be 1. We are now attempting to achieve success with a single clock cycle being glitched.</li>
| + | |
− | <li>Still in the main GUI, adjust the number of traces per capture to be 1000. This reflects the number of iterations required to run through both loops (20 x 50).</li>
| + | |
− | <li>Hit the ''Capture Multi'' button and cross your fingers! Hopefully you will see a successful glitch for some combination of glitch width and offset. We aren't quite done yet, as you will also need to do some fine-tuning to achieve high reliability on the glitch.</li></ol>
| + | |
− | | + | |
− | Record some of the useful parameters by scrolling through the window (WARNING: changing parameters will clear the table, so record useful values now). In this example there was a success at Offset = 8.5%, and Width = 7.5%. Let's see how to fine-tune those values:
| + | |
− | | + | |
− | <ol style="list-style-type: decimal;">
| + | |
− | <li>Plug those values into the main GUI ''Glitch Module'' setting. If we use the ''Capture 1'' button values are taken from the main GUI, instead of the glitch explorer.</li>
| + | |
− | <li>Press the ''Capture 1'' button a few times. You'll note it records the output of the device, which may not be generating successful glitches (NB: the "offset" and "width" recorded in the table may be wrong when using the Capture 1 button, as the glitch explorer is not recording values from the main GUI correctly. This is a bug in the display only, the correct values are being sent to the device).</li>
| + | |
− | <li><p>Using arrow keys, nudge the ''Glitch Offset (fine adjust)'' up and down. Try performing a ''Capture 1'' to see if you are able to achieve a reliable glitch. In this example setting the fine adjust to 44 resulted in a very reliable glitch:</p>
| + | |
− | <p>[[File:ge_examplebasic2.png|image]]</p>
| + | |
− | <p>You might want to try seeing if there is an upper limit to this setting, and putting it mid-way between the lower and upper limits for generating a glitch.</p></li></ol>
| + | |
− | | + | |
− | Congrats! You've now performed some tuning to achieve a reliable glitch on the target device. The next step is to glitch something more fun - like a password check
| + | |
− | | + | |
− | == Glitching a Password Check ==
| + | |
− | | + | |
− | This assumes you now have a set of parameters which caused a reliable glitch. We'll now glitch past a password check, initially using our trigger as a crutch. The function of interest compares a received password to some known password. The <code>glitch3()</code> function looks as follows:
| + | |
− | | + | |
− | <pre>void glitch3(void)
| + | |
− | {
| + | |
− | char inp[16];
| + | |
− | char c = 'A';
| + | |
− | unsigned char cnt = 0;
| + | |
− | uart_puts("Password:");
| + | |
− | | + | |
− | while((c != '\n') & (cnt < 16)){
| + | |
− | c = getch();
| + | |
− | inp[cnt] = c;
| + | |
− | cnt++;
| + | |
− | }
| + | |
− | | + | |
− | char passwd[] = "touch";
| + | |
− | char passok = 1;
| + | |
− | | + | |
− | trigger_high();
| + | |
− | trigger_low();
| + | |
− | | + | |
− | //Simple test - doesn't check for too-long password!
| + | |
− | for(cnt = 0; cnt < 5; cnt++){
| + | |
− | if (inp[cnt] != passwd[cnt]){
| + | |
− | passok = 0;
| + | |
− | }
| + | |
− | }
| + | |
− | | + | |
− | if (!passok){
| + | |
− | uart_puts("Denied\n");
| + | |
− | } else {
| + | |
− | uart_puts("Welcome\n");
| + | |
− | }
| + | |
− | }</pre>
| + | |
− | The following assumes you have already completed the previous steps:
| + | |
− | | + | |
− | <ol style="list-style-type: decimal;">
| + | |
− | <li>Close the glitch explorer.</li>
| + | |
− | <li>Modify the file <code>glitchexample.c</code> to call <code>glitch3()</code> instead of <code>glitch1()</code>, which is to say simply change the main function called from <code>main()</code> to <code>glitch3()</code>.</li>
| + | |
− | <li>R<code>ebuild the firmware</code>.</li>
| + | |
− | <li>Program the target device with your <code>.hex</code> file.</li>
| + | |
− | <li>On the ''Target Settings'' tab, clear the ''Output Format'' field. That is remove the <code>$GLITCH$</code> text, as we are no longer using the glitch explorer. If you don't do this, you will not see any output of the device on the terminal emulator.</li>
| + | |
− | <li>Open the terminal emulator, and connect to it again (if you closed it).</li>
| + | |
− | <li><p>Reset the device, it should prompt you for a password. The correct password is <code>touch</code>, try both correct and incorrect passwords. The program as designed loops after a password try to prompt you again. You should see both correct and incorrect responses:</p>
| + | |
− | <p>[[File:password_normal.png|image]]</p></li>
| + | |
− | <li>On the ''Scope Settings'' tab, adjust the ''Timeout(s)'' to a larger value such as 20. We need a longer timeout to work with the serial terminal.</li>
| + | |
− | <li><p>Let's try a glitch insertion! Perform the following:</p>
| + | |
− | <blockquote><ol style="list-style-type: lower-alpha;">
| + | |
− | <li>Press the ''Capture 1'' button. This will reset the target and arm the glitch.</li>
| + | |
− | <li>Before the timeout, enter a wrong password such as <code>test</code> in the terminal and hit enter.</li>
| + | |
− | <li>See if you can get the wrong password accepted. If not, let's use the Glitch Explorer to automate the parameter adjustments.</li></ol>
| + | |
− | </blockquote></li>
| + | |
− | <li><p>Switching to the ''Auxiliary Settings'' tab, adjust the delay on the reset such that you have a ''150 mS'' delay. This will mean once the device resets there is a delay while it prints the startup message.</p>
| + | |
− | <p>[[File:aux_delay150ms.png|image]]</p></li>
| + | |
− | <li><p>Switch to the ''Target Settings'' tab:</p>
| + | |
− | <blockquote><ol style="list-style-type: lower-alpha;">
| + | |
− | <li>In the ''Go Command'' field, put the bad password such as <code>test\n</code>.</li>
| + | |
− | <li>In the ''Output Format'' field, put <code>$GLITCH$</code> to route the output to the glitch explorer.</li></ol>
| + | |
− | </blockquote></li>
| + | |
− | <li>Open the ''Glitch Explorer'', and press ''Capture 1''. You should see the ''Denied'' message come across.</li>
| + | |
− | <li>Generate a script to modify the 'offset' parameter in the glitch generator. You can always dump the scope parameters with ''scope'' at the command line in the ChipWhisperer-Capture to see all the fields.</li>
| + | |
− | <li>Set the number of traces on the ''General Settings'' tab to 200.</li>
| + | |
− | <li>On the main GUI, in the ''Scope Settings'' tab, ensure that you have the number of repeats on the ''Glitch Module'' set to 1. We will start with a single clock cycle glitched.</li>
| + | |
− | <li><p>Press ''Capture Multi''. Monitor the glitch outputs, you may see some errors or a successful glitch. Note that sometimes the errors are useful - here is an example where the glitched code actually dumped the password:</p>
| + | |
− | <blockquote><p>[[File:password_glitch_dump.png|image]]</p></blockquote>
| + | |
− | <p>More likely you might see a "Welcome" message indicating the password check was glitched:</p>
| + | |
− | <blockquote><p>[[File:password_glitch_success.png|image]]</p></blockquote></li>
| + | |
− | <li><p>If the previous step isn't successful, increase the "repeat" count on the ''Glitch Module'' section of the ''Scope Settings'' tab, and try again. In this example I actually needed a repeat count of "3" to get the successful "Welcome" message printed above.</p>
| + | |
− | <p>You can also increase the repeat count in the glitch explorer, which simply tries the same settings multiple times. You will likely find that the successful glitch does not have 100% success rate, so using a repeat count of 2 or 3 is helpful to increase your chances of success.</p></li></ol>
| + | |
− | | + | |
− | == Glitching Onward ==
| + | |
− | | + | |
− | This basic tutorial has introduced you to glitch attacks. They are a powerful tool for bypassing authentication in embedded hardware devices. There are many ways to expand your knowledge with additional practice, such as:
| + | |
− | | + | |
− | * Use manual glitches to try simply glitching past the prompt in <code>glitch3()</code>.
| + | |
− | * Completing [[Tutorial A3 VCC Glitch Attacks]], which introduces glitching via voltage instead of the clock.
| + | |
− | * Using the ChipWhisperer Python API to make GUI-less scripts. For examples of using scripting, see [[Making Scripts]].
| + | |
− | * Download some example source code (bootloaders, login prompts, etc) and port them to the AVR. See how you can glitch past security checks.
| + | |
− | * Use one of the IO triggers discussed in [[Tutorial_A1_Synchronization_to_Communication_Lines]].
| + | |
− | | + | |
− | == Links ==
| + | |
− | | + | |
− | {{Template:Tutorials}}
| + | |
− | [[Category:Tutorials]]
| + | |
This tutorial will introduce you to measuring the power consumption of a device under attack. It will demonstrate how you can view the difference between assembly instructions. In ChipWhisperer 5 Release, the software documentation is now held outside the wiki. See links below.
Running the tutorial uses the referenced Jupyter notebook file.