import serial
import time
import sys
import os
from tabulate import tabulate
from scope import Scope
from collections import deque
# Serial port settings
SERIAL_PORT = "/dev/ttyUSB0"
BAUD_RATE = 115200
TIMEOUT = 2
# Glitch configuration limits
INCREMENT_LEN = 1
LOWER_GLITCH_LEN = 41
UPPER_GLITCH_LEN = 60
INCREMENT_REPEAT = 1
LOWER_GLITCH_REPEAT = 1
UPPER_GLITCH_REPEAT = 30
INCREMENT_DELAY = 5
LOWER_DELAY_TIME = 0
UPPER_DELAY_TIME = 30
message_history = deque(maxlen=20)
def restartDeviceAndChall():
s.io.add(0, 0, delay=20000000)
s.io.add(0, 1, delay=20000000)
s.io.upload()
s.trigger()
time.sleep(5)
s.io.add(1, 1, delay=30000000)
s.io.add(1, 0, delay=30000000)
s.io.upload()
s.trigger()
time.sleep(5)
def restartChall():
s.io.add(1, 1, delay=30000000)
s.io.add(1, 0, delay=30000000)
s.io.upload()
s.trigger()
time.sleep(5)
def clear_console():
os.system('cls' if os.name == 'nt' else 'clear')
def store_message(message):
message_history.append(message)
def print_info(message):
store_message(f"[INFO] {message}")
def print_warning(message):
store_message(f"[WARNING] {message}")
def print_error(message):
store_message(f"[ERROR] {message}")
def print_last_x_messages(x):
# Ensure we print only the last 'x' messages, or all if less than x
for msg in list(message_history)[-x:]:
print(msg)
def format_elapsed_time(seconds):
days = seconds // (24 * 3600)
hours = (seconds % (24 * 3600)) // 3600
minutes = (seconds % 3600) // 60
seconds = seconds % 60
return f"{int(days)}d {int(hours)}h {int(minutes)}m {int(seconds)}s"
def print_table(
glitch_len, trigger_repeats, delay_time, elapsed_time):
headers = ["Glitch Len", "Repeats", "Delay", "Elapsed Time"]
data = [[f"{glitch_len} / {UPPER_GLITCH_LEN}",
f"{trigger_repeats} / {UPPER_GLITCH_REPEAT}",
f"{delay_time} / {UPPER_DELAY_TIME}",
elapsed_time]]
clear_console()
print_banner()
print(tabulate(data, headers=headers, tablefmt="fancy_grid"))
def connect_serial():
try:
ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=TIMEOUT)
print_info("Connected to serial port.")
time.sleep(1)
ser.flushInput()
version_info = ser.readline().decode("utf-8", errors="ignore").strip()
if version_info:
print_info(f"Connected to version: {version_info}")
else:
print_warning("No version information received. Device might be unresponsive.")
return ser
except serial.SerialException as e:
print_error(f"Could not open serial port {SERIAL_PORT}: {e}")
sys.exit(1)
def read_serial():
global glitch_len, trigger_repeats, delay_time
global UPPER_GLITCH_LEN, LOWER_GLITCH_LEN, INCREMENT_LEN
global UPPER_GLITCH_REPEAT, LOWER_GLITCH_REPEAT, INCREMENT_REPEAT
global UPPER_DELAY_TIME, LOWER_DELAY_TIME, INCREMENT_DELAY
glitch_len = LOWER_GLITCH_LEN
trigger_repeats = LOWER_GLITCH_REPEAT
delay_time = LOWER_DELAY_TIME
start_time = time.time()
last_restart_time = time.time()
restart_interval = 600 # 600 secs = 10 min
ser = connect_serial()
print_info("Restarting device and challenge")
#restartDeviceAndChall()
while True:
cycle_start_time = time.time()
line = ""
while time.time() - cycle_start_time < TIMEOUT:
if ser.in_waiting > 0:
char = ser.read().decode("utf-8", errors="ignore")
line += char
if char == '\n':
break
if line:
line = line.strip()
print_info(f"Received data: {line}")
line_lower = line.lower()
if "ctf" in line_lower:
print_info(f"Flag: {line}")
print_warning("Received 'ctf', exiting...")
print_table(glitch_len, trigger_repeats, delay_time, elapsed_time)
print_last_x_messages(10)
sys.exit()
elif "starting challenge" in line_lower:
print_info("Detected 'Starting Challenge'. Resetting glitch repeat count.")
if (glitch_len + trigger_repeats) % 2 == 0:
#UPPER_GLITCH_REPEAT = trigger_repeats
trigger_repeats -= INCREMENT_REPEAT
glitch_len += INCREMENT_LEN
else:
UPPER_GLITCH_LEN = glitch_len
glitch_len -= INCREMENT_LEN
trigger_repeats += INCREMENT_REPEAT
elif "hold" in line_lower:
print_info("Detected 'Hold'. Restarting Challenge.")
#restartChall()
else:
execute_scope_script(glitch_len, trigger_repeats, delay_time)
# 1. Increment delay time first
if delay_time < UPPER_DELAY_TIME:
delay_time += INCREMENT_DELAY
else:
delay_time = LOWER_DELAY_TIME # Reset delay time
# 2. Alternate between glitch_len and trigger_repeats when delay resets
if (glitch_len + trigger_repeats) % 2 == 0:
if glitch_len < UPPER_GLITCH_LEN:
glitch_len += INCREMENT_LEN
print_info(f"Incrementing glitch length: {glitch_len}")
elif (glitch_len > UPPER_GLITCH_LEN):
UPPER_GLITCH_LEN += INCREMENT_LEN
else:
glitch_len = LOWER_GLITCH_LEN # Reset glitch length
trigger_repeats += INCREMENT_REPEAT # Increment trigger repeats
print_info(f"Glitch length reset. Incrementing trigger repeats: {trigger_repeats}")
else:
if trigger_repeats < UPPER_GLITCH_REPEAT:
trigger_repeats += INCREMENT_REPEAT
print_info(f"Incrementing trigger repeats: {trigger_repeats}")
else:
if(glitch_len == UPPER_GLITCH_LEN):
trigger_repeats = LOWER_GLITCH_REPEAT # Reset trigger repeats
else:
trigger_repeats = LOWER_GLITCH_REPEAT
glitch_len += INCREMENT_LEN # Increment glitch length
print_info(f"Trigger repeats reset. Incrementing glitch length: {glitch_len}")
elapsed_time = format_elapsed_time(time.time() - start_time)
print_table(glitch_len, trigger_repeats, delay_time, elapsed_time)
# To print the last 3 messages
print_last_x_messages(10)
if time.time() - last_restart_time >= restart_interval:
print_info(f"10 min mark. Setting glitch length: 80 and restarting device")
UPPER_GLITCH_LEN = 80
#restartDeviceAndChall()
last_restart_time = time.time()
def execute_scope_script(glitch_len, trigger_repeats, delay):
s.glitch.repeat = glitch_len
s.glitch.ext_offset = delay
for _ in range(trigger_repeats):
s.trigger()
def print_banner():
print(" ___ _ _ _ _ _ _ ")
print(" / __| (_) |_ __| |_ ___ ___ ___ _ __ __ _| |_(_)__ ")
print(" | (_ | | | _/ _| ' \\___/ _ \\___| ' \\/ _` | _| / _|")
print(" \\___|_|_|\\__\\__|_||_| \\___/ |_|_|_\\__,_|\\__|_\\__|")
if __name__ == "__main__":
print_info("Starting Program")
s = Scope()
read_serial()