Part 2, Topic 3: Voltage Glitching to Dump Memory (MAIN)¶
NOTE: This lab references some (commercial) training material on ChipWhisperer.io. You can freely execute and use the lab per the open-source license (including using it in your own courses if you distribute similarly), but you must maintain notice about this source location. Consider joining our training course to enjoy the full experience.
SUMMARY: In the previous labs, we learned how voltage glitching can be used for a similar function as clock glitching. We also learned about how it has fewer limitations, but can be less reliable for certain target setups. It also changes a great deal based on the properties of the glitch circuit itself - even changing a wire can have a huge effect.
In this lab, we'll use what we learned in the last lab to again attack the vulnerable serial printing of the bootloader
LEARNING OUTCOMES:
- Applying previous glitch settings to new firmware
- Checking for success and failure when glitching
- Understanding how compiler optimizations can cause devices to behave in strange ways
The Situation¶
You should already know the situation from your previous attempts at glitching this bootloader (as well as what the flaw is). No need to do big long searches for parameters to try glitching at the beginning of the loop, just use values that worked well for the previous tutorial.
Be careful that you don't accidentally put the spot we're trying to glitch outside of glitch_spots
- if you used a repeat > 1, the actual spot being glitched might be at the end or in the middle of the repeat!
Like with the clock glitching version of this lab, we'll be using SimpleSerial V2 to speed up glitching
SCOPETYPE = 'OPENADC'
PLATFORM = 'CWLITEARM'
SS_VER='SS_VER_2_1'
CRYPTO_TARGET = 'TINYAES128C'
allowable_exceptions = None
VERSION = 'HARDWARE'
%%bash -s "$PLATFORM" "$SS_VER"
cd ../../../firmware/mcu/bootloader-glitch
make PLATFORM=$1 CRYPTO_TARGET=NONE -j SS_VER=$2
SS_VER set to SS_VER_2_1
SS_VER set to SS_VER_2_1
arm-none-eabi-gcc (15:9-2019-q4-0ubuntu1) 9.2.1 20191025 (release) [ARM/arm-9-branch revision 277599]
Copyright (C) 2019 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.
mkdir -p objdir-CWLITEARM
.
Welcome to another exciting ChipWhisperer target build!!
.
.
.
Compiling:
Compiling:
Compiling:
-en bootloader.c ...
-en decryption.c ...
-en .././simpleserial/simpleserial.c ...
.
.
Compiling:
Compiling:
-en .././hal//stm32f3/stm32f3_hal.c ...
-en .././hal//stm32f3/stm32f3_hal_lowlevel.c ...
.
.
-e Done!
Compiling:
Assembling: .././hal//stm32f3/stm32f3_startup.S
arm-none-eabi-gcc -c -mcpu=cortex-m4 -I. -x assembler-with-cpp -mthumb -mfloat-abi=soft -fmessage-length=0 -ffunction-sections -DF_CPU=7372800 -Wa,-gstabs,-adhlns=objdir-CWLITEARM/stm32f3_startup.lst -I.././simpleserial/ -I.././hal/ -I.././hal/ -I.././hal//stm32f3 -I.././hal//stm32f3/CMSIS -I.././hal//stm32f3/CMSIS/core -I.././hal//stm32f3/CMSIS/device -I.././hal//stm32f4/Legacy -I.././simpleserial/ -I.././crypto/ .././hal//stm32f3/stm32f3_startup.S -o objdir-CWLITEARM/stm32f3_startup.o
-en .././hal//stm32f3/stm32f3_sysmem.c ...
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
.
LINKING:
-en bootloader-CWLITEARM.elf ...
-e Done!
.
.
.
Creating load file for Flash: bootloader-CWLITEARM.hex
Creating load file for Flash: bootloader-CWLITEARM.bin
arm-none-eabi-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature bootloader-CWLITEARM.elf bootloader-CWLITEARM.hex
Creating load file for EEPROM: bootloader-CWLITEARM.eep
arm-none-eabi-objcopy -O binary -R .eeprom -R .fuse -R .lock -R .signature bootloader-CWLITEARM.elf bootloader-CWLITEARM.bin
arm-none-eabi-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 --no-change-warnings -O ihex bootloader-CWLITEARM.elf bootloader-CWLITEARM.eep || exit 0
.
.
Creating Extended Listing: bootloader-CWLITEARM.lss
arm-none-eabi-objdump -h -S -z bootloader-CWLITEARM.elf > bootloader-CWLITEARM.lss
Creating Symbol Table: bootloader-CWLITEARM.sym
arm-none-eabi-nm -n bootloader-CWLITEARM.elf > bootloader-CWLITEARM.sym
Size after:
text data bss dec hex filename
4600 124 1292 6016 1780 bootloader-CWLITEARM.elf
+--------------------------------------------------------
+ Default target does full rebuild each time.
+ Specify buildtarget == allquick == to avoid full rebuild
+--------------------------------------------------------
+--------------------------------------------------------
+ Built for platform CW-Lite Arm \(STM32F3\) with:
+ CRYPTO_TARGET = NONE
+ CRYPTO_OPTIONS = AES128C
+--------------------------------------------------------
#!/usr/bin/env python
# coding: utf-8
# In[ ]:
import chipwhisperer as cw
try:
if not scope.connectStatus:
scope.con()
except NameError:
scope = cw.scope(hw_location=(5, 3))
try:
if SS_VER == "SS_VER_2_1":
target_type = cw.targets.SimpleSerial2
elif SS_VER == "SS_VER_2_0":
raise OSError("SS_VER_2_0 is deprecated. Use SS_VER_2_1")
else:
target_type = cw.targets.SimpleSerial
except:
SS_VER="SS_VER_1_1"
target_type = cw.targets.SimpleSerial
try:
target = cw.target(scope, target_type)
except:
print("INFO: Caught exception on reconnecting to target - attempting to reconnect to scope first.")
print("INFO: This is a work-around when USB has died without Python knowing. Ignore errors above this line.")
scope = cw.scope(hw_location=(5, 3))
target = cw.target(scope, target_type)
print("INFO: Found ChipWhisperer😍")
# In[ ]:
if "STM" in PLATFORM or PLATFORM == "CWLITEARM" or PLATFORM == "CWNANO":
prog = cw.programmers.STM32FProgrammer
elif PLATFORM == "CW303" or PLATFORM == "CWLITEXMEGA":
prog = cw.programmers.XMEGAProgrammer
elif "neorv32" in PLATFORM.lower():
prog = cw.programmers.NEORV32Programmer
elif PLATFORM == "CW308_SAM4S" or PLATFORM == "CWHUSKY":
prog = cw.programmers.SAM4SProgrammer
else:
prog = None
# In[ ]:
import time
time.sleep(0.05)
scope.default_setup()
def reset_target(scope):
if PLATFORM == "CW303" or PLATFORM == "CWLITEXMEGA":
scope.io.pdic = 'low'
time.sleep(0.1)
scope.io.pdic = 'high_z' #XMEGA doesn't like pdic driven high
time.sleep(0.1) #xmega needs more startup time
elif "neorv32" in PLATFORM.lower():
raise IOError("Default iCE40 neorv32 build does not have external reset - reprogram device to reset")
elif PLATFORM == "CW308_SAM4S" or PLATFORM == "CWHUSKY":
scope.io.nrst = 'low'
time.sleep(0.25)
scope.io.nrst = 'high_z'
time.sleep(0.25)
else:
scope.io.nrst = 'low'
time.sleep(0.05)
scope.io.nrst = 'high_z'
time.sleep(0.05)
INFO: Found ChipWhisperer😍
scope.gain.mode changed from low to high scope.gain.gain changed from 0 to 30 scope.gain.db changed from 5.5 to 24.8359375 scope.adc.basic_mode changed from low to rising_edge scope.adc.samples changed from 24400 to 5000 scope.adc.trig_count changed from 10842027 to 21868502 scope.clock.adc_src changed from clkgen_x1 to clkgen_x4 scope.clock.adc_freq changed from 81677753 to 29910095 scope.clock.adc_rate changed from 81677753.0 to 29910095.0 scope.clock.clkgen_div changed from 1 to 26 scope.clock.clkgen_freq changed from 192000000.0 to 7384615.384615385 scope.io.tio1 changed from serial_tx to serial_rx scope.io.tio2 changed from serial_rx to serial_tx scope.io.hs2 changed from None to clkgen scope.glitch.mmcm_locked changed from True to False
fw_path = "../../../firmware/mcu/bootloader-glitch/bootloader-{}.hex".format(PLATFORM)
cw.program_target(scope, prog, fw_path)
Detected known STMF32: STM32F302xB(C)/303xB(C) Extended erase (0x44), this can take ten seconds or more Attempting to program 4723 bytes at 0x8000000 STM32F Programming flash...
STM32F Reading flash...
Verified flash OK, 4723 bytes
def reboot_flush():
reset_target(scope)
#Flush garbage too
target.flush()
scope.clock.adc_src = "clkgen_x1"
reboot_flush()
scope.adc.samples = 24000
Again, we're going to use a higher frequency on non-Husky ChipWhisperers. We'll also use the trigger length to get our ext_offset
range:
scope.clock.adc_src = "clkgen_x1"
def reboot_flush():
reset_target(scope)
#Flush garbage too
target.flush()
scope.clock.adc_src = "clkgen_x1"
reboot_flush()
scope.adc.samples = 24000
if PLATFORM == "CWLITEXMEGA":
scope.clock.clkgen_freq = 32E6
if SS_VER=='SS_VER_2_1':
target.baud = 230400*32/7.37
else:
target.baud = 38400*32/7.37
elif (PLATFORM == "CWLITEARM") or ("F3" in PLATFORM):
scope.clock.clkgen_freq = 24E6
if SS_VER=='SS_VER_2_1':
target.baud = 230400*24/7.37
else:
target.baud = 38400*24/7.37
reboot_flush()
scope.arm()
target.write("p516261276720736265747267206762206f686c207a76797821\n")
ret = scope.capture()
trig_count = scope.adc.trig_count
print(trig_count)
cw.plot(scope.get_last_trace())
4236