VCC Glitching with CW1200 on STM32F3 (CW308)

@aross I am baffled. Error again :frowning:


USBError Traceback (most recent call last)
~/chipwhisperer/software/chipwhisperer/capture/scopes/openadc_interface/naeusbchip.py in con(self, sn)
86 #sn = None
—> 87 found_id = self.dev.con(idProduct=nae_products, serial_number=sn)
88 except (IOError, ValueError):

~/chipwhisperer/software/chipwhisperer/capture/scopes/cwhardware/ChipWhispererLite.py in con(self, *args, **kwargs)
49 def con(self, *args, **kwargs):
—> 50 return self._cwusb.con(*args, **kwargs)
51

~/chipwhisperer/software/chipwhisperer/hardware/naeusb/naeusb.py in con(self, idProduct, connect_to_first, serial_number)
584
–> 585 self.usbseralizer.open(dev[‘sn’])
586 foundId = dev[‘pid’]

~/chipwhisperer/software/chipwhisperer/hardware/naeusb/naeusb.py in open(self, serial_number)
157 cmdpacket = self.make_cmd(self.OPEN, serial_number)
–> 158 return self.process_rx(self.txrx(tx=cmdpacket))
159

~/chipwhisperer/software/chipwhisperer/hardware/naeusb/naeusb.py in process_rx(self, inp)
150 if resp == self.ERROR:
–> 151 raise payload
152

USBError: [Errno None] None

During handling of the above exception, another exception occurred:

Warning Traceback (most recent call last)
in
** 214 target = cw.target(scope)**
** 215 **
–> 216 setup()
** 217 rejection_builder()**

in setup()
** 49 **
** 50 prog = cw.programmers.STM32FProgrammer**
—> 51 scope = cw.scope()
** 52 **
** 53 time.sleep(0.05)**

~/chipwhisperer/software/chipwhisperer/init.py in scope(scope_type, sn)
209 scope_type = get_cw_type(sn)
210 scope = scope_type()
–> 211 scope.con(sn)
212 return scope
213

~/chipwhisperer/software/chipwhisperer/capture/scopes/base.py in con(self, sn)
56
57 def con(self, sn=None):
—> 58 if self._con(sn):
59 self.connectStatus = True
60

~/chipwhisperer/software/chipwhisperer/capture/scopes/OpenADC.py in _con(self, sn)
201 def _con(self, sn=None):
202 if self.scopetype is not None:
–> 203 self.scopetype.con(sn)
204
205 self.qtadc.sc.usbcon = self.scopetype.ser._usbdev

~/chipwhisperer/software/chipwhisperer/capture/scopes/openadc_interface/naeusbchip.py in con(self, sn)
87 found_id = self.dev.con(idProduct=nae_products, serial_number=sn)
88 except (IOError, ValueError):
—> 89 raise Warning(‘Could not connect to “%s”. It may have been disconnected, is in an error state, or is being used by another tool.’ % self.getName())
90
91 if found_id != self.last_id:

Warning: Could not connect to “NewAE USB (CWLite/CW1200)”. It may have been disconnected, is in an error state, or is being used by another tool.

Error on the same exact line, despite the modifications.

“Regular” VCC Glitch tutorial still connects and works (with the Setup_Generic.ipynb script).

Above you said you were running it in Linux, what distro? I’m using Windows with the Linux subsystem and I’m not getting that error so there must be a difference in the drivers. I think your error is still valid though. Provided this is the only notebook running I think this fix should work for you. Basically I just removed all of the try stuff so it’s not expecting the scope to be connected to anything.

from enum import Enum     
from tqdm import tnrange
%matplotlib inline
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
import time

if "STM" in PLATFORM or PLATFORM == "CWLITEARM" or PLATFORM == "CWNANO":
    prog = cw.programmers.STM32FProgrammer
elif PLATFORM == "CW303" or PLATFORM == "CWLITEXMEGA":
    prog = cw.programmers.XMEGAProgrammer
else:
    prog = None

SCOPETYPE = 'OPENADC'
PLATFORM = 'CWLITEARM'
sample_size = 5

def reset_target(scope):
    time.sleep(0.05)
    scope.default_setup()

    scope.glitch.output = "glitch_only"
    scope.glitch.clk_src = "clkgen"
    scope.glitch.repeat = 9
    
    scope.io.glitch_hp = True
    scope.io.glitch_lp = False
    
    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 setup():
    fw_path = "../hardware/victims/firmware/glitch-simple/glitchsimple-{}.hex".format(PLATFORM)
    
    prog = cw.programmers.STM32FProgrammer

    time.sleep(0.05)
    scope.default_setup()
    reset_target(scope)

    print(fw_path)
    cw.program_target(scope, prog, fw_path)
    
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
    
    width_range = Range(27, 28, step_size)
    offset_range = Range(-20, -19, step_size)
    
    loop_ext_offset = 1000 
    scope.glitch.ext_offset = loop_ext_offset    
    loop_ext_max = 1001  
    
    dataReset = [[],[]]
    dataSuccess = [[],[]]
    dataExpected = [[],[]]
    
    result = Results.Expected
    
    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[ms],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:

                date_time_delta = (datetime.utcnow() - starting_time)
                
                seconds_elapsed = str(date_time_delta.total_seconds())

                scope.glitch.width = loop_width
                scope.glitch.ext_offset = loop_ext_offset
                scope.glitch.offset = loop_offset
                
                counter += 1
            
                loop_width += width_range.step
                
                try:
                    result, line = test_for_success(20)
                except: 
                    setup()
                    
                if result == Results.Success:
                    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:
                    dataExpected[0].append(loop_offset)
                    dataExpected[1].append(loop_width)
                elif result == Results.Reset:
                    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.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()
    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  


scope = cw.scope()
    
target = cw.target(scope)

setup()
rejection_builder()

Kali Linux 2019.3

I somehow doubt that the try stuff would be the issue since the Setup_Generic.ipynb script works with other tutorials, and it does include a try/except group right on the first block.

In fact, I tried to compare both scripts to figure out what could be different, and I can’t find anything that strikes me. Especially since running this script fails, and then running the original tutorial right away (after kernel reset of course) works.

I will try this new version again tonight. I might also try it in the Windows VM on the same computer (it’s a dual boot) to confirm whether the issue is related to this.

Good news: The script works!
Bad news: No successful glitch again :frowning:

I reallly don’t know… Would it be possible that, by some bad luck, I would have a jumper/switch on the CW308 that would not be set the right way?

I mean, the fact that I have not even got a reset baffles me…

@aross By the way, I managed to get the CWLite to work again. For some reason, in one of the USB ports of my laptop, I get the error message pasted here:

But once connected into another USB port, it worked (!!!)

Anyway. Point is that I tried running the same scripts with the CWLite, and the results are not different.

So that’s good news in that I assume that the issue is not with the CW1200. And that’s another arrow pointing towards the CW308 and the target. Or maybe the timing offset?

Or something else, I’m lacking ideas. Would still like to make sure that everything works fine before I try my luck onto another target. I’d prefer not to have doubts about the equipment/setup before going on to try something new…

I’ll get my pro back ASAP and compare some screen plots with you to rule out some hardware.

Glad to see the CWLITE is working! The fact you’re not getting any resets seems really weird. However, the CWLITE not working at all is strange. Does it have the XMEGA victim on it or the STM32F3?

STM32F3 on the CW308. Anyway I guess that trying to program the XMega with the STM32 firmware would not work?

But yeah, it is the STM32F3. I wish it was that easy :smiley:

The CWLite is the 2-part version with the XMega. I simply connected it to the CW308.

I’m beginning to wonder if wire attenuation is having some sort of effect here. My script was successfully ran on a CWLITE single piece (with STM32F3) right on it, but I’ve been struggling to get it to work on the CW308.

Just for consistency, how long is your VOUT to GLITCH connector cable?

The tests with the CW1200 were first conducted with the ones included in the CW1200 package, so 12 inches.

The ones I had with the CWLite are shorter, like 3-4 inches. The CWLite tests were ran with this smaller one.

Hi, Whilibarj!

I have experience in success Vcc glitch for CW1200 with STM32F3. For success result you must to know next:

  • use no long coax cable (it must be 15 cm or less);
  • in glitch_infinte() setup scope.glitch.repeat near 15-20 numbers;
  • the value scope.glitch.ext_offset not really matter it is enough 2180 for glitch_infinte()

For more effective pulse parameters searching do next:

  1. Connect oscilloscope to the UART_TX pin and seek the crashing of STM. It will seems like voltage falling.
  2. Set the pulse scope.glitch.width very high. If you see crashing, it mean that the scope.glitch.width is very high. Its right way.
  3. Fix the scope.glitch.offset parameter (value is not matter on this step) and start reducing the scope.glitch.width by stepping (step of scope.glitch.width and scope.glitch.offset in CW is multiple to 0.4) while the STM is not stopping crash.
  4. When you finding the boarder of crashing and normal working, fix the scope.glitch.width and start sweeping by the scope.glitch.offset in range (-49, 49).
  5. If you steel not find the glitch keep try to sweep in small range by scope.glitch.width and repeate 4th step.

The all of this you must to do because all of glitch-attacks is working by the boarder of crashing/normalworking of core the STM.
Remember that the success of glitch is random and it near to 1 - 5%. It means that the you have repeat attack for each parameter (width and offset) not less than 100 times.

You can find more information in previous branch Help needed with Tutorial A3 VCC Glitching XMEGA Target

Have luck.
Regards,
Nik.

1 Like

The two significant differences I see here are the length of the cable, and the repeat value (15-20 vs 9) when comparing with what @aross suggested before.

I know success rates should be low, but after more than 250k times, I had hopes for at least 1 reset! :slight_smile:

I will try to run these values over the weekend. Thanks for your input!

Ok. I’ve been running this for quite a while now. The good news is that I finally managed to get some resets. Still no success, but that’s progress. Right?

However, the results are bugging me again. Below is a chart of the results I got so far. You’ll notice that I stopped the sweeping around offset -25 because I wanted to finish within the current century… What bugs me? The resets I have seem to be totally dependent on the Offset rather than the Width of the glitch.

Somehow, I expected that, for example, the widest voltage drops would cause the chip to reset at pretty much anytime over its operation. Pretty much like if I simply unplugged the power supply. Instead, I got resets over a very narrow offset range, but all over the place in terms of width.

So yeah. Progress, but no success and still confusion.

Wondering if @aross managed to get something on his end. Guess we’ll find out after the holidays.

Hi, Whilibarj

Seem’s strange. What length of coax cable you use? I found that the length near 60 cm is very wourse (in complecte of CW1200). The deal start great when I changed this to 15 cm.

Did you try to find in positive range of width values?

Regards,
Nik.

I found a 15cm cable that I used to produce my last results. I did get some resets in the positive range of width values (check my graph above. horizontal axis is width, vertical is offset). I stopped because my sweep took way too long (this graph is 3 days of results!) and was confused by the apparent lack of impact of the width, and the apparent important impact of offset! I might have expected it for successful results, but for resets? I’m confused.

Also hoped @aross would have some results to share on his end.

Just in case someone has the same issue and ends up reading this thread. I revisited this topic after a few months, hoping that I might find something new, or that something might have changed a bit with the new release and new tutorial version.

Nothing. I just can’t find a way to glitch this damn loop on the stm32f3 target. I don’t even dare to try the password check or bootloader tutorials on this target!

Anyway, if someone with the same setup has been successful and would like to share details… Dead end so far.

In the new tutorials, we run the STM at a higher clock frequency, which seems to help things. Have you tried that?

Aex

True. I’ll rerun tests over the entire parameter space again. Should come back with an update within a few days :slight_smile:

Finally.

I was able to glitch the damn loop of tutorial fault 1_1. I needed an offset of -44.8 to get there.

I was also able to glitch the 1_2 one, but with totally different settings.

Unable to get anything out of 1_3.

Somehow surprised about 1_2 and 1_3 as the way the text is written, I assumed that just using the parameters from 1_1 should work as is, or close to it.