#!/usr/bin/env ruby # frozen_string_literal: false require 'pwn' require 'optparse' require 'json' opts = {} OptionParser.new do |options| options.banner = "USAGE: #{$PROGRAM_NAME} [opts] " options.on('-dDEV', '--block-dev=DEV', '') do |d| opts[:block_dev] = d end options.on('-bBAUD', '--baud=BAUD', '') do |b| opts[:baud] = b end options.on('-DDATABITS', '--data-bits=DATABITS', '') do |d| opts[:data_bits] = d end options.on('-sSTOPBITS', '--stop-bits=STOPBITS', '') do |s| opts[:stop_bits] = s end options.on('-pPARITY', '--parity=PARITY', '') do |p| opts[:parity] = p end options.on('-fFLOWCTRL', '--flow-control=FLOWCTRL', '') do |f| opts[:flow_control] = f end end.parse! if opts.empty? puts `#{$PROGRAM_NAME} --help` exit 1 end begin block_dev = opts[:block_dev] if File.exist?(opts[:block_dev]) baud = opts[:baud] data_bits = opts[:data_bits] stop_bits = opts[:stop_bits] parity = opts[:parity] flow_control = opts[:flow_control] msr206_obj = PWN::Plugins::MSR206.connect( block_dev: block_dev, baud: baud, data_bits: data_bits, stop_bits: stop_bits, parity: parity, flow_control: flow_control ) puts "- Welcome to #{File.basename($PROGRAM_NAME)} -" puts "Connected via: #{block_dev} @ #{msr206_obj[:serial_conn].modem_params}" puts "Flow Control: #{msr206_obj[:serial_conn].flow_control}" puts "Signals: #{msr206_obj[:serial_conn].signals}" exec_resp = PWN::Plugins::MSR206.exec( msr206_obj: msr206_obj, cmd: :simulate_power_cycle_warm_reset ) # TODO: Parse Binary Bits to Derive Readable Configuration # e.g. 'Read & Write All Three Tracks' if binary_resp == '11101111' # Probably better to split each bit and then evaluate # binary_resp_arr = binary_resp.chars # -------------------------------------------------- # Bit|Bit = 0 |Bit = 1 # -------------------------------------------------- # 0 |Track 1 Read not present |Track 1 Read present # 1 |Track 2 Read not present |Track 2 Read present # 2 |Track 3 Read not present |Track 3 Read present # 3 |not used – should be 0 |not used # 4 |Track 3 Write not present|Track 3 Write present # 5 |Track 2 Write not present|Track 2 Write present # 6 |Track 1 Write not present|Track 1 Write present # 7 |parity bit** |parity bit** exec_resp = PWN::Plugins::MSR206.exec( msr206_obj: msr206_obj, cmd: :configuration_request ) puts "Configuration Bits: #{exec_resp[:binary].first}" exec_resp = PWN::Plugins::MSR206.exec( msr206_obj: msr206_obj, cmd: :version_report ) puts "Firmware Version: #{exec_resp[:decoded]}" # Main Menu menu_msg = '' loop do unless menu_msg.include?('ERROR') exec_resp = PWN::Plugins::MSR206.exec( msr206_obj: msr206_obj, cmd: :green_flash ) end puts "\n>> MAIN MENU OPTIONS:" puts '[(R)ead Card]' puts '[(C)opy Card]' puts '[(E)dit Card]' puts '[(B)ackup Card]' puts '[(W)arm Reset]' puts '[(Q)uit]' puts menu_msg print 'MAIN MENU OPTION >>> ' menu_msg = '' option = gets.scrub.chomp.strip.upcase.to_sym case option when :R menu_msg = 'READY TO READ - PLEASE SWIPE CARD' # Read Card track_data = PWN::Plugins::MSR206.wait_for_swipe( msr206_obj: msr206_obj, type: :arm_to_read ) when :C menu_msg = 'READY TO COPY - PLEASE SWIPE ORIGINAL CARD' # Read Original Card track_data = PWN::Plugins::MSR206.wait_for_swipe( msr206_obj: msr206_obj, type: :arm_to_read ) # TODO: Save Original Card Contents # arm_to_write card to clone # read cloned card to verify successful write when :E menu_msg = 'READY TO EDIT - PLEASE SWIPE TARGET CARD' # Read Target Card track_data = PWN::Plugins::MSR206.wait_for_swipe( msr206_obj: msr206_obj, type: :arm_to_read ) # TODO: Save Original Card Contents # arm_to_write card to edit # read edited card to verify successful write when :B menu_msg = 'READY TO BACKUP - PLEASE SWIPE CARD' # Read Card track_data = PWN::Plugins::MSR206.wait_for_swipe( msr206_obj: msr206_obj, type: :arm_to_read ) file = '' backup_msg = '' loop do if backup_msg.empty? exec_resp = PWN::Plugins::MSR206.exec( msr206_obj: msr206_obj, cmd: :green_flash ) end print 'Enter File Name to Save Backup: ' file = gets.scrub.chomp.strip file_dir = File.dirname(file) break if Dir.exist?(file_dir) backup_msg = "\n****** ERROR: Directory #{file_dir} for #{file} does not exist ******" puts backup_msg exec_resp = PWN::Plugins::MSR206.exec( msr206_obj: msr206_obj, cmd: :green_off ) exec_resp = PWN::Plugins::MSR206.exec( msr206_obj: msr206_obj, cmd: :yellow_flash ) end File.write(file, "#{track_data.to_json}\n") exec_resp = PWN::Plugins::MSR206.exec( msr206_obj: msr206_obj, cmd: :yellow_off ) puts 'complete.' when :W exec_resp = PWN::Plugins::MSR206.exec( msr206_obj: msr206_obj, cmd: :simulate_power_cycle_warm_reset ) puts exec_resp.inspect when :Q exit else menu_msg = '****** ERROR: Invalid Menu Option Selected ******' exec_resp = PWN::Plugins::MSR206.exec( msr206_obj: msr206_obj, cmd: :green_off ) exec_resp = PWN::Plugins::MSR206.exec( msr206_obj: msr206_obj, cmd: :yellow_flash ) end end rescue StandardError => e raise e rescue SystemExit, Interrupt puts "\nGoodbye." ensure # Lights Off exec_resp = PWN::Plugins::MSR206.exec( msr206_obj: msr206_obj, cmd: :green_off ) exec_resp = PWN::Plugins::MSR206.exec( msr206_obj: msr206_obj, cmd: :yellow_off ) exec_resp = PWN::Plugins::MSR206.exec( msr206_obj: msr206_obj, cmd: :red_off ) msr206_obj = PWN::Plugins::MSR206.disconnect(msr206_obj: msr206_obj) if msr206_obj end