pwn 0.4.475 → 0.4.478

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 73e46f9f5d11b3a1678cc2b01ff31932ab1086a6bb950f4401c5b60f4379a018
4
- data.tar.gz: a4a54c020973d8b83e8692193ad5e3fcc3f0500dc8cf5967d10eaddcbfdc221a
3
+ metadata.gz: '09d06003d8060cade6a56174ce2237cb1d60044e596117e66b8dd882778bc971'
4
+ data.tar.gz: 00d295054465bae88230fd25606a00c10fe635478300b40409af241e99f20322
5
5
  SHA512:
6
- metadata.gz: 65c2271c0947f84645a6d25f981aa40cb5243bc56387fd9694925911c281745d51e264de03638003d745335a80a4e73212ad4e448115915b71a2c6a707cf63e5
7
- data.tar.gz: 33fda34f85dc4e1155d527452f6d7dec225ce85cd81018ece1fb7a7496236cde8bcacfe32ea1c1f6ade513c3aef0df9569be146621049be6fb3c50ef0230e078
6
+ metadata.gz: 5ddbe9550e2d6ecf8f480fc76ffaa2c44b04db21e53e3d617a7cc562ffa26a34e44db6aaee0ad1972c96533a3f91ecec97a1f8159a797db3e994405a7163904b
7
+ data.tar.gz: 309fb8124dbf9c76fa24b89b984b32f1e8f11869395e8e95d3bd6ba79f4438ed814475b5329dd0e5f6e660092e5d7f681cb002d4734a3c5f0af0b7a0fe7cd8d2
data/Gemfile CHANGED
@@ -33,7 +33,7 @@ gem 'ipaddress', '0.8.3'
33
33
  gem 'js-beautify', '0.1.8'
34
34
  gem 'json', '2.6.2'
35
35
  gem 'jsonpath', '1.1.2'
36
- gem 'jwt', '2.3.0'
36
+ gem 'jwt', '2.4.0'
37
37
  gem 'luhn', '1.0.2'
38
38
  gem 'mail', '2.7.1'
39
39
  gem 'mongo', '2.17.1'
@@ -59,7 +59,7 @@ gem 'rex', '2.0.13'
59
59
  gem 'rmagick', '4.2.5'
60
60
  gem 'rspec', '3.11.0'
61
61
  gem 'rtesseract', '3.1.2'
62
- gem 'rubocop', '1.30.0'
62
+ gem 'rubocop', '1.30.1'
63
63
  gem 'rubocop-rake', '0.6.0'
64
64
  gem 'rubocop-rspec', '2.11.1'
65
65
  gem 'ruby-audio', '1.6.1'
@@ -70,7 +70,7 @@ gem 'savon', '2.12.1'
70
70
  gem 'selenium-devtools', '0.102.0'
71
71
  gem 'serialport', '1.3.2'
72
72
  gem 'sinatra', '2.2.0'
73
- gem 'slack-ruby-client', '1.0.0'
73
+ gem 'slack-ruby-client', '1.1.0'
74
74
  gem 'socksify', '1.7.1'
75
75
  gem 'spreadsheet', '1.3.0'
76
76
  gem 'sqlite3', '1.4.2'
data/README.md CHANGED
@@ -37,7 +37,7 @@ $ rvm use ruby-3.1.2@pwn
37
37
  $ rvm list gemsets
38
38
  $ gem install --verbose pwn
39
39
  $ pwn
40
- pwn[v0.4.475]:001 >>> PWN.help
40
+ pwn[v0.4.478]:001 >>> PWN.help
41
41
  ```
42
42
 
43
43
  [![Installing the pwn Security Automation Framework](https://raw.githubusercontent.com/0dayInc/pwn/master/documentation/pwn_install.png)](https://youtu.be/G7iLUY4FzsI)
@@ -52,7 +52,7 @@ $ rvm use ruby-3.1.2@pwn
52
52
  $ gem uninstall --all --executables pwn
53
53
  $ gem install --verbose pwn
54
54
  $ pwn
55
- pwn[v0.4.475]:001 >>> PWN.help
55
+ pwn[v0.4.478]:001 >>> PWN.help
56
56
  ```
57
57
 
58
58
 
@@ -15,7 +15,7 @@ OptionParser.new do |options|
15
15
  opts[:block_dev] = d
16
16
  end
17
17
 
18
- options.on('-bBAUD', '--baud=BAUD', '<Optional - (defaults to 9600)>') do |b|
18
+ options.on('-bBAUD', '--baud=BAUD', '<Optional - (defaults to 9_600)>') do |b|
19
19
  opts[:baud] = b
20
20
  end
21
21
 
@@ -31,7 +31,7 @@ OptionParser.new do |options|
31
31
  opts[:parity] = p
32
32
  end
33
33
 
34
- options.on('-fFLOWCTRL', '--flow-control=FLOWCTRL', '<Optional - none||hard||soft (defaults to none)>') do |f|
34
+ options.on('-fFLOWCTRL', '--flow-control=FLOWCTRL', '<Optional - none||hard||soft (defaults to soft)>') do |f|
35
35
  opts[:flow_control] = f
36
36
  end
37
37
  end.parse!
@@ -68,26 +68,17 @@ begin
68
68
  cmd: :simulate_power_cycle_warm_reset
69
69
  )
70
70
 
71
- # TODO: Parse Binary Bits to Derive Readable Configuration
72
- # e.g. 'Read & Write All Three Tracks' if binary_resp == '11101111'
73
- # Probably better to split each bit and then evaluate
74
- # binary_resp_arr = binary_resp.chars
75
- # --------------------------------------------------
76
- # Bit|Bit = 0 |Bit = 1
77
- # --------------------------------------------------
78
- # 0 |Track 1 Read not present |Track 1 Read present
79
- # 1 |Track 2 Read not present |Track 2 Read present
80
- # 2 |Track 3 Read not present |Track 3 Read present
81
- # 3 |not used – should be 0 |not used
82
- # 4 |Track 3 Write not present|Track 3 Write present
83
- # 5 |Track 2 Write not present|Track 2 Write present
84
- # 6 |Track 1 Write not present|Track 1 Write present
85
- # 7 |parity bit** |parity bit**
86
- exec_resp = PWN::Plugins::MSR206.exec(
87
- msr206_obj: msr206_obj,
88
- cmd: :configuration_request
71
+ # Unsure if this switches the protocol from USI0 to USI1
72
+ # exec_resp = PWN::Plugins::MSR206.exec(
73
+ # msr206_obj: msr206_obj,
74
+ # cmd: :proto_usi1
75
+ # )
76
+ # puts exec_resp.inspect
77
+
78
+ config_hash = PWN::Plugins::MSR206.get_config(
79
+ msr206_obj: msr206_obj
89
80
  )
90
- puts "Configuration Bits: #{exec_resp[:binary].first}"
81
+ puts "Configuration: #{config_hash.inspect}"
91
82
 
92
83
  exec_resp = PWN::Plugins::MSR206.exec(
93
84
  msr206_obj: msr206_obj,
@@ -107,9 +98,10 @@ begin
107
98
 
108
99
  puts "\n>> MAIN MENU OPTIONS:"
109
100
  puts '[(R)ead Card]'
101
+ puts '[(B)ackup Card]'
110
102
  puts '[(C)opy Card]'
103
+ puts '[(L)oad Card from File]'
111
104
  puts '[(E)dit Card]'
112
- puts '[(B)ackup Card]'
113
105
  puts '[(W)arm Reset]'
114
106
  puts '[(Q)uit]'
115
107
  puts menu_msg
@@ -119,77 +111,41 @@ begin
119
111
 
120
112
  case option
121
113
  when :R
122
- menu_msg = 'READY TO READ - PLEASE SWIPE CARD'
114
+ menu_msg = 'READ CARD'
123
115
  # Read Card
124
- track_data = PWN::Plugins::MSR206.wait_for_swipe(
125
- msr206_obj: msr206_obj,
126
- type: :arm_to_read
116
+ track_data = PWN::Plugins::MSR206.read_card(
117
+ msr206_obj: msr206_obj
118
+ )
119
+ when :B
120
+ menu_msg = 'BACKUP CARD TO FILE'
121
+ # Read Card to Backup
122
+ track_data = PWN::Plugins::MSR206.backup_card(
123
+ msr206_obj: msr206_obj
127
124
  )
128
125
  when :C
129
- menu_msg = 'READY TO COPY - PLEASE SWIPE ORIGINAL CARD'
130
- # Read Original Card
131
- track_data = PWN::Plugins::MSR206.wait_for_swipe(
132
- msr206_obj: msr206_obj,
133
- type: :arm_to_read
126
+ menu_msg = 'COPY CARD'
127
+ # Copy Card
128
+ track_data = PWN::Plugins::MSR206.copy_card(
129
+ msr206_obj: msr206_obj
130
+ )
131
+ when :L
132
+ menu_msg = 'LOAD FROM FILE'
133
+ # Read Card to Backup
134
+ track_data = PWN::Plugins::MSR206.load_card_from_file(
135
+ msr206_obj: msr206_obj
134
136
  )
135
-
136
- # TODO: Save Original Card Contents
137
- # arm_to_write card to clone
138
- # read cloned card to verify successful write
139
137
  when :E
140
- menu_msg = 'READY TO EDIT - PLEASE SWIPE TARGET CARD'
138
+ menu_msg = 'EDIT'
141
139
  # Read Target Card
142
- track_data = PWN::Plugins::MSR206.wait_for_swipe(
143
- msr206_obj: msr206_obj,
144
- type: :arm_to_read
140
+ track_data = PWN::Plugins::MSR206.edit_card(
141
+ msr206_obj: msr206_obj
145
142
  )
146
143
 
147
144
  # TODO: Save Original Card Contents
148
145
  # arm_to_write card to edit
149
146
  # read edited card to verify successful write
150
- when :B
151
- menu_msg = 'READY TO BACKUP - PLEASE SWIPE CARD'
152
- # Read Card
153
- track_data = PWN::Plugins::MSR206.wait_for_swipe(
154
- msr206_obj: msr206_obj,
155
- type: :arm_to_read
156
- )
157
-
158
- file = ''
159
- backup_msg = ''
160
- loop do
161
- if backup_msg.empty?
162
- exec_resp = PWN::Plugins::MSR206.exec(
163
- msr206_obj: msr206_obj,
164
- cmd: :green_flash
165
- )
166
- end
167
-
168
- print 'Enter File Name to Save Backup: '
169
- file = gets.scrub.chomp.strip
170
- file_dir = File.dirname(file)
171
- break if Dir.exist?(file_dir)
172
-
173
- backup_msg = "\n****** ERROR: Directory #{file_dir} for #{file} does not exist ******"
174
- puts backup_msg
175
- exec_resp = PWN::Plugins::MSR206.exec(
176
- msr206_obj: msr206_obj,
177
- cmd: :green_off
178
- )
179
- exec_resp = PWN::Plugins::MSR206.exec(
180
- msr206_obj: msr206_obj,
181
- cmd: :yellow_flash
182
- )
183
- end
184
-
185
- File.write(file, "#{track_data.to_json}\n")
186
- exec_resp = PWN::Plugins::MSR206.exec(
187
- msr206_obj: msr206_obj,
188
- cmd: :yellow_off
189
- )
190
-
191
- puts 'complete.'
192
147
  when :W
148
+ menu_msg = 'WARM RESET'
193
149
  exec_resp = PWN::Plugins::MSR206.exec(
194
150
  msr206_obj: msr206_obj,
195
151
  cmd: :simulate_power_cycle_warm_reset
@@ -63,7 +63,7 @@ begin
63
63
  raw_results = {}
64
64
  raw_results[:query] = query
65
65
  raw_results[:results] = search_results
66
- raw_results_arr.push(raw_results.to_json)
66
+ raw_results_arr.push(raw_results)
67
67
 
68
68
  search_results[:matches].select do |m|
69
69
  f.puts "ORG: #{m[:org]} | PUBIP: #{m[:ip_str]} #{'*' * 36}"
@@ -73,7 +73,7 @@ begin
73
73
  end
74
74
  end
75
75
  end
76
- File.write(raw_query_results_file, raw_results_arr)
76
+ File.write(raw_query_results_file, raw_results_arr.to_json)
77
77
  rescue SystemExit, Interrupt
78
78
  puts "\nGoodbye."
79
79
  end
@@ -12,7 +12,7 @@ module PWN
12
12
  # data_bits: 'optional - (defaults to 8)',
13
13
  # stop_bits: 'optional - (defaults to 1)',
14
14
  # parity: 'optional - :even|:mark|:odd|:space|:none (defaults to :none),'
15
- # flow_control: 'optional - :none||:hard||:soft (defaults to :none)'
15
+ # flow_control: 'optional - :none|:hard|:soft (defaults to :soft)'
16
16
  # )
17
17
 
18
18
  public_class_method def self.connect(opts = {})
@@ -22,7 +22,7 @@ module PWN
22
22
  opts[:data_bits] = 8 unless opts[:data_bits]
23
23
  opts[:stop_bits] = 1 unless opts[:stop_bits]
24
24
  opts[:parity] = :none unless opts[:parity]
25
- opts[:flow_control] = :none unless opts[:flow_control]
25
+ opts[:flow_control] = :soft unless opts[:flow_control]
26
26
  msr206_obj = PWN::Plugins::Serial.connect(opts)
27
27
  rescue StandardError => e
28
28
  disconnect(msr206_obj: msr206_obj) unless msr206_obj.nil?
@@ -34,6 +34,8 @@ module PWN
34
34
  public_class_method def self.list_cmds
35
35
  # Returns an Array of Symbols
36
36
  cmds = %i[
37
+ proto_usi0
38
+ proto_usi1
37
39
  version_report
38
40
  simulate_power_cycle_warm_reset
39
41
  configuration_request
@@ -319,7 +321,7 @@ module PWN
319
321
  binary_byte_arr = []
320
322
  if raw_byte_arr
321
323
  raw_byte_arr.first.split.each do |byte_str|
322
- binary_byte_arr.push([byte_str].pack('H*').unpack1('B*').reverse)
324
+ binary_byte_arr.push([byte_str].pack('H*').unpack1('B*'))
323
325
  end
324
326
  end
325
327
 
@@ -336,6 +338,7 @@ module PWN
336
338
  private_class_method def self.parse_responses(opts = {})
337
339
  msr206_obj = opts[:msr206_obj]
338
340
  cmd = opts[:cmd]
341
+ cmd_bytes = opts[:cmd_bytes]
339
342
 
340
343
  keep_parsing_responses = true
341
344
  next_response_detected = false
@@ -343,22 +346,28 @@ module PWN
343
346
  response[:cmd] = cmd
344
347
  response[:cmd] ||= :na
345
348
 
349
+ if cmd_bytes.instance_of?(Array)
350
+ response[:cmd_bytes] = opts[:cmd_bytes].map do |base10_int|
351
+ "0x#{base10_int.to_s(16).rjust(2, '0')}"
352
+ end
353
+ end
354
+ response[:cmd_bytes] ||= :na
355
+
346
356
  raw_byte_arr = []
347
- a_cmd_r_len = 0
348
- last_a_cmd_r_len = 0
357
+ raw_byte_arr_len = 0
358
+ last_raw_byte_arr_len = 0
349
359
 
350
360
  parsed_cmd_resp_arr = []
351
- bytes_in_cmd_resp = 0
352
361
  cmd_resp = ''
353
362
 
354
363
  while keep_parsing_responses
355
364
  until next_response_detected
365
+ last_raw_byte_arr_len = raw_byte_arr_len
356
366
  raw_byte_arr = PWN::Plugins::Serial.response(serial_obj: msr206_obj)
357
367
  cmd_resp = raw_byte_arr.last
358
- bytes_in_cmd_resp = cmd_resp.split.length if cmd_resp
359
- a_cmd_r_len = raw_byte_arr.length
368
+ raw_byte_arr_len = raw_byte_arr.length
360
369
 
361
- next_response_detected = true if a_cmd_r_len > last_a_cmd_r_len
370
+ next_response_detected = true if raw_byte_arr_len > last_raw_byte_arr_len
362
371
  end
363
372
 
364
373
  case cmd_resp
@@ -393,15 +402,15 @@ module PWN
393
402
  when '7E'
394
403
  response[:msg] = :command_not_supported_by_hardware
395
404
  else
396
- response[:msg] = :na
405
+ response[:msg] = :response
397
406
  end
398
407
 
399
408
  next_response_detected = false
400
- last_a_cmd_r_len = a_cmd_r_len
409
+ last_raw_byte_arr_len = raw_byte_arr_len
401
410
  keep_parsing_responses = false
402
411
  end
403
412
 
404
- response[:raw] = raw_byte_arr
413
+ response[:hex] = raw_byte_arr
405
414
  response[:binary] = binary(raw_byte_arr: raw_byte_arr)
406
415
  response[:decoded] = decode(raw_byte_arr: raw_byte_arr)
407
416
  response
@@ -421,10 +430,15 @@ module PWN
421
430
  public_class_method def self.exec(opts = {})
422
431
  msr206_obj = opts[:msr206_obj]
423
432
  cmd = opts[:cmd].to_s.scrub.strip.chomp
424
- params = opts[:params].to_s.scrub.strip.chomp
433
+ params = opts[:params]
434
+ raise 'ERROR: params argument must be a byte array (e.g. [0x41]).' if params && !params.instance_of?(Array)
425
435
 
426
436
  params_bytes = []
427
437
  case cmd.to_sym
438
+ when :proto_usi0
439
+ cmd_bytes = [0x55, 0x53, 0x49, 0x30]
440
+ when :proto_usi1
441
+ cmd_bytes = [0x55, 0x53, 0x49, 0x31]
428
442
  when :resume_transmission_to_host
429
443
  cmd_bytes = [0x11]
430
444
  when :pause_transmission_to_host
@@ -459,11 +473,11 @@ module PWN
459
473
  cmd_bytes = [0x42]
460
474
  when :load_iso_std_data_for_writing_track3
461
475
  cmd_bytes = [0x43]
462
- when :tx_custom_data_forward_track1, :load_custom_data_for_writing_track1
476
+ when :load_custom_data_for_writing_track1
463
477
  cmd_bytes = [0x45]
464
- when :tx_custom_data_forward_track2, :load_custom_data_for_writing_track2
478
+ when :load_custom_data_for_writing_track2
465
479
  cmd_bytes = [0x46]
466
- when :tx_custom_data_forward_track3, :load_custom_data_for_writing_track3
480
+ when :load_custom_data_for_writing_track3
467
481
  cmd_bytes = [0x47]
468
482
  when :tx_error_data
469
483
  cmd_bytes = [0x49]
@@ -485,6 +499,12 @@ module PWN
485
499
  cmd_bytes = [0x52]
486
500
  when :tx_iso_std_data_track3
487
501
  cmd_bytes = [0x53]
502
+ when :tx_custom_data_forward_track1
503
+ cmd_bytes = [0x55]
504
+ when :tx_custom_data_forward_track2
505
+ cmd_bytes = [0x56]
506
+ when :tx_custom_data_forward_track3
507
+ cmd_bytes = [0x57]
488
508
  when :tx_passbook_data
489
509
  cmd_bytes = [0x58]
490
510
  when :arm_to_write_no_raw
@@ -532,7 +552,7 @@ module PWN
532
552
  end
533
553
 
534
554
  # If parameters to a command are set, append them.
535
- cmd_bytes += params_bytes unless params_bytes.empty?
555
+ cmd_bytes += params if params
536
556
  # Execute the command.
537
557
  PWN::Plugins::Serial.request(
538
558
  serial_obj: msr206_obj,
@@ -543,7 +563,8 @@ module PWN
543
563
  # Return an array of hashes.
544
564
  parse_responses(
545
565
  msr206_obj: msr206_obj,
546
- cmd: cmd.to_sym
566
+ cmd: cmd.to_sym,
567
+ cmd_bytes: cmd_bytes
547
568
  )
548
569
  rescue StandardError => e
549
570
  raise e
@@ -553,25 +574,18 @@ module PWN
553
574
  end
554
575
 
555
576
  # Supported Method Parameters::
556
- # PWN::Plugins::MSR206.wait_for_swipe(
577
+ # MSR206.wait_for_swipe(
557
578
  # msr206_obj: 'required - msr206_obj returned from #connect method'
558
- # type: 'required - swipe type'
579
+ # type: 'required - swipe type :arm_to_read || :arm_to_read_w_speed_prompts || :arm_to_write_no_raw || :arm_to_write_with_raw || :arm_to_write_with_raw_speed_prompts',
580
+ # encoding: 'required - :iso || :iso_alt || :raw',
581
+ # track_data: 'optional - track_data to write'
559
582
  # )
560
583
 
561
- public_class_method def self.wait_for_swipe(opts = {})
584
+ private_class_method def self.wait_for_swipe(opts = {})
562
585
  msr206_obj = opts[:msr206_obj]
563
586
  type = opts[:type].to_s.scrub.strip.chomp.to_sym
564
- types_arr = %i[
565
- arm_to_read
566
- arm_to_read_w_speed_prompts
567
- arm_to_write_no_raw
568
- arm_to_write_with_raw
569
- arm_to_write_with_raw_speed_prompts
570
- ]
571
-
572
- raise "ERROR Unsupported type in #wait_for_swipe - #{type}. Valid types:\n#{types_arr}" unless types_arr.include?(type)
573
-
574
- track_data = {}
587
+ encoding = opts[:encoding].to_s.scrub.strip.chomp.to_sym
588
+ track_data = opts[:track_data]
575
589
 
576
590
  exec_resp = exec(
577
591
  msr206_obj: msr206_obj,
@@ -583,96 +597,477 @@ module PWN
583
597
  cmd: :yellow_off
584
598
  )
585
599
 
586
- exec_resp = PWN::Plugins::MSR206.exec(
600
+ exec_resp = exec(
587
601
  msr206_obj: msr206_obj,
588
- cmd: type
602
+ cmd: :green_on
589
603
  )
590
604
 
605
+ track_data_arr = []
606
+
607
+ case type
608
+ when :arm_to_read,
609
+ :arm_to_read_w_speed_prompts
610
+
611
+ exec_resp = PWN::Plugins::MSR206.exec(
612
+ msr206_obj: msr206_obj,
613
+ cmd: type
614
+ )
615
+
616
+ print 'Ready to Read. Please Swipe Card Now:'
617
+ loop do
618
+ exec_resp = parse_responses(
619
+ msr206_obj: msr206_obj,
620
+ cmd: type
621
+ )
622
+
623
+ break if exec_resp[:msg] == :ack_command_completed
624
+ end
625
+
626
+ if encoding == :iso
627
+ cmds_arr = %i[
628
+ tx_iso_std_data_track1
629
+ tx_iso_std_data_track2
630
+ tx_iso_std_data_track3
631
+ ]
632
+ cmds_arr.each do |cmd|
633
+ puts "\n*** #{cmd.to_s.gsub('_', ' ').upcase} #{'*' * 17}"
634
+ exec_resp = exec(
635
+ msr206_obj: msr206_obj,
636
+ cmd: cmd
637
+ )
638
+ exec_resp[:encoding] = encoding
639
+ puts exec_resp[:decoded]
640
+ puts exec_resp.inspect
641
+ track_data_arr.push(exec_resp)
642
+ end
643
+ end
644
+
645
+ if encoding == :iso_alt
646
+ cmds_arr = %i[
647
+ alt_tx_iso_std_data_track1
648
+ alt_tx_iso_std_data_track2
649
+ alt_tx_iso_std_data_track3
650
+ ]
651
+
652
+ cmds_arr.each do |cmd|
653
+ params_arr = [0x31, 0x32, 0x33]
654
+ params_arr.each do |param|
655
+ puts "\n*** #{cmd.to_s.gsub('_', ' ').upcase} #{'*' * 17}"
656
+ exec_resp = exec(
657
+ msr206_obj: msr206_obj,
658
+ cmd: cmd,
659
+ params: [param]
660
+ )
661
+ exec_resp[:encoding] = encoding
662
+ puts exec_resp[:decoded]
663
+ puts exec_resp.inspect
664
+ track_data_arr.push(exec_resp)
665
+ end
666
+ end
667
+ end
668
+
669
+ if encoding == :raw
670
+ cmds_arr = %i[
671
+ tx_custom_data_forward_track1
672
+ tx_custom_data_forward_track2
673
+ tx_custom_data_forward_track3
674
+ ]
675
+
676
+ cmds_arr.each do |cmd|
677
+ params_arr = [0x33, 0x34, 0x35, 0x36, 0x37]
678
+ params_arr.each do |param|
679
+ puts "\n*** #{cmd.to_s.gsub('_', ' ').upcase} #{'*' * 17}"
680
+ # 2 byte command
681
+ exec_resp = exec(
682
+ msr206_obj: msr206_obj,
683
+ cmd: cmd,
684
+ params: [param]
685
+ )
686
+ exec_resp[:encoding] = encoding
687
+ puts exec_resp[:decoded]
688
+ puts exec_resp.inspect
689
+ track_data_arr.push(exec_resp)
690
+
691
+ # 3 byte command
692
+ exec_resp = exec(
693
+ msr206_obj: msr206_obj,
694
+ cmd: cmd,
695
+ params: [0x5f] + [param]
696
+ )
697
+ exec_resp[:encoding] = encoding
698
+ puts exec_resp[:decoded]
699
+ puts exec_resp.inspect
700
+ track_data_arr.push(exec_resp)
701
+ end
702
+ end
703
+ end
704
+ when :arm_to_write_no_raw,
705
+ :arm_to_write_with_raw,
706
+ :arm_to_write_with_raw_speed_prompts
707
+
708
+ if encoding == :iso
709
+ cmds_arr = %i[
710
+ load_iso_std_data_for_writing_track1
711
+ load_iso_std_data_for_writing_track2
712
+ load_iso_std_data_for_writing_track3
713
+ ]
714
+
715
+ cmds_arr.each_with_index do |cmd, track|
716
+ puts "\n*** #{cmd.to_s.gsub('_', ' ').upcase} #{'*' * 17}"
717
+ this_track = track_data[track][:decoded].chars.map do |c|
718
+ c.unpack1('H*').to_i(16)
719
+ end
720
+ this_track_w_eot = this_track + [0x04]
721
+ puts this_track_w_eot.inspect
722
+ exec_resp = exec(
723
+ msr206_obj: msr206_obj,
724
+ cmd: cmd,
725
+ params: this_track_w_eot
726
+ )
727
+ exec_resp[:encoding] = encoding
728
+ puts exec_resp[:decoded]
729
+ puts exec_resp.inspect
730
+ track_data_arr.push(exec_resp)
731
+ end
732
+ end
733
+
734
+ # if encoding == :iso_alt
735
+ # cmds_arr = %i[
736
+ # alt_load_iso_std_data_for_writing_track1
737
+ # alt_load_iso_std_data_for_writing_track2
738
+ # alt_load_iso_std_data_for_writing_track3
739
+ # ]
740
+
741
+ # cmds_arr.each do |cmd|
742
+ # puts "\n*** #{cmd.to_s.gsub('_', ' ').upcase} #{'*' * 17}"
743
+ # exec_resp = exec(
744
+ # msr206_obj: msr206_obj,
745
+ # cmd: cmd
746
+ # )
747
+ # exec_resp[:encoding] = encoding
748
+ # puts exec_resp[:decoded]
749
+ # puts exec_resp.inspect
750
+ # track_data_arr.push(exec_resp)
751
+ # end
752
+ # end
753
+
754
+ # if encoding == :raw
755
+ # cmds_arr = %i[
756
+ # load_custom_data_for_writing_track1
757
+ # load_custom_data_for_writing_track2
758
+ # load_custom_data_for_writing_track3
759
+ # ]
760
+
761
+ # cmds_arr.each do |cmd|
762
+ # puts "\n*** #{cmd.to_s.gsub('_', ' ').upcase} #{'*' * 17}"
763
+ # exec_resp = exec(
764
+ # msr206_obj: msr206_obj,
765
+ # cmd: cmd
766
+ # )
767
+ # exec_resp[:encoding] = encoding
768
+ # puts exec_resp[:decoded]
769
+ # puts exec_resp.inspect
770
+ # track_data_arr.push(exec_resp)
771
+ # end
772
+ # end
773
+
774
+ exec_resp = PWN::Plugins::MSR206.exec(
775
+ msr206_obj: msr206_obj,
776
+ cmd: type
777
+ )
778
+
779
+ print 'Ready to Write. Please Swipe Card Now:'
780
+ loop do
781
+ exec_resp = parse_responses(
782
+ msr206_obj: msr206_obj,
783
+ cmd: type
784
+ )
785
+
786
+ break if exec_resp[:msg] == :ack_command_completed
787
+ end
788
+ else
789
+ raise "ERROR Unsupported type in #wait_for_swipe - #{type}"
790
+ end
791
+
792
+ track_data_arr
793
+ rescue StandardError => e
794
+ raise e
795
+ ensure
591
796
  exec_resp = exec(
592
797
  msr206_obj: msr206_obj,
593
- cmd: :green_on
798
+ cmd: :green_off
594
799
  )
800
+ end
595
801
 
596
- exec_resp = PWN::Plugins::MSR206.exec(
802
+ # Supported Method Parameters::
803
+ # PWN::Plugins::MSR206.read_card(
804
+ # msr206_obj: 'required - msr206_obj returned from #connect method'
805
+ # )
806
+
807
+ public_class_method def self.read_card(opts = {})
808
+ msr206_obj = opts[:msr206_obj]
809
+ type = opts[:type].to_s.scrub.strip.chomp.to_sym
810
+
811
+ encoding = :waiting_for_selection
812
+ loop do
813
+ puts "\nENCODING OPTIONS:"
814
+ puts '[(I)SO Standard]'
815
+ puts '[(A)LT ISO Standard]'
816
+ puts '[(R)aw]'
817
+ print 'ENCODING TYPE >>> '
818
+ encoding_choice = gets.scrub.chomp.strip.upcase.to_sym
819
+
820
+ case encoding_choice
821
+ when :I
822
+ encoding = :iso
823
+ break
824
+ when :A
825
+ encoding = :iso_alt
826
+ break
827
+ when :R
828
+ encoding = :raw
829
+ break
830
+ end
831
+ end
832
+
833
+ wait_for_swipe(
597
834
  msr206_obj: msr206_obj,
598
- cmd: :card_edge_detect
835
+ type: :arm_to_read,
836
+ encoding: encoding
837
+ )
838
+ rescue StandardError => e
839
+ raise e
840
+ end
841
+
842
+ # Supported Method Parameters::
843
+ # PWN::Plugins::MSR206.backup_card(
844
+ # msr206_obj: 'required - msr206_obj returned from #connect method'
845
+ # )
846
+
847
+ public_class_method def self.backup_card(opts = {})
848
+ msr206_obj = opts[:msr206_obj]
849
+ type = opts[:type].to_s.scrub.strip.chomp.to_sym
850
+
851
+ # Read Card to Backup
852
+ track_data = read_card(
853
+ msr206_obj: msr206_obj
599
854
  )
600
855
 
601
- print 'Ready. Please Swipe Card Now:'
856
+ file = ''
857
+ backup_msg = ''
602
858
  loop do
603
- exec_resp = parse_responses(
859
+ if backup_msg.empty?
860
+ exec_resp = exec(
861
+ msr206_obj: msr206_obj,
862
+ cmd: :green_flash
863
+ )
864
+ end
865
+
866
+ print 'Enter File Name to Save Backup: '
867
+ file = gets.scrub.chomp.strip
868
+ file_dir = File.dirname(file)
869
+ break if Dir.exist?(file_dir)
870
+
871
+ backup_msg = "\n****** ERROR: Directory #{file_dir} for #{file} does not exist ******"
872
+ puts backup_msg
873
+ exec_resp = exec(
604
874
  msr206_obj: msr206_obj,
605
- cmd: :card_edge_detect
875
+ cmd: :green_off
876
+ )
877
+ exec_resp = exec(
878
+ msr206_obj: msr206_obj,
879
+ cmd: :yellow_flash
606
880
  )
607
-
608
- break if exec_resp[:msg] == :ack_command_completed
609
881
  end
610
882
 
611
- puts "\n*** ISO Track Format: Standard #{'*' * 17}"
612
- print 'TRACK 1 >>> '
883
+ File.write(file, "#{track_data.to_json}\n")
613
884
  exec_resp = exec(
614
885
  msr206_obj: msr206_obj,
615
- cmd: :tx_iso_std_data_track1
886
+ cmd: :yellow_off
616
887
  )
617
- puts exec_resp[:decoded]
618
- puts exec_resp.inspect
619
- track_data[:track1] = exec_resp
620
-
621
- # (1..3).each do |n|
622
- # print ">> Track 1 (ALT DATA) ISO Track Format: #{n}\n"
623
- # exec_resp = exec(
624
- # msr206_obj: msr206_obj,
625
- # cmd: :alt_tx_iso_std_data_track1,
626
- # params: [n.to_s]
627
- # )
628
- # puts exec_resp.inspect
629
- # end
630
-
631
- print "\nTRACK 2 >>> "
632
- exec_resp = exec(
888
+
889
+ puts 'complete.'
890
+
891
+ track_data
892
+ rescue StandardError => e
893
+ raise e
894
+ end
895
+
896
+ # Supported Method Parameters::
897
+ # PWN::Plugins::MSR206.copy_card(
898
+ # msr206_obj: 'required - msr206_obj returned from #connect method'
899
+ # )
900
+
901
+ public_class_method def self.copy_card(opts = {})
902
+ msr206_obj = opts[:msr206_obj]
903
+
904
+ # Read Card to Backup
905
+ track_data = backup_card(
906
+ msr206_obj: msr206_obj
907
+ )
908
+
909
+ encoding = track_data.first[:encoding] if track_data.length == 3
910
+ # TODO: Save Original Card Contents
911
+ track_data = wait_for_swipe(
633
912
  msr206_obj: msr206_obj,
634
- cmd: :tx_iso_std_data_track2
913
+ type: :arm_to_write_no_raw,
914
+ encoding: encoding,
915
+ track_data: track_data
635
916
  )
636
- puts exec_resp[:decoded]
637
- puts exec_resp.inspect
638
- track_data[:track2] = exec_resp
639
-
640
- # (1..3).each do |n|
641
- # print ">> Track 2 (ALT DATA) ISO Track Format: #{n}\n"
642
- # exec_resp = exec(
643
- # msr206_obj: msr206_obj,
644
- # cmd: :alt_tx_iso_std_data_track2,
645
- # params: [n.to_s]
646
- # )
647
- # puts exec_resp.inspect
648
- # end
649
-
650
- print "\nTRACK 3 >>> "
917
+
918
+ puts 'complete.'
919
+
920
+ track_data
921
+ rescue StandardError => e
922
+ raise e
923
+ end
924
+
925
+ # Supported Method Parameters::
926
+ # PWN::Plugins::MSR206.load_card_from_file(
927
+ # msr206_obj: 'required - msr206_obj returned from #connect method'
928
+ # )
929
+
930
+ public_class_method def self.load_card_from_file(opts = {})
931
+ msr206_obj = opts[:msr206_obj]
932
+
933
+ file = ''
934
+ restore_msg = ''
935
+ loop do
936
+ if restore_msg.empty?
937
+ exec_resp = exec(
938
+ msr206_obj: msr206_obj,
939
+ cmd: :green_flash
940
+ )
941
+ end
942
+
943
+ print 'Enter File Name to Restore to Card: '
944
+ file = gets.scrub.chomp.strip
945
+ break if File.exist?(file)
946
+
947
+ restore_msg = "\n****** ERROR: #{file} does not exist ******"
948
+ puts restore_msg
949
+ exec_resp = exec(
950
+ msr206_obj: msr206_obj,
951
+ cmd: :green_off
952
+ )
953
+ exec_resp = exec(
954
+ msr206_obj: msr206_obj,
955
+ cmd: :yellow_flash
956
+ )
957
+ end
958
+
959
+ track_data = JSON.parse(
960
+ File.read(file),
961
+ symbolize_names: true
962
+ )
963
+
651
964
  exec_resp = exec(
652
965
  msr206_obj: msr206_obj,
653
- cmd: :tx_iso_std_data_track3
966
+ cmd: :yellow_off
967
+ )
968
+
969
+ # Read Card from Backup
970
+ encoding = track_data.first[:encoding] if track_data.length == 3
971
+
972
+ # TODO: Save Original Card Contents
973
+ track_data = wait_for_swipe(
974
+ msr206_obj: msr206_obj,
975
+ type: :arm_to_write_no_raw,
976
+ encoding: encoding,
977
+ track_data: track_data
654
978
  )
655
- puts exec_resp[:decoded]
656
- puts exec_resp.inspect
657
- track_data[:track3] = exec_resp
658
-
659
- # (1..3).each do |n|
660
- # print ">> Track 3 (ALT DATA) ISO Track Format: #{n}\n"
661
- # exec_resp = exec(
662
- # msr206_obj: msr206_obj,
663
- # cmd: :alt_tx_iso_std_data_track3,
664
- # params: [n.to_s]
665
- # )
666
- # puts exec_resp.inspect
667
- # end
979
+
980
+ puts 'complete.'
981
+
668
982
  track_data
669
983
  rescue StandardError => e
670
984
  raise e
671
- ensure
672
- exec_resp = exec(
985
+ end
986
+
987
+ # Supported Method Parameters::
988
+ # PWN::Plugins::MSR206.edit_card(
989
+ # msr206_obj: 'required - msr206_obj returned from #connect method'
990
+ # )
991
+
992
+ public_class_method def self.edit_card(opts = {})
993
+ msr206_obj = opts[:msr206_obj]
994
+
995
+ # Read Card to Backup
996
+ track_data = backup_card(
997
+ msr206_obj: msr206_obj
998
+ )
999
+
1000
+ # TODO: Inline Editing
1001
+
1002
+ encoding = track_data.first[:encoding] if track_data.length == 3
1003
+ # TODO: Save Original Card Contents
1004
+ track_data = wait_for_swipe(
673
1005
  msr206_obj: msr206_obj,
674
- cmd: :green_off
1006
+ type: :arm_to_write_no_raw,
1007
+ encoding: encoding
1008
+ )
1009
+
1010
+ puts 'complete.'
1011
+
1012
+ track_data
1013
+ rescue StandardError => e
1014
+ raise e
1015
+ end
1016
+
1017
+ # Supported Method Parameters::
1018
+ # PWN::Plugins::MSR206.get_config(
1019
+ # msr206_obj: 'required - msr206_obj returned from #connect method'
1020
+ # )
1021
+
1022
+ public_class_method def self.get_config(opts = {})
1023
+ msr206_obj = opts[:msr206_obj]
1024
+
1025
+ # --------------------------------------------------
1026
+ # Bit|Bit = 0 |Bit = 1
1027
+ # --------------------------------------------------
1028
+ # 0 |Track 1 Read not present |Track 1 Read present
1029
+ # 1 |Track 2 Read not present |Track 2 Read present
1030
+ # 2 |Track 3 Read not present |Track 3 Read present
1031
+ # 3 |not used – should be 0 |not used
1032
+ # 4 |Track 3 Write not present|Track 3 Write present
1033
+ # 5 |Track 2 Write not present|Track 2 Write present
1034
+ # 6 |Track 1 Write not present|Track 1 Write present
1035
+ # 7 |parity bit** |parity bit**
1036
+ exec_resp = PWN::Plugins::MSR206.exec(
1037
+ msr206_obj: msr206_obj,
1038
+ cmd: :configuration_request
675
1039
  )
1040
+
1041
+ config_arr = exec_resp[:binary].first.reverse.chars
1042
+ config_hash = {}
1043
+ config_arr.each_with_index do |bit_str, i|
1044
+ bit = bit_str.to_i
1045
+ config_hash[:track1_read] = false if bit.zero? && i.zero?
1046
+ config_hash[:track1_read] = true if bit == 1 && i.zero?
1047
+
1048
+ config_hash[:track2_read] = false if bit.zero? && i == 1
1049
+ config_hash[:track2_read] = true if bit == 1 && i == 1
1050
+
1051
+ config_hash[:track3_read] = false if bit.zero? && i == 2
1052
+ config_hash[:track3_read] = true if bit == 1 && i == 2
1053
+
1054
+ config_hash[:not_used] if i == 3
1055
+
1056
+ config_hash[:track1_write] = false if bit.zero? && i == 4
1057
+ config_hash[:track1_write] = true if bit == 1 && i == 4
1058
+
1059
+ config_hash[:track2_write] = false if bit.zero? && i == 5
1060
+ config_hash[:track2_write] = true if bit == 1 && i == 5
1061
+
1062
+ config_hash[:track3_write] = false if bit.zero? && i == 6
1063
+ config_hash[:track3_write] = true if bit == 1 && i == 6
1064
+
1065
+ config_hash[:parity] = true if bit == 1 && i == 7
1066
+ end
1067
+
1068
+ config_hash
1069
+ rescue StandardError => e
1070
+ raise e
676
1071
  end
677
1072
 
678
1073
  # Supported Method Parameters::
@@ -706,7 +1101,7 @@ module PWN
706
1101
  data_bits: 'optional (defaults to 8)',
707
1102
  stop_bits: 'optional (defaults to 1)',
708
1103
  parity: 'optional - :even|:mark|:odd|:space|:none (defaults to :none),'
709
- flow_control: 'optional - :none||:hard||:soft (defaults to :none)'
1104
+ flow_control: 'optional - :none|:hard|:soft (defaults to :none)'
710
1105
  )
711
1106
 
712
1107
  cmds = #{self}.list_cmds
@@ -44,7 +44,7 @@ module PWN
44
44
  opts[:stop_bits].to_i
45
45
  end
46
46
 
47
- case opts[:parity]
47
+ case opts[:parity].to_s.to_sym
48
48
  when :even
49
49
  parity = SerialPort::EVEN
50
50
  when :mark
@@ -57,7 +57,7 @@ module PWN
57
57
  parity = SerialPort::NONE
58
58
  end
59
59
 
60
- case opts[:flow_control]
60
+ case opts[:flow_control].to_s.to_sym
61
61
  when :hard
62
62
  flow_control = SerialPort::HARD
63
63
  when :soft
data/lib/pwn/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PWN
4
- VERSION = '0.4.475'
4
+ VERSION = '0.4.478'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pwn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.475
4
+ version: 0.4.478
5
5
  platform: ruby
6
6
  authors:
7
7
  - 0day Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-04 00:00:00.000000000 Z
11
+ date: 2022-06-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -310,14 +310,14 @@ dependencies:
310
310
  requirements:
311
311
  - - '='
312
312
  - !ruby/object:Gem::Version
313
- version: 2.3.0
313
+ version: 2.4.0
314
314
  type: :runtime
315
315
  prerelease: false
316
316
  version_requirements: !ruby/object:Gem::Requirement
317
317
  requirements:
318
318
  - - '='
319
319
  - !ruby/object:Gem::Version
320
- version: 2.3.0
320
+ version: 2.4.0
321
321
  - !ruby/object:Gem::Dependency
322
322
  name: luhn
323
323
  requirement: !ruby/object:Gem::Requirement
@@ -674,14 +674,14 @@ dependencies:
674
674
  requirements:
675
675
  - - '='
676
676
  - !ruby/object:Gem::Version
677
- version: 1.30.0
677
+ version: 1.30.1
678
678
  type: :runtime
679
679
  prerelease: false
680
680
  version_requirements: !ruby/object:Gem::Requirement
681
681
  requirements:
682
682
  - - '='
683
683
  - !ruby/object:Gem::Version
684
- version: 1.30.0
684
+ version: 1.30.1
685
685
  - !ruby/object:Gem::Dependency
686
686
  name: rubocop-rake
687
687
  requirement: !ruby/object:Gem::Requirement
@@ -828,14 +828,14 @@ dependencies:
828
828
  requirements:
829
829
  - - '='
830
830
  - !ruby/object:Gem::Version
831
- version: 1.0.0
831
+ version: 1.1.0
832
832
  type: :runtime
833
833
  prerelease: false
834
834
  version_requirements: !ruby/object:Gem::Requirement
835
835
  requirements:
836
836
  - - '='
837
837
  - !ruby/object:Gem::Version
838
- version: 1.0.0
838
+ version: 1.1.0
839
839
  - !ruby/object:Gem::Dependency
840
840
  name: socksify
841
841
  requirement: !ruby/object:Gem::Requirement