pwn 0.4.465 → 0.4.468
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +3 -3
- data/README.md +2 -2
- data/bin/pwn_serial_msr206 +59 -7
- data/lib/pwn/plugins/msr206.rb +76 -45
- data/lib/pwn/version.rb +1 -1
- metadata +9 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 98c7c96215e79c7af756b24a758d15c55ee42fddc0822d90350c5476059f5573
|
|
4
|
+
data.tar.gz: 75ecc6b0534b384612dae50bb7d23143e4e11a5c3a2bddda8fc6f14ea1f8c44e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ee8208c011822cee15ef9d92a564ce3e3027c61dd2f975acb7d154e398b763a1bb820a56d6c56fe6ec63b9c0fbd6bf80528f0a05db6081d2327b831bde5f5bd1
|
|
7
|
+
data.tar.gz: 747b0b22555e4f75be1b25455bbe07e903e82184bbbd68d67a6981e41c7f8f82173003cd6986e6953b5d3cc3e6fbf70aff3aaacd5f24b33881709c90494e007e
|
data/Gemfile
CHANGED
|
@@ -13,12 +13,12 @@ gemspec
|
|
|
13
13
|
# to review these custom flags (e.g. pg, serialport, etc).
|
|
14
14
|
gem 'activesupport', '7.0.3'
|
|
15
15
|
gem 'anemone', '0.7.2'
|
|
16
|
-
gem 'authy', '3.0.
|
|
16
|
+
gem 'authy', '3.0.1'
|
|
17
17
|
gem 'aws-sdk', '3.1.0'
|
|
18
18
|
gem 'bettercap', '1.6.2'
|
|
19
19
|
gem 'brakeman', '5.2.3'
|
|
20
20
|
gem 'bson', '4.15.0'
|
|
21
|
-
gem 'bundler', '>=2.3.
|
|
21
|
+
gem 'bundler', '>=2.3.15'
|
|
22
22
|
gem 'bundler-audit', '0.9.1'
|
|
23
23
|
gem 'bunny', '2.19.0'
|
|
24
24
|
gem 'colorize', '0.8.1'
|
|
@@ -80,4 +80,4 @@ gem 'watir', '7.1.0'
|
|
|
80
80
|
gem 'waveform', '0.1.2'
|
|
81
81
|
gem 'webrick', '1.7.0'
|
|
82
82
|
gem 'wicked_pdf', '2.6.3'
|
|
83
|
-
gem 'yard', '0.9.
|
|
83
|
+
gem 'yard', '0.9.28'
|
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.
|
|
40
|
+
pwn[v0.4.468]:001 >>> PWN.help
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
[](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.
|
|
55
|
+
pwn[v0.4.468]:001 >>> PWN.help
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
|
data/bin/pwn_serial_msr206
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
require 'pwn'
|
|
5
5
|
require 'optparse'
|
|
6
|
+
require 'json'
|
|
6
7
|
|
|
7
8
|
opts = {}
|
|
8
9
|
OptionParser.new do |options|
|
|
@@ -67,6 +68,27 @@ begin
|
|
|
67
68
|
cmd: :simulate_power_cycle_warm_reset
|
|
68
69
|
)
|
|
69
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
|
|
89
|
+
)
|
|
90
|
+
puts "Configuration Bits: #{exec_resp[:binary].first}"
|
|
91
|
+
|
|
70
92
|
exec_resp = PWN::Plugins::MSR206.exec(
|
|
71
93
|
msr206_obj: msr206_obj,
|
|
72
94
|
cmd: :version_report
|
|
@@ -79,7 +101,7 @@ begin
|
|
|
79
101
|
unless menu_msg.include?('ERROR')
|
|
80
102
|
exec_resp = PWN::Plugins::MSR206.exec(
|
|
81
103
|
msr206_obj: msr206_obj,
|
|
82
|
-
cmd: :
|
|
104
|
+
cmd: :green_flash
|
|
83
105
|
)
|
|
84
106
|
end
|
|
85
107
|
|
|
@@ -99,14 +121,14 @@ begin
|
|
|
99
121
|
when :R
|
|
100
122
|
menu_msg = 'READY TO READ - PLEASE SWIPE CARD'
|
|
101
123
|
# Read Card
|
|
102
|
-
PWN::Plugins::MSR206.wait_for_swipe(
|
|
124
|
+
track_data = PWN::Plugins::MSR206.wait_for_swipe(
|
|
103
125
|
msr206_obj: msr206_obj,
|
|
104
126
|
type: :arm_to_read
|
|
105
127
|
)
|
|
106
128
|
when :C
|
|
107
129
|
menu_msg = 'READY TO COPY - PLEASE SWIPE ORIGINAL CARD'
|
|
108
130
|
# Read Original Card
|
|
109
|
-
PWN::Plugins::MSR206.wait_for_swipe(
|
|
131
|
+
track_data = PWN::Plugins::MSR206.wait_for_swipe(
|
|
110
132
|
msr206_obj: msr206_obj,
|
|
111
133
|
type: :arm_to_read
|
|
112
134
|
)
|
|
@@ -117,7 +139,7 @@ begin
|
|
|
117
139
|
when :E
|
|
118
140
|
menu_msg = 'READY TO EDIT - PLEASE SWIPE TARGET CARD'
|
|
119
141
|
# Read Target Card
|
|
120
|
-
PWN::Plugins::MSR206.wait_for_swipe(
|
|
142
|
+
track_data = PWN::Plugins::MSR206.wait_for_swipe(
|
|
121
143
|
msr206_obj: msr206_obj,
|
|
122
144
|
type: :arm_to_read
|
|
123
145
|
)
|
|
@@ -128,10 +150,40 @@ begin
|
|
|
128
150
|
when :B
|
|
129
151
|
menu_msg = 'READY TO BACKUP - PLEASE SWIPE CARD'
|
|
130
152
|
# Read Card
|
|
131
|
-
PWN::Plugins::MSR206.wait_for_swipe(
|
|
153
|
+
track_data = PWN::Plugins::MSR206.wait_for_swipe(
|
|
132
154
|
msr206_obj: msr206_obj,
|
|
133
155
|
type: :arm_to_read
|
|
134
156
|
)
|
|
157
|
+
file = ''
|
|
158
|
+
loop do
|
|
159
|
+
exec_resp = PWN::Plugins::MSR206.exec(
|
|
160
|
+
msr206_obj: msr206_obj,
|
|
161
|
+
cmd: :green_flash
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
print 'Enter File Name to Save Backup: '
|
|
165
|
+
file = gets.scrub.chomp.strip
|
|
166
|
+
file_dir = File.dirname(file)
|
|
167
|
+
break if Dir.exist?(file_dir)
|
|
168
|
+
|
|
169
|
+
puts "\nDirectory #{file_dir} for #{file} does not exist."
|
|
170
|
+
exec_resp = PWN::Plugins::MSR206.exec(
|
|
171
|
+
msr206_obj: msr206_obj,
|
|
172
|
+
cmd: :green_off
|
|
173
|
+
)
|
|
174
|
+
exec_resp = PWN::Plugins::MSR206.exec(
|
|
175
|
+
msr206_obj: msr206_obj,
|
|
176
|
+
cmd: :yellow_flash
|
|
177
|
+
)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
File.write(file, "#{track_data.to_json}\n")
|
|
181
|
+
exec_resp = PWN::Plugins::MSR206.exec(
|
|
182
|
+
msr206_obj: msr206_obj,
|
|
183
|
+
cmd: :yellow_off
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
puts 'complete.'
|
|
135
187
|
when :W
|
|
136
188
|
exec_resp = PWN::Plugins::MSR206.exec(
|
|
137
189
|
msr206_obj: msr206_obj,
|
|
@@ -144,12 +196,12 @@ begin
|
|
|
144
196
|
menu_msg = '****** ERROR: Invalid Menu Option Selected ******'
|
|
145
197
|
exec_resp = PWN::Plugins::MSR206.exec(
|
|
146
198
|
msr206_obj: msr206_obj,
|
|
147
|
-
cmd: :
|
|
199
|
+
cmd: :green_off
|
|
148
200
|
)
|
|
149
201
|
|
|
150
202
|
exec_resp = PWN::Plugins::MSR206.exec(
|
|
151
203
|
msr206_obj: msr206_obj,
|
|
152
|
-
cmd: :
|
|
204
|
+
cmd: :yellow_flash
|
|
153
205
|
)
|
|
154
206
|
end
|
|
155
207
|
end
|
data/lib/pwn/plugins/msr206.rb
CHANGED
|
@@ -308,6 +308,26 @@ module PWN
|
|
|
308
308
|
raise e
|
|
309
309
|
end
|
|
310
310
|
|
|
311
|
+
# Supported Method Parameters::
|
|
312
|
+
# parsed_cmd_resp_arr = binary(
|
|
313
|
+
# raw_byte_arr: 'required - raw_byte_arr produced in #parse_responses'
|
|
314
|
+
# )
|
|
315
|
+
|
|
316
|
+
private_class_method def self.binary(opts = {})
|
|
317
|
+
raw_byte_arr = opts[:raw_byte_arr]
|
|
318
|
+
|
|
319
|
+
binary_byte_arr = []
|
|
320
|
+
if raw_byte_arr
|
|
321
|
+
raw_byte_arr.first.split.each do |byte_str|
|
|
322
|
+
binary_byte_arr.push([byte_str].pack('H*').unpack1('B*').reverse)
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
binary_byte_arr
|
|
327
|
+
rescue StandardError => e
|
|
328
|
+
raise e
|
|
329
|
+
end
|
|
330
|
+
|
|
311
331
|
# Supported Method Parameters::
|
|
312
332
|
# parsed_cmd_resp_arr = parse_responses(
|
|
313
333
|
# cmd_resp: 'required - command response string'
|
|
@@ -342,31 +362,31 @@ module PWN
|
|
|
342
362
|
end
|
|
343
363
|
|
|
344
364
|
case cmd_resp
|
|
345
|
-
when '21'
|
|
365
|
+
when '21', 'A1'
|
|
346
366
|
response[:msg] = :invalid_command
|
|
347
|
-
when '28'
|
|
367
|
+
when '28', 'A8'
|
|
348
368
|
response[:msg] = :card_speed_measurement_start
|
|
349
|
-
when '29'
|
|
369
|
+
when '29', 'A9'
|
|
350
370
|
response[:msg] = :card_speed_measurement_end
|
|
351
|
-
when '2A'
|
|
371
|
+
when '2A', 'AA'
|
|
352
372
|
response[:msg] = :error
|
|
353
|
-
when '2B'
|
|
373
|
+
when '2B', 'AB'
|
|
354
374
|
response[:msg] = :no_data_found
|
|
355
|
-
when '2D'
|
|
375
|
+
when '2D', 'AD'
|
|
356
376
|
response[:msg] = :insufficient_leading_zeros_for_custom_writing
|
|
357
|
-
when '2F'
|
|
377
|
+
when '2F', 'AF'
|
|
358
378
|
response[:msg] = :first_lsb_char_not_one_for_custom_writing
|
|
359
|
-
when '
|
|
360
|
-
response[:msg] = :power_on_report
|
|
361
|
-
when '31'
|
|
379
|
+
when '31', 'B1'
|
|
362
380
|
response[:msg] = :unsuccessful_read_after_write_track1
|
|
363
|
-
when '32'
|
|
381
|
+
when '32', 'B2'
|
|
364
382
|
response[:msg] = :unsuccessful_read_after_write_track2
|
|
365
|
-
when '33'
|
|
383
|
+
when '33', 'B3'
|
|
366
384
|
response[:msg] = :unsuccessful_read_after_write_track3
|
|
367
|
-
when '
|
|
385
|
+
when '3A', 'BA'
|
|
386
|
+
response[:msg] = :power_on_report
|
|
387
|
+
when '3E', 'BE'
|
|
368
388
|
response[:msg] = :card_edge_detected
|
|
369
|
-
when '3F'
|
|
389
|
+
when '3F', 'BF'
|
|
370
390
|
response[:msg] = :communications_error
|
|
371
391
|
when '5E'
|
|
372
392
|
response[:msg] = :ack_command_completed
|
|
@@ -382,6 +402,7 @@ module PWN
|
|
|
382
402
|
end
|
|
383
403
|
|
|
384
404
|
response[:raw] = raw_byte_arr
|
|
405
|
+
response[:binary] = binary(raw_byte_arr: raw_byte_arr)
|
|
385
406
|
response[:decoded] = decode(raw_byte_arr: raw_byte_arr)
|
|
386
407
|
response
|
|
387
408
|
rescue StandardError => e
|
|
@@ -534,6 +555,7 @@ module PWN
|
|
|
534
555
|
# Supported Method Parameters::
|
|
535
556
|
# PWN::Plugins::MSR206.wait_for_swipe(
|
|
536
557
|
# msr206_obj: 'required - msr206_obj returned from #connect method'
|
|
558
|
+
# type: 'required - swipe type'
|
|
537
559
|
# )
|
|
538
560
|
|
|
539
561
|
public_class_method def self.wait_for_swipe(opts = {})
|
|
@@ -549,6 +571,8 @@ module PWN
|
|
|
549
571
|
|
|
550
572
|
raise "ERROR Unsupported type in #wait_for_swipe - #{type}. Valid types:\n#{types_arr}" unless types_arr.include?(type)
|
|
551
573
|
|
|
574
|
+
track_data = {}
|
|
575
|
+
|
|
552
576
|
exec_resp = exec(
|
|
553
577
|
msr206_obj: msr206_obj,
|
|
554
578
|
cmd: :red_off
|
|
@@ -584,57 +608,64 @@ module PWN
|
|
|
584
608
|
break if exec_resp[:msg] == :ack_command_completed
|
|
585
609
|
end
|
|
586
610
|
|
|
587
|
-
puts "*** ISO Track Format: Standard #{'*' * 17}"
|
|
611
|
+
puts "\n*** ISO Track Format: Standard #{'*' * 17}"
|
|
588
612
|
print 'TRACK 1 >>> '
|
|
589
613
|
exec_resp = exec(
|
|
590
614
|
msr206_obj: msr206_obj,
|
|
591
|
-
cmd: :tx_iso_std_data_track1
|
|
592
|
-
params: [0x31]
|
|
615
|
+
cmd: :tx_iso_std_data_track1
|
|
593
616
|
)
|
|
594
617
|
puts exec_resp[:decoded]
|
|
595
618
|
puts exec_resp.inspect
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
#
|
|
599
|
-
#
|
|
600
|
-
#
|
|
601
|
-
#
|
|
602
|
-
#
|
|
603
|
-
#
|
|
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
|
|
604
630
|
|
|
605
631
|
print "\nTRACK 2 >>> "
|
|
606
632
|
exec_resp = exec(
|
|
607
633
|
msr206_obj: msr206_obj,
|
|
608
|
-
cmd: :tx_iso_std_data_track2
|
|
609
|
-
params: [0x32]
|
|
634
|
+
cmd: :tx_iso_std_data_track2
|
|
610
635
|
)
|
|
611
636
|
puts exec_resp[:decoded]
|
|
612
637
|
puts exec_resp.inspect
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
#
|
|
616
|
-
#
|
|
617
|
-
#
|
|
618
|
-
#
|
|
619
|
-
#
|
|
620
|
-
#
|
|
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
|
|
621
649
|
|
|
622
650
|
print "\nTRACK 3 >>> "
|
|
623
651
|
exec_resp = exec(
|
|
624
652
|
msr206_obj: msr206_obj,
|
|
625
|
-
cmd: :tx_iso_std_data_track3
|
|
626
|
-
params: [0x33]
|
|
653
|
+
cmd: :tx_iso_std_data_track3
|
|
627
654
|
)
|
|
628
655
|
puts exec_resp[:decoded]
|
|
629
656
|
puts exec_resp.inspect
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
#
|
|
633
|
-
#
|
|
634
|
-
#
|
|
635
|
-
#
|
|
636
|
-
#
|
|
637
|
-
#
|
|
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
|
|
668
|
+
track_data
|
|
638
669
|
rescue StandardError => e
|
|
639
670
|
raise e
|
|
640
671
|
ensure
|
data/lib/pwn/version.rb
CHANGED
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.
|
|
4
|
+
version: 0.4.468
|
|
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-
|
|
11
|
+
date: 2022-06-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -44,14 +44,14 @@ dependencies:
|
|
|
44
44
|
requirements:
|
|
45
45
|
- - '='
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: 3.0.
|
|
47
|
+
version: 3.0.1
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - '='
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: 3.0.
|
|
54
|
+
version: 3.0.1
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: aws-sdk
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -114,14 +114,14 @@ dependencies:
|
|
|
114
114
|
requirements:
|
|
115
115
|
- - ">="
|
|
116
116
|
- !ruby/object:Gem::Version
|
|
117
|
-
version: 2.3.
|
|
117
|
+
version: 2.3.15
|
|
118
118
|
type: :development
|
|
119
119
|
prerelease: false
|
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
|
121
121
|
requirements:
|
|
122
122
|
- - ">="
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
|
-
version: 2.3.
|
|
124
|
+
version: 2.3.15
|
|
125
125
|
- !ruby/object:Gem::Dependency
|
|
126
126
|
name: bundler-audit
|
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -968,14 +968,14 @@ dependencies:
|
|
|
968
968
|
requirements:
|
|
969
969
|
- - '='
|
|
970
970
|
- !ruby/object:Gem::Version
|
|
971
|
-
version: 0.9.
|
|
971
|
+
version: 0.9.28
|
|
972
972
|
type: :runtime
|
|
973
973
|
prerelease: false
|
|
974
974
|
version_requirements: !ruby/object:Gem::Requirement
|
|
975
975
|
requirements:
|
|
976
976
|
- - '='
|
|
977
977
|
- !ruby/object:Gem::Version
|
|
978
|
-
version: 0.9.
|
|
978
|
+
version: 0.9.28
|
|
979
979
|
description: https://github.com/0dayinc/pwn/README.md
|
|
980
980
|
email:
|
|
981
981
|
- request.pentest@0dayinc.com
|
|
@@ -1972,7 +1972,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
1972
1972
|
- !ruby/object:Gem::Version
|
|
1973
1973
|
version: '0'
|
|
1974
1974
|
requirements: []
|
|
1975
|
-
rubygems_version: 3.3.
|
|
1975
|
+
rubygems_version: 3.3.15
|
|
1976
1976
|
signing_key:
|
|
1977
1977
|
specification_version: 4
|
|
1978
1978
|
summary: Automated Security Testing for CI/CD Pipelines & Beyond
|