VCC Glitching with CW1200 on STM32F3 (CW308)

Just above the step section of the link I just posted, can you get it into bootloader mode?

Specifically this part:

To erase the FLASH memory, simply short the jumper labeled “ERASE” on the ChipWhisperer-Lite. Do this while the device is connected via micro-USB. The blue LED should stop flashing at this point, and will stay either on or off (depending when you shorted the jumper). This can be accomplished by anything metallic - for example using a screwdriver or tweezers:

Seems to work as I was able to have Bossa detect it as a serial port.

Were the correct LEDs lit?

Once this is accomplished, unplug and replug the micro-USB port. This will install a new driver (assuming you installed BOSSA already), and the red and blue LED should be only dimmly lit:

Also does BOSSA give you any errors?

No errors from BOSSA. The red and blue leds are dimmly lit, just like they were right after erase/reply.

No errors from BOSSA after writing the firmware? Can you use all of BOSSA’s functionality without error? (Verify, info, etc)?

The only thing I can think of is that you’re not letting it fully discharge after unplugging it. On your next attempt can you leave it unplugged for ~10 seconds?

Bossa’s messages are “Successful” (or whatever exact wording they are using), after both the Write and Verify processes.I repeated the process 3 times with similar results/behavior.

I indeed did not let it unplugged for 10 seconds. More like 2-3. Will try that tonight, hopefully the tests with the CW1200 might be completed at that time.

Speaking of which, did you notice anything unusual on the scope capture traces I posted?

There’s nothing unusual in your scope plots but it is hard to say that definitively. I’ve lost my CW308 so I’m waiting to get it back so I can compare.

This attack has given me grief as well as there’s a lot of variability to it. My hope is that the script above helps you find the correct parameters. It has worked for me before on the CWLITE.

Ok. Thanks alot on the feedback. I’ll get back to you with my test results and my battle with Boss :slight_smile:

Here’s a way to get the firmware version out. If this doesn’t work it means the driver or bootloader isn’t right. (Run this in a Python console)

import chipwhisperer.hardware.naeusb.naeusb as naeusb
​
usb = naeusb.NAEUSB()​

usb.con()​

print(usb.readFwVersion())

Good luck!

Well sadly that will not work since the device is no longer detected as a CW :slight_smile: “Failed to find USB device”.

I have tried to reprogram it, now disconnecting it for 30 seconds between operations. BOSSA write and verify works. Results are the same :frowning: Erasing it always works, so I guess that this is good news.

Also, every BOSSA feature seems to work, including Read and Info.

The CWLite is the one with the XMega target. P/N is NPCB-CWLITE-03. In case it helps somehow.

I have just noticed a difference from this image.

https://wiki.newae.com/File:Lights_prog.jpg

Led D9 on my board is much farther from JP1 than the one on the image. It is actually higher than R57, unlike the image that shows it under the resistance.

In case it might be a clue… As I said, I know this version was acquired around 2014.

By the way, about the signals, let me know when you get to check because I am still confused by 3 things:

1 - Single glitch in “single mode”. That sounds dumb, but since it loops over 20 iterations, I expected 20
2 - The fact that the voltage does not seem to go down to 0
3 - The fact that the shape of the glitches seem different between single and continuous.

CWLite fixed! Now that is weird.

For some reason, the firmware version I downloaded from github was 66kb. Then I noticed the one I had included in my installation was actually 57kb, which obviously got my attention.

So I pushed the 57kb one and now everything works. I redownloaded the one from github and now it is also 57kb.

So in short, I was trying to push a file that got messed up somehow, not sure how, but that is why it was not working. :roll_eyes: Odd that BOSSA did not complain about anything.

So much energy wasted…

Anyway, back to VCC glitching. To make it an even better day, my CW1200 tests stopped after 30 minutes last night… You know, sleep after 30 minutes…

Well… Closer, but not there yet:

I’m not a python guru so I’m having a rough time with the script you posted. Wherever I include it in the Jupyter tutorial, I always end up with the same error message:

Traceback (most recent call last):
File “/home/pafortin/chipwhisperer/software/chipwhisperer/hardware/naeusb/naeusb.py”, line 295, in txrx
response = self.open(serial_number=payload)
File “/home/pafortin/chipwhisperer/software/chipwhisperer/hardware/naeusb/naeusb.py”, line 345, in open
dev.set_configuration(0)
File “/home/pafortin/.local/lib/python3.7/site-packages/usb/core.py”, line 869, in set_configuration
self._ctx.managed_set_configuration(self, configuration)
File “/home/pafortin/.local/lib/python3.7/site-packages/usb/core.py”, line 102, in wrapper
return f(self, *args, **kwargs)
File “/home/pafortin/.local/lib/python3.7/site-packages/usb/core.py”, line 148, in managed_set_configuration
self.backend.set_configuration(self.handle, cfg.bConfigurationValue)
File “/home/pafortin/.local/lib/python3.7/site-packages/usb/backend/libusb0.py”, line 493, in set_configuration
_check(_lib.usb_set_configuration(dev_handle, config_value))
File “/home/pafortin/.local/lib/python3.7/site-packages/usb/backend/libusb0.py”, line 431, in _check
raise USBError(errmsg, ret)
usb.core.USBError: [Errno None] b’could not set config 0: Device or resource busy’
/home/pafortin/chipwhisperer/software/chipwhisperer/common/utils/util.py:474: UserWarning: getName function is deprecated use get_name instead.
warnings.warn(’{} function is deprecated use {} instead.’.format(cc_func, func.name))

The other “cells” of the tutorial are working, so I guess there is something in the script that just does not match… Like a double open-connection maybe?

Additional information: when running the scripts as standalone (the files you attached) and I get the same problem, so it does not seem to be some kind of “interference” from other code in the Jupyter tutorial.

Update. I was finally able to get the script running with the CW1200. I’ll paste the code below. It’s probably bad Python, but since it works, might end up being useful for someone else.

Now the bad news: it’s been running for over 30 hours now. I am a measurement #62767 right now and every single line of the CSV is an “Expected” one so far…

So here’s the code.

from enum import Enum     
from tqdm import tnrange
import matplotlib
import matplotlib.pyplot as plt
from collections import namedtuple
import time
import chipwhisperer as cw
import csv
import re 
from datetime import datetime

def reset_target(scope):
    if PLATFORM == "CW303" or PLATFORM == "CWLITEXMEGA":
        scope.io.pdic = 'low'
        time.sleep(0.05)
        scope.io.pdic = 'high_z' #XMEGA doesn't like pdic driven high
        time.sleep(0.05)
    else:  
        scope.io.nrst = 'low'
        time.sleep(0.05)
        scope.io.nrst = 'high'
        time.sleep(0.05)    
    
def rejection_builder():
    Range = namedtuple('Range', ['min', 'max', 'step'])

    step_size = (1/512)*100
    #step_size = 1

    min_value = -49
    max_value = min_value*-1
    
    #change the values here:
    width_range = Range(min_value, max_value, step_size)
    offset_range = Range(min_value, max_value, step_size)
    
    loop_ext_offset = 2185 
    scope.glitch.ext_offset = loop_ext_offset    
    loop_ext_max = 2186  
    
    dataReset = [[],[]]
    dataSuccess = [[],[]]
    dataExpected = [[],[]]
    
    print("Starting loop: ")
    
    #starting points
    loop_offset = offset_range.min
    loop_width = width_range.min  
    
    counter = 0
    
    timestr = time.strftime("%Y-%m-%d__%H%M%S") 
    csv_file_name = 'rejection_builder_log' + timestr + ".csv"
    f = open(csv_file_name,'w')
    f.write("Time[s],EXT_Offset, Offset, Width, Result, Raw Line \n")
    
    starting_time = datetime.utcnow()

    while loop_ext_offset < loop_ext_max: 
        loop_offset = offset_range.min

        while loop_offset < offset_range.max:
            loop_width = width_range.min
    
            while loop_width < width_range.max:

                time_now = datetime.utcnow()
            
                print("Last run at: {}".format(time_now.strftime("%H:%M:%S")))
                date_time_delta = (time_now - starting_time)
                
                seconds_elapsed = str(date_time_delta.total_seconds())

                scope.glitch.width = loop_width
                scope.glitch.offset = loop_offset
                scope.glitch.trigger_src = "ext_single"
                scope.glitch.repeat = 9
                
                counter += 1
            
                loop_width += width_range.step
                
                try:
                    result, line = test_for_success(3)
                except: 
                    setup()
                    
                if result == Results.Success:
                #if counter % 3:
                    dataSuccess[0].append(loop_offset)
                    dataSuccess[1].append(loop_width)
                    print("Loop width: {}, Loop offset: {} Loop ext_offset: {} Result: {} Raw Line: {}" .format(loop_width, loop_offset, loop_ext_offset, result, line))
                    print("success")
                elif result == Results.Expected:
                #elif counter % 2:
                    dataExpected[0].append(loop_offset)
                    dataExpected[1].append(loop_width)
                elif result == Results.Reset:
                #else:
                    dataReset[0].append(loop_offset)
                    dataReset[1].append(loop_width)
                
                line_list =  list(map(str.strip,line))
                
                line = ''.join(line_list) 
                result_string = str(result).strip("Result.")
                f.write("{},{},{},{},{},{}\n".format(seconds_elapsed, loop_ext_max, loop_offset, loop_width, result_string, line))
                        
                #print("Loop width: {}, Loop offset: {} Loop ext_offset: {} Result: {}" .format(loop_width, loop_offset, loop_ext_offset, result))
        
            loop_offset += offset_range.step
        loop_ext_offset += 1
        
    f.close()
    
    plt.scatter(dataReset[0], dataReset[1], marker='o')
    plt.scatter(dataSuccess[0], dataSuccess[1], marker='x')
    plt.scatter(dataExpected[0], dataExpected[1], marker='v')


    #plt.scatter(dataSuccess[0], dataSuccess[1], 'r--', dataReset[0], dataReset[1], 'bs', dataExpected[0], dataExpected[1], 'g^')

    plt.show()

class Results(Enum):
    Reset = 0
    Expected = 1
    Success = 2

# Looks for a gltiched output
# If a success is detected it will break regardless of attempts left 
# in order to reduce to a single data point of parameters 
def test_for_success(attempts):    
    
    reset_target(scope)
    
    target.flush()
    time.sleep(1)
    scope.arm()
    if SCOPETYPE == "OPENADC":
         scope.glitch.trigger_src = "ext_continuous"
    
    result = Results.Expected

    line = ""
    for j in range(attempts):
        
        line = ""
                
        while "\n" not in line:
            time.sleep(0.1)
            line += target.read()
        lines = line.split("\n") 
        if len(lines) > 1:
            line = lines[-1]
        else:
            line = ""
        
        while "\n" not in line:
            time.sleep(0.1)
            line += target.read()
            
        if "hello" in line:
            result = Results.Reset         
        nums = line.split(" ")
        try:
            if (int(nums[0]) != 40000 or int(nums[1]) != 200 or int(nums[2]) != 200 ) and nums[0] != '':        
                result = Results.Success  
                break      
        except ValueError as e:
            if(result != Results.Success):
                continue
            else:
                break
    if SCOPETYPE == "OPENADC":
         scope.glitch.trigger_src = "ext_single"
    return result, line  

fw_path = "../hardware/victims/firmware/glitch-simple/glitchsimple-{}.hex".format(PLATFORM)
    
prog = cw.programmers.STM32FProgrammer
scope = cw.scope()
    
time.sleep(0.05)
scope.default_setup()
reset_target(scope)

print(fw_path)
cw.program_target(scope, prog, fw_path)

target = cw.target(scope)


#setup()
rejection_builder()

Now at 92000. All “Expected”. :thinking:

Additional information: I am getting the buffer overrun warning on every iteration. Don’t know if it really is a problem or not.

157k. If my calculations are correct, I’m 60% through. Still nothing.

@aross : Now at 200k. All “Expected”. Any point on letting it run? Any idea of what could be the problem?

I mean, if it was packaged as a tutorial/example, I guess it should be working somehow? Unless there is something wrong with my setup?

Hmm, should have found something. I made an edit that puts the scope into continuous mode just for the duration of the attack so make sure you have that. I’m glad to see that script doesn’t crash at least.

I have some parameters working with my Chip Whisperer Lite in the single point glitch attack. Is the CW that you have with the STM32 or the MEGA?

Try this in the single point:

scope.glitch.width = 27.90
scope.glitch.ext_offset = 1000
scope.glitch.offset = -19.0
scope.glitch.repeat = 9

Once we’ve got it working with the CWLITEARM, we should be able to use that script to make sure it actually works. Then we can apply the same strategy to the CW308.