pwn 0.5.75 → 0.5.77

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1cba5aa01f8984c7ba1ce83fa78dc1d095b4d861396b9232ab3f76b3016006a3
4
- data.tar.gz: 7f485302aa1bf96ce268673fb81b954146de4c2ccc9689019e7f511b2f9e025e
3
+ metadata.gz: 785ee96770cdafec2335a97bebd6ead037c1e101e71034a42ac7a2b2d9e1ad3f
4
+ data.tar.gz: ec5131e73e7880531e0eb1c7c3d61ba0736c0f8f1f65756a61d9deaf59dc458a
5
5
  SHA512:
6
- metadata.gz: f7f4289fa20980acead88c2fe8d4229e4e264fd19781b9bfe36992eeff5f9fecabbc8d90d65b508d0eee73ae0277d97a54818cf2c8f9eadac6fbf4ee6719bd05
7
- data.tar.gz: 8ed257b5ecf62599422d90dea3fba4e2bf03a8bf5831e793cd91e2fc138bd5cecf820abd477b6f8689b55934e4d4629ab72c9387b62ec812ab35d881591a9bbc
6
+ metadata.gz: b35076b724a522bd1ea40981ce5d37f1454162b64ba2120217e6b19f26856d8eacb1457032179148a136c375809dd09b7fad4348169e1a8cce8381f6bfe154ae
7
+ data.tar.gz: 0db05cecffa1a616df0dfc49d7b78e13f2f25099b350f31e24b2f69d534c876490df424b8ab9b7a63de249b0103e34bac58fd8df39c58ca8b41902cb10514978
data/Gemfile CHANGED
@@ -26,7 +26,7 @@ gem 'colorize', '1.1.0'
26
26
  gem 'credit_card_validations', '6.1.0'
27
27
  gem 'eventmachine', '1.2.7'
28
28
  gem 'executable-hooks', '1.7.1'
29
- gem 'faker', '3.3.0'
29
+ gem 'faker', '3.3.1'
30
30
  gem 'faye-websocket', '0.11.3'
31
31
  gem 'ffi', '1.16.3'
32
32
  gem 'fftw3', '0.3'
@@ -63,7 +63,7 @@ gem 'pdf-reader', '2.12.0'
63
63
  gem 'pg', '1.5.6'
64
64
  gem 'pry', '0.14.2'
65
65
  gem 'pry-doc', '1.5.0'
66
- gem 'rake', '13.1.0'
66
+ gem 'rake', '13.2.0'
67
67
  gem 'rb-readline', '0.5.5'
68
68
  gem 'rbvmomi', '3.0.0'
69
69
  gem 'rdoc', '6.6.3.1'
@@ -75,13 +75,13 @@ gem 'rspec', '3.13.0'
75
75
  gem 'rtesseract', '3.1.3'
76
76
  gem 'rubocop', '1.62.1'
77
77
  gem 'rubocop-rake', '0.6.0'
78
- gem 'rubocop-rspec', '2.27.1'
78
+ gem 'rubocop-rspec', '2.28.0'
79
79
  gem 'ruby-audio', '1.6.1'
80
80
  gem 'ruby-nmap', '1.0.3'
81
81
  gem 'ruby-saml', '1.16.0'
82
82
  gem 'rvm', '1.11.3.9'
83
83
  gem 'savon', '2.15.0'
84
- gem 'selenium-devtools', '0.122.0'
84
+ gem 'selenium-devtools', '0.123.0'
85
85
  gem 'serialport', '1.3.2'
86
86
  # gem 'sinatra', '4.0.0'
87
87
  gem 'slack-ruby-client', '2.3.0'
data/README.md CHANGED
@@ -37,7 +37,7 @@ $ cd /opt/pwn
37
37
  $ ./install.sh
38
38
  $ ./install.sh ruby-gem
39
39
  $ pwn
40
- pwn[v0.5.75]:001 >>> PWN.help
40
+ pwn[v0.5.77]: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.3.0@pwn
52
52
  $ gem uninstall --all --executables pwn
53
53
  $ gem install --verbose pwn
54
54
  $ pwn
55
- pwn[v0.5.75]:001 >>> PWN.help
55
+ pwn[v0.5.77]:001 >>> PWN.help
56
56
  ```
57
57
 
58
58
  If you're using a multi-user install of RVM do:
@@ -62,7 +62,7 @@ $ rvm use ruby-3.3.0@pwn
62
62
  $ rvmsudo gem uninstall --all --executables pwn
63
63
  $ rvmsudo gem install --verbose pwn
64
64
  $ pwn
65
- pwn[v0.5.75]:001 >>> PWN.help
65
+ pwn[v0.5.77]:001 >>> PWN.help
66
66
  ```
67
67
 
68
68
  PWN periodically upgrades to the latest version of Ruby which is reflected in `/opt/pwn/.ruby-version`. The easiest way to upgrade to the latest version of Ruby from a previous PWN installation is to run the following script:
@@ -38,6 +38,10 @@ OptionParser.new do |options|
38
38
  opts[:file] = f
39
39
  end
40
40
 
41
+ options.on('-TNAME', '--test-title=NAME', '<Optional - name of test to associate w/ scan type (Defaults to --scan-type value>') do |t|
42
+ opts[:test_title] = t
43
+ end
44
+
41
45
  options.on('-lUSER', '--lead-username=USER', '<Optional - username of lead to tie to engagement (Defaults to username)>') do |l|
42
46
  opts[:lead_username] = l
43
47
  end
@@ -58,6 +62,10 @@ OptionParser.new do |options|
58
62
  opts[:verified] = v
59
63
  end
60
64
 
65
+ options.on('-G', '--group-by', '<Optional - group findings by "component_name" || "component_name+component_version" || "file_path" || "finding_title" (defaults to nil)') do |g|
66
+ opts[:group_by] = g
67
+ end
68
+
61
69
  options.on('-g', '--create-finding-groups', '<Optional - group similar findings into one finding (defaults to false)') do |g|
62
70
  opts[:create_finding_groups] = g
63
71
  end
@@ -91,10 +99,12 @@ engagement_name = opts[:engagement_name]
91
99
  scan_type = opts[:scan_type]
92
100
  file = opts[:file]
93
101
  opts[:lead_username] ? (lead_username = opts[:lead_username]) : (lead_username = username)
102
+ test_title = opts[:test_title]
94
103
  tags = opts[:tags]
95
104
  minimum_severity = opts[:minimum_severity]
96
105
  scan_date = opts[:scan_date]
97
106
  verified = opts[:verified]
107
+ group_by = opts[:group_by]
98
108
  create_findings_groups = opts[:create_finding_groups]
99
109
  close_old_findings_product_scope = opts[:close_old_findings_product_scope]
100
110
  close_old_findings = opts[:close_old_findings]
@@ -113,11 +123,13 @@ begin
113
123
  engagement_name: engagement_name,
114
124
  scan_type: scan_type,
115
125
  file: file,
126
+ test_title: test_title,
116
127
  lead_username: lead_username,
117
128
  tags: tags,
118
129
  minimum_severity: minimum_severity,
119
130
  scan_date: scan_date,
120
131
  verified: verified,
132
+ group_by: group_by,
121
133
  create_findings_groups: create_findings_groups,
122
134
  close_old_findings_product_scope: close_old_findings_product_scope,
123
135
  close_old_findings: close_old_findings,
data/bin/pwn_gqrx_scanner CHANGED
@@ -73,282 +73,6 @@ if opts.empty?
73
73
  exit 1
74
74
  end
75
75
 
76
- def gqrx_cmd(opts = {})
77
- gqrx_sock = opts[:gqrx_sock]
78
- cmd = opts[:cmd]
79
- resp_ok = opts[:resp_ok]
80
-
81
- # Most Recent GQRX Command Set:
82
- # https://raw.githubusercontent.com/gqrx-sdr/gqrx/master/resources/remote-control.txt
83
- # Supported commands:
84
- # f Get frequency [Hz]
85
- # F <frequency> Set frequency [Hz]
86
- # m Get demodulator mode and passband
87
- # M <mode> [passband]
88
- # Set demodulator mode and passband [Hz]
89
- # Passing a '?' as the first argument instead of 'mode' will return
90
- # a space separated list of radio backend supported modes.
91
- # l|L ?
92
- # Get a space separated list of settings available for reading (l) or writing (L).
93
- # l STRENGTH
94
- # Get signal strength [dBFS]
95
- # l SQL
96
- # Get squelch threshold [dBFS]
97
- # L SQL <sql>
98
- # Set squelch threshold to <sql> [dBFS]
99
- # l AF
100
- # Get audio gain [dB]
101
- # L AF <gain>
102
- # Set audio gain to <gain> [dB]
103
- # l <gain_name>_GAIN
104
- # Get the value of the gain setting with the name <gain_name>
105
- # L <gain_name>_GAIN <value>
106
- # Set the value of the gain setting with the name <gain_name> to <value>
107
- # p RDS_PI
108
- # Get the RDS PI code (in hexadecimal). Returns 0000 if not applicable.
109
- # u RECORD
110
- # Get status of audio recorder
111
- # U RECORD <status>
112
- # Set status of audio recorder to <status>
113
- # u DSP
114
- # Get DSP (SDR receiver) status
115
- # U DSP <status>
116
- # Set DSP (SDR receiver) status to <status>
117
- # u RDS
118
- # Get RDS decoder to <status>. Only functions in WFM mode.
119
- # U RDS <status>
120
- # Set RDS decoder to <status>. Only functions in WFM mode.
121
- # q|Q
122
- # Close connection
123
- # AOS
124
- # Acquisition of signal (AOS) event, start audio recording
125
- # LOS
126
- # Loss of signal (LOS) event, stop audio recording
127
- # LNB_LO [frequency]
128
- # If frequency [Hz] is specified set the LNB LO frequency used for
129
- # display. Otherwise print the current LNB LO frequency [Hz].
130
- # \chk_vfo
131
- # Get VFO option status (only usable for hamlib compatibility)
132
- # \dump_state
133
- # Dump state (only usable for hamlib compatibility)
134
- # \get_powerstat
135
- # Get power status (only usable for hamlib compatibility)
136
- # v
137
- # Get 'VFO' (only usable for hamlib compatibility)
138
- # V
139
- # Set 'VFO' (only usable for hamlib compatibility)
140
- # s
141
- # Get 'Split' mode (only usable for hamlib compatibility)
142
- # S
143
- # Set 'Split' mode (only usable for hamlib compatibility)
144
- # _
145
- # Get version
146
- #
147
- # Reply:
148
- # RPRT 0
149
- # Command successful
150
- # RPRT 1
151
- # Command failed
152
-
153
- gqrx_sock.write("#{cmd}\n")
154
- response = []
155
- got_freq = false
156
- # Read all responses from gqrx_sock.write
157
- timeout = 0.001 if timeout.nil?
158
-
159
- begin
160
- response.push(gqrx_sock.readline.chomp) while gqrx_sock.wait_readable(timeout)
161
- raise IOError if response.empty?
162
- rescue IOError
163
- timeout += 0.001
164
- retry
165
- end
166
-
167
- got_int_value_in_resp = true if response.first.to_i.positive?
168
- response = response.first if response.length == 1
169
-
170
- raise "ERROR!!! Command: #{cmd} Expected Resp: #{resp_ok}, Got: #{response}" if resp_ok && response != resp_ok
171
-
172
- if got_int_value_in_resp
173
- fixed_len_freq = format('%0.12d', response.to_i)
174
- freq_segments = fixed_len_freq.scan(/.{3}/)
175
- first_non_zero_index = freq_segments.index { |s| s.to_i.positive? }
176
- freq_segments = freq_segments[first_non_zero_index..-1]
177
- freq_segments[0] = freq_segments.first.to_i.to_s
178
- response = freq_segments.join('.')
179
- end
180
-
181
- # DEBUG
182
- # puts response.inspect
183
- # puts response.length
184
-
185
- response
186
- rescue RuntimeError => e
187
- puts 'WARNING: RF Gain is not supported by the radio backend.' if e.message.include?('Command: L RF_GAIN')
188
- puts 'WARNING: Intermediate Gain is not supported by the radio backend.' if e.message.include?('Command: L IF_GAIN')
189
- puts 'WARNING: Baseband Gain is not supported by the radio backend.' if e.message.include?('Command: L BB_GAIN')
190
-
191
- raise e unless e.message.include?('Command: L RF_GAIN') ||
192
- e.message.include?('Command: L IF_GAIN') ||
193
- e.message.include?('Command: L BB_GAIN')
194
- end
195
-
196
- def init_freq(opts = {})
197
- gqrx_sock = opts[:gqrx_sock]
198
- demodulator_mode = opts[:demodulator_mode]
199
- bandwidth = opts[:bandwidth]
200
- this_freq = opts[:this_freq]
201
- lock_freq_duration = opts[:lock_freq_duration]
202
- strength_lock = opts[:strength_lock]
203
-
204
- demod_n_passband = gqrx_cmd(
205
- gqrx_sock: gqrx_sock,
206
- cmd: 'm'
207
- )
208
-
209
- change_freq_resp = gqrx_cmd(
210
- gqrx_sock: gqrx_sock,
211
- cmd: "F #{this_freq}",
212
- resp_ok: 'RPRT 0'
213
- )
214
-
215
- current_freq = gqrx_cmd(
216
- gqrx_sock: gqrx_sock,
217
- cmd: 'f'
218
- )
219
-
220
- audio_gain_db = gqrx_cmd(
221
- gqrx_sock: gqrx_sock,
222
- cmd: 'l AF'
223
- ).to_f
224
-
225
- current_strength = gqrx_cmd(
226
- gqrx_sock: gqrx_sock,
227
- cmd: 'l STRENGTH'
228
- ).to_f
229
-
230
- current_squelch = gqrx_cmd(
231
- gqrx_sock: gqrx_sock,
232
- cmd: 'l SQL'
233
- ).to_f
234
-
235
- rf_gain = gqrx_cmd(
236
- gqrx_sock: gqrx_sock,
237
- cmd: 'l RF_GAIN'
238
- ).to_f
239
-
240
- if_gain = gqrx_cmd(
241
- gqrx_sock: gqrx_sock,
242
- cmd: 'l IF_GAIN'
243
- ).to_f
244
-
245
- bb_gain = gqrx_cmd(
246
- gqrx_sock: gqrx_sock,
247
- cmd: 'l BB_GAIN'
248
- ).to_f
249
-
250
- init_freq_hash = {
251
- demod_mode_n_passband: demod_n_passband,
252
- frequency: current_freq,
253
- bandwidth: bandwidth,
254
- audio_gain_db: audio_gain_db,
255
- squelch: current_squelch,
256
- rf_gain: rf_gain,
257
- if_gain: if_gain,
258
- bb_gain: bb_gain,
259
- strength: current_strength,
260
- strength_lock: strength_lock,
261
- lock_freq_duration: lock_freq_duration
262
- }
263
-
264
- print '.'
265
- sleep lock_freq_duration if current_strength > strength_lock
266
-
267
- init_freq_hash
268
- end
269
-
270
- def scan_range(opts = {})
271
- gqrx_sock = opts[:gqrx_sock]
272
- demodulator_mode = opts[:demodulator_mode]
273
- bandwidth = opts[:bandwidth]
274
- start_freq = opts[:start_freq]
275
- target_freq = opts[:target_freq]
276
- precision = opts[:precision]
277
- lock_freq_duration = opts[:lock_freq_duration]
278
- strength_lock = opts[:strength_lock]
279
-
280
- multiplier = 10**(precision - 1)
281
- prev_freq_hash = {
282
- demod_mode_n_passband: demodulator_mode,
283
- frequency: start_freq,
284
- bandwidth: bandwidth,
285
- audio_gain_db: 0.0,
286
- squelch: 0.0,
287
- rf_gain: 0.0,
288
- if_gain: 0.0,
289
- bb_gain: 0.0,
290
- strength: 0.0,
291
- strength_lock: strength_lock,
292
- lock_freq_duration: lock_freq_duration
293
- }
294
- if start_freq > target_freq
295
- start_freq.downto(target_freq) do |this_freq|
296
- next unless (this_freq % multiplier).zero?
297
-
298
- init_freq_hash = init_freq(
299
- gqrx_sock: gqrx_sock,
300
- demodulator_mode: demodulator_mode,
301
- bandwidth: bandwidth,
302
- this_freq: this_freq,
303
- lock_freq_duration: lock_freq_duration,
304
- strength_lock: strength_lock
305
- )
306
-
307
- current_strength = init_freq_hash[:strength]
308
- prev_strength = prev_freq_hash[:strength]
309
- prev_freq = prev_freq_hash[:frequency]
310
-
311
- approaching_detection = true if current_strength > prev_strength &&
312
- current_strength > strength_lock
313
- if approaching_detection && current_strength <= prev_strength
314
- puts "\n**** Found a signal ~ #{prev_freq} Hz ****"
315
- puts JSON.pretty_generate(prev_freq_hash)
316
- approaching_detection = false
317
- end
318
-
319
- prev_freq_hash = init_freq_hash
320
- end
321
- else
322
- this_freq = start_freq
323
- while this_freq <= target_freq
324
- init_freq_hash = init_freq(
325
- gqrx_sock: gqrx_sock,
326
- demodulator_mode: demodulator_mode,
327
- bandwidth: bandwidth,
328
- this_freq: this_freq,
329
- lock_freq_duration: lock_freq_duration,
330
- strength_lock: strength_lock
331
- )
332
-
333
- current_strength = init_freq_hash[:strength]
334
- prev_strength = prev_freq_hash[:strength]
335
- prev_freq = prev_freq_hash[:frequency]
336
-
337
- approaching_detection = true if current_strength > prev_strength &&
338
- current_strength > strength_lock
339
- if approaching_detection && current_strength < prev_strength
340
- puts "\n**** Discovered a signal ~ #{prev_freq} Hz ****"
341
- puts JSON.pretty_generate(prev_freq_hash)
342
- approaching_detection = false
343
- end
344
-
345
- prev_freq_hash = init_freq_hash
346
-
347
- this_freq += multiplier
348
- end
349
- end
350
- end
351
-
352
76
  begin
353
77
  pwn_provider = 'ruby-gem'
354
78
  pwn_provider = ENV.fetch('PWN_PROVIDER') if ENV.keys.any? { |s| s == 'PWN_PROVIDER' }
@@ -358,11 +82,11 @@ begin
358
82
  target_freq = target_freq.to_i
359
83
  raise "ERROR: Invalid target frequency #{target_freq}" if target_freq.zero?
360
84
 
361
- host = opts[:host] ||= '127.0.0.1'
362
- port = opts[:port] ||= 7356
85
+ host = opts[:host]
86
+ port = opts[:port]
363
87
 
364
88
  puts "Connecting to GQRX at #{host}:#{port}..."
365
- gqrx_sock = PWN::Plugins::Sock.connect(target: host, port: port)
89
+ gqrx_sock = PWN::Plugins::GQRX.connect(target: host, port: port)
366
90
 
367
91
  start_freq = opts[:start_freq]
368
92
  start_freq = start_freq.to_s.delete('.') unless start_freq.nil?
@@ -377,7 +101,7 @@ begin
377
101
 
378
102
  puts "Setting demodulator mode to #{demodulator_mode} and bandwidth to #{bandwidth}..."
379
103
  bandwidth = bandwidth.to_s.delete('.').to_i unless bandwidth.nil?
380
- demod_resp = gqrx_cmd(
104
+ demod_resp = PWN::Plugins::GQRX.gqrx_cmd(
381
105
  gqrx_sock: gqrx_sock,
382
106
  cmd: "M #{demodulator_mode} #{bandwidth}",
383
107
  resp_ok: 'RPRT 0'
@@ -385,7 +109,7 @@ begin
385
109
 
386
110
  audio_gain_db = opts[:audio_gain_db] ||= 1.0
387
111
  audio_gain_db = audio_gain_db.to_f
388
- audio_gain_db_resp = gqrx_cmd(
112
+ audio_gain_db_resp = PWN::Plugins::GQRX.gqrx_cmd(
389
113
  gqrx_sock: gqrx_sock,
390
114
  cmd: "L AF #{audio_gain_db}",
391
115
  resp_ok: 'RPRT 0'
@@ -393,7 +117,7 @@ begin
393
117
 
394
118
  squelch = opts[:squelch] ||= -63.0
395
119
  squelch = squelch.to_f
396
- squelch_resp = gqrx_cmd(
120
+ squelch_resp = PWN::Plugins::GQRX.gqrx_cmd(
397
121
  gqrx_sock: gqrx_sock,
398
122
  cmd: "L SQL #{squelch}",
399
123
  resp_ok: 'RPRT 0'
@@ -411,7 +135,7 @@ begin
411
135
 
412
136
  rf_gain = opts[:rf_gain] ||= 0.0
413
137
  rf_gain = rf_gain.to_f
414
- rf_gain_resp = gqrx_cmd(
138
+ rf_gain_resp = PWN::Plugins::GQRX.gqrx_cmd(
415
139
  gqrx_sock: gqrx_sock,
416
140
  cmd: "L RF_GAIN #{rf_gain}",
417
141
  resp_ok: 'RPRT 0'
@@ -419,7 +143,7 @@ begin
419
143
 
420
144
  intermediate_gain = opts[:intermediate_gain] ||= 32.0
421
145
  intermediate_gain = intermediate_gain.to_f
422
- intermediate_resp = gqrx_cmd(
146
+ intermediate_resp = PWN::Plugins::GQRX.gqrx_cmd(
423
147
  gqrx_sock: gqrx_sock,
424
148
  cmd: "L IF_GAIN #{intermediate_gain}",
425
149
  resp_ok: 'RPRT 0'
@@ -427,7 +151,7 @@ begin
427
151
 
428
152
  baseband_gain = opts[:baseband_gain] ||= 10.0
429
153
  baseband_gain = baseband_gain.to_f
430
- baseband_resp = gqrx_cmd(
154
+ baseband_resp = PWN::Plugins::GQRX.gqrx_cmd(
431
155
  gqrx_sock: gqrx_sock,
432
156
  cmd: "L BB_GAIN #{baseband_gain}",
433
157
  resp_ok: 'RPRT 0'
@@ -437,7 +161,7 @@ begin
437
161
  t_freq_pretty = target_freq.to_s.chars.insert(-4, '.').insert(-8, '.').join
438
162
  puts "*** Scanning from #{s_freq_pretty} to #{t_freq_pretty}\n\n\n"
439
163
 
440
- scan_range(
164
+ PWN::Plugins::GQRX.scan_range(
441
165
  gqrx_sock: gqrx_sock,
442
166
  demodulator_mode: demodulator_mode,
443
167
  bandwidth: bandwidth,
@@ -454,5 +178,5 @@ rescue StandardError => e
454
178
  rescue Interrupt, SystemExit
455
179
  puts "\nGoodbye."
456
180
  ensure
457
- gqrx_sock = PWN::Plugins::Sock.disconnect(sock_obj: gqrx_sock)
181
+ gqrx_sock = PWN::Plugins::GQRX.disconnect(gqrx_sock: gqrx_sock)
458
182
  end
@@ -432,6 +432,8 @@ module PWN
432
432
  http_body[:multipart] = true
433
433
  http_body[:file] = File.new(opts[:file].to_s.strip.chomp.scrub, 'rb') if File.exist?(opts[:file].to_s.strip.chomp.scrub)
434
434
 
435
+ http_body[:test_title] = opts[:test_title]
436
+
435
437
  # Ok lets determine the resource_uri for the lead username
436
438
  lead_username = opts[:lead_username].to_s.strip.chomp.scrub
437
439
  user_list = self.user_list(dd_obj: dd_obj)
@@ -469,6 +471,19 @@ module PWN
469
471
  # Defaults to false
470
472
  opts[:verified] ? (http_body[:verified] = true) : (http_body[:verified] = false)
471
473
 
474
+ valid_group_by = %w[
475
+ component_name
476
+ component_name+compoent_version
477
+ file_path
478
+ finding_title
479
+ ]
480
+
481
+ group_by = opts[:group_by]
482
+ # If group_by is set, ensure we have a valid group_by value
483
+ raise "ERROR: Invalid group_by value: #{group_by}. Options are 'product' or 'engagement'" unless valid_group_by.include?(group_by) || group_by.nil?
484
+
485
+ http_body[:group_by] = group_by if group_by
486
+
472
487
  opts[:create_finding_groups] ? (http_body[:create_finding_groups_for_all_findings] = true) : (http_body[:create_finding_groups_for_all_findings] = false)
473
488
 
474
489
  opts[:close_old_findings_product_scope] ? (http_body[:close_old_findings_product_scope] = true) : (http_body[:close_old_findings_product_scope] = false)
@@ -0,0 +1,361 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ module PWN
6
+ module Plugins
7
+ # This plugin interacts with the remote control interface of GQRX.
8
+ module GQRX
9
+ # Supported Method Parameters::
10
+ # gqrx_sock = PWN::Plugins::GQRX.connect(
11
+ # target: 'optional - GQRX target IP address (defaults to 127.0.0.1)',
12
+ # port: 'optional - GQRX target port (defaults to 7356)'
13
+ # )
14
+ public_class_method def self.connect(opts = {})
15
+ target = opts[:target] ||= '127.0.0.1'
16
+ port = opts[:port] ||= 7356
17
+
18
+ PWN::Plugins::Sock.connect(target: target, port: port)
19
+ rescue StandardError => e
20
+ raise e
21
+ end
22
+
23
+ # Supported Method Parameters::
24
+ # gqrx_resp = PWN::Plugins::GQRX.gqrx_cmd(
25
+ # gqrx_sock: 'required - GQRX socket object returned from #connect method',
26
+ # cmd: 'required - GQRX command to execute'
27
+ # resp_ok: 'optional - Expected response from GQRX to indicate success'
28
+ # )
29
+
30
+ public_class_method def self.gqrx_cmd(opts = {})
31
+ gqrx_sock = opts[:gqrx_sock]
32
+ cmd = opts[:cmd]
33
+ resp_ok = opts[:resp_ok]
34
+
35
+ # Most Recent GQRX Command Set:
36
+ # https://raw.githubusercontent.com/gqrx-sdr/gqrx/master/resources/remote-control.txt
37
+ # Supported commands:
38
+ # f Get frequency [Hz]
39
+ # F <frequency> Set frequency [Hz]
40
+ # m Get demodulator mode and passband
41
+ # M <mode> [passband]
42
+ # Set demodulator mode and passband [Hz]
43
+ # Passing a '?' as the first argument instead of 'mode' will return
44
+ # a space separated list of radio backend supported modes.
45
+ # l|L ?
46
+ # Get a space separated list of settings available for reading (l) or writing (L).
47
+ # l STRENGTH
48
+ # Get signal strength [dBFS]
49
+ # l SQL
50
+ # Get squelch threshold [dBFS]
51
+ # L SQL <sql>
52
+ # Set squelch threshold to <sql> [dBFS]
53
+ # l AF
54
+ # Get audio gain [dB]
55
+ # L AF <gain>
56
+ # Set audio gain to <gain> [dB]
57
+ # l <gain_name>_GAIN
58
+ # Get the value of the gain setting with the name <gain_name>
59
+ # L <gain_name>_GAIN <value>
60
+ # Set the value of the gain setting with the name <gain_name> to <value>
61
+ # p RDS_PI
62
+ # Get the RDS PI code (in hexadecimal). Returns 0000 if not applicable.
63
+ # u RECORD
64
+ # Get status of audio recorder
65
+ # U RECORD <status>
66
+ # Set status of audio recorder to <status>
67
+ # u DSP
68
+ # Get DSP (SDR receiver) status
69
+ # U DSP <status>
70
+ # Set DSP (SDR receiver) status to <status>
71
+ # u RDS
72
+ # Get RDS decoder to <status>. Only functions in WFM mode.
73
+ # U RDS <status>
74
+ # Set RDS decoder to <status>. Only functions in WFM mode.
75
+ # q|Q
76
+ # Close connection
77
+ # AOS
78
+ # Acquisition of signal (AOS) event, start audio recording
79
+ # LOS
80
+ # Loss of signal (LOS) event, stop audio recording
81
+ # LNB_LO [frequency]
82
+ # If frequency [Hz] is specified set the LNB LO frequency used for
83
+ # display. Otherwise print the current LNB LO frequency [Hz].
84
+ # \chk_vfo
85
+ # Get VFO option status (only usable for hamlib compatibility)
86
+ # \dump_state
87
+ # Dump state (only usable for hamlib compatibility)
88
+ # \get_powerstat
89
+ # Get power status (only usable for hamlib compatibility)
90
+ # v
91
+ # Get 'VFO' (only usable for hamlib compatibility)
92
+ # V
93
+ # Set 'VFO' (only usable for hamlib compatibility)
94
+ # s
95
+ # Get 'Split' mode (only usable for hamlib compatibility)
96
+ # S
97
+ # Set 'Split' mode (only usable for hamlib compatibility)
98
+ # _
99
+ # Get version
100
+ #
101
+ # Reply:
102
+ # RPRT 0
103
+ # Command successful
104
+ # RPRT 1
105
+ # Command failed
106
+
107
+ gqrx_sock.write("#{cmd}\n")
108
+ response = []
109
+ got_freq = false
110
+ # Read all responses from gqrx_sock.write
111
+ timeout = 0.001 if timeout.nil?
112
+
113
+ begin
114
+ response.push(gqrx_sock.readline.chomp) while gqrx_sock.wait_readable(timeout)
115
+ raise IOError if response.empty?
116
+ rescue IOError
117
+ timeout += 0.001
118
+ retry
119
+ end
120
+
121
+ got_int_value_in_resp = true if response.first.to_i.positive?
122
+ response = response.first if response.length == 1
123
+
124
+ raise "ERROR!!! Command: #{cmd} Expected Resp: #{resp_ok}, Got: #{response}" if resp_ok && response != resp_ok
125
+
126
+ if got_int_value_in_resp
127
+ fixed_len_freq = format('%0.12d', response.to_i)
128
+ freq_segments = fixed_len_freq.scan(/.{3}/)
129
+ first_non_zero_index = freq_segments.index { |s| s.to_i.positive? }
130
+ freq_segments = freq_segments[first_non_zero_index..-1]
131
+ freq_segments[0] = freq_segments.first.to_i.to_s
132
+ response = freq_segments.join('.')
133
+ end
134
+
135
+ # DEBUG
136
+ # puts response.inspect
137
+ # puts response.length
138
+
139
+ response
140
+ rescue RuntimeError => e
141
+ puts 'WARNING: RF Gain is not supported by the radio backend.' if e.message.include?('Command: L RF_GAIN')
142
+ puts 'WARNING: Intermediate Gain is not supported by the radio backend.' if e.message.include?('Command: L IF_GAIN')
143
+ puts 'WARNING: Baseband Gain is not supported by the radio backend.' if e.message.include?('Command: L BB_GAIN')
144
+
145
+ raise e unless e.message.include?('Command: L RF_GAIN') ||
146
+ e.message.include?('Command: L IF_GAIN') ||
147
+ e.message.include?('Command: L BB_GAIN')
148
+ rescue StandardError => e
149
+ raise e
150
+ end
151
+
152
+ # Supported Method Parameters::
153
+ # PWN::Plugins::GQRX.init_freq(
154
+ # gqrx_sock: 'required - GQRX socket object returned from #connect method',
155
+ # freq: 'required - Frequency to set',
156
+ # demodulator_mode: 'optional - Demodulator mode (defaults to WFM)',
157
+ # bandwidth: 'optional - Bandwidth (defaults to 200000)',
158
+ # lock_freq_duration: 'optional - Lock frequency duration (defaults to 0.5)',
159
+ # strength_lock: 'optional - Strength lock (defaults to -60.0)'
160
+ # )
161
+ public_class_method def self.init_freq(opts = {})
162
+ gqrx_sock = opts[:gqrx_sock]
163
+ freq = opts[:freq]
164
+ demodulator_mode = opts[:demodulator_mode]
165
+ bandwidth = opts[:bandwidth]
166
+ lock_freq_duration = opts[:lock_freq_duration]
167
+ strength_lock = opts[:strength_lock]
168
+
169
+ demod_n_passband = gqrx_cmd(
170
+ gqrx_sock: gqrx_sock,
171
+ cmd: 'm'
172
+ )
173
+
174
+ change_freq_resp = gqrx_cmd(
175
+ gqrx_sock: gqrx_sock,
176
+ cmd: "F #{freq}",
177
+ resp_ok: 'RPRT 0'
178
+ )
179
+
180
+ current_freq = gqrx_cmd(
181
+ gqrx_sock: gqrx_sock,
182
+ cmd: 'f'
183
+ )
184
+
185
+ audio_gain_db = gqrx_cmd(
186
+ gqrx_sock: gqrx_sock,
187
+ cmd: 'l AF'
188
+ ).to_f
189
+
190
+ current_strength = gqrx_cmd(
191
+ gqrx_sock: gqrx_sock,
192
+ cmd: 'l STRENGTH'
193
+ ).to_f
194
+
195
+ current_squelch = gqrx_cmd(
196
+ gqrx_sock: gqrx_sock,
197
+ cmd: 'l SQL'
198
+ ).to_f
199
+
200
+ rf_gain = gqrx_cmd(
201
+ gqrx_sock: gqrx_sock,
202
+ cmd: 'l RF_GAIN'
203
+ ).to_f
204
+
205
+ if_gain = gqrx_cmd(
206
+ gqrx_sock: gqrx_sock,
207
+ cmd: 'l IF_GAIN'
208
+ ).to_f
209
+
210
+ bb_gain = gqrx_cmd(
211
+ gqrx_sock: gqrx_sock,
212
+ cmd: 'l BB_GAIN'
213
+ ).to_f
214
+
215
+ init_freq_hash = {
216
+ demod_mode_n_passband: demod_n_passband,
217
+ frequency: current_freq,
218
+ bandwidth: bandwidth,
219
+ audio_gain_db: audio_gain_db,
220
+ squelch: current_squelch,
221
+ rf_gain: rf_gain,
222
+ if_gain: if_gain,
223
+ bb_gain: bb_gain,
224
+ strength: current_strength,
225
+ strength_lock: strength_lock,
226
+ lock_freq_duration: lock_freq_duration
227
+ }
228
+
229
+ print '.'
230
+ sleep lock_freq_duration if current_strength > strength_lock
231
+
232
+ init_freq_hash
233
+ rescue StandardError => e
234
+ raise e
235
+ end
236
+
237
+ # Supported Method Parameters::
238
+ # PWN::Plugins::GQRX.scan_range(
239
+ # gqrx_sock: 'required - GQRX socket object returned from #connect method',
240
+ # demodulator_mode: 'required - Demodulator mode',
241
+ # bandwidth: 'required - Bandwidth',
242
+ # start_freq: 'required - Starting frequency',
243
+ # target_freq: 'required - Target frequency',
244
+ # precision: 'required - Precision',
245
+ # lock_freq_duration: 'optional - Lock frequency duration (defaults to 0.5)',
246
+ # strength_lock: 'optional - Strength lock (defaults to -60.0)'
247
+ # )
248
+
249
+ public_class_method def self.scan_range(opts = {})
250
+ gqrx_sock = opts[:gqrx_sock]
251
+ demodulator_mode = opts[:demodulator_mode]
252
+ bandwidth = opts[:bandwidth]
253
+ start_freq = opts[:start_freq]
254
+ target_freq = opts[:target_freq]
255
+ precision = opts[:precision]
256
+ lock_freq_duration = opts[:lock_freq_duration]
257
+ strength_lock = opts[:strength_lock]
258
+
259
+ multiplier = 10**(precision - 1)
260
+ prev_freq_hash = {
261
+ demod_mode_n_passband: demodulator_mode,
262
+ frequency: start_freq,
263
+ bandwidth: bandwidth,
264
+ audio_gain_db: 0.0,
265
+ squelch: 0.0,
266
+ rf_gain: 0.0,
267
+ if_gain: 0.0,
268
+ bb_gain: 0.0,
269
+ strength: 0.0,
270
+ strength_lock: strength_lock,
271
+ lock_freq_duration: lock_freq_duration
272
+ }
273
+ if start_freq > target_freq
274
+ start_freq.downto(target_freq) do |freq|
275
+ next unless (freq % multiplier).zero?
276
+
277
+ init_freq_hash = init_freq(
278
+ gqrx_sock: gqrx_sock,
279
+ freq: freq,
280
+ demodulator_mode: demodulator_mode,
281
+ bandwidth: bandwidth,
282
+ lock_freq_duration: lock_freq_duration,
283
+ strength_lock: strength_lock
284
+ )
285
+
286
+ current_strength = init_freq_hash[:strength]
287
+ prev_strength = prev_freq_hash[:strength]
288
+ prev_freq = prev_freq_hash[:frequency]
289
+
290
+ approaching_detection = true if current_strength > prev_strength &&
291
+ current_strength > strength_lock
292
+ if approaching_detection && current_strength <= prev_strength
293
+ puts "\n**** Found a signal ~ #{prev_freq} Hz ****"
294
+ puts JSON.pretty_generate(prev_freq_hash)
295
+ approaching_detection = false
296
+ end
297
+
298
+ prev_freq_hash = init_freq_hash
299
+ end
300
+ else
301
+ freq = start_freq
302
+ while freq <= target_freq
303
+ init_freq_hash = init_freq(
304
+ gqrx_sock: gqrx_sock,
305
+ demodulator_mode: demodulator_mode,
306
+ bandwidth: bandwidth,
307
+ freq: freq,
308
+ lock_freq_duration: lock_freq_duration,
309
+ strength_lock: strength_lock
310
+ )
311
+
312
+ current_strength = init_freq_hash[:strength]
313
+ prev_strength = prev_freq_hash[:strength]
314
+ prev_freq = prev_freq_hash[:frequency]
315
+
316
+ approaching_detection = true if current_strength > prev_strength &&
317
+ current_strength > strength_lock
318
+ if approaching_detection && current_strength < prev_strength
319
+ puts "\n**** Discovered a signal ~ #{prev_freq} Hz ****"
320
+ puts JSON.pretty_generate(prev_freq_hash)
321
+ approaching_detection = false
322
+ end
323
+
324
+ prev_freq_hash = init_freq_hash
325
+
326
+ freq += multiplier
327
+ end
328
+ end
329
+ end
330
+
331
+ # Supported Method Parameters::
332
+ # PWN::Plugins::GQRX.disconnect(
333
+ # gqrx_sock: 'required - GQRX socket object returned from #connect method'
334
+ # )
335
+ public_class_method def self.disconnect(opts = {})
336
+ gqrx_sock = opts[:gqrx_sock]
337
+
338
+ PWN::Plugins::Sock.disconnect(sock_obj: gqrx_sock)
339
+ rescue StandardError => e
340
+ raise e
341
+ end
342
+
343
+ # Author(s):: 0day Inc. <request.pentest@0dayinc.com>
344
+
345
+ public_class_method def self.authors
346
+ "AUTHOR(S):
347
+ 0day Inc. <request.pentest@0dayinc.com>
348
+ "
349
+ end
350
+
351
+ # Display Usage for this Module
352
+
353
+ public_class_method def self.help
354
+ puts "USAGE:
355
+
356
+ #{self}.authors
357
+ "
358
+ end
359
+ end
360
+ end
361
+ end
data/lib/pwn/plugins.rb CHANGED
@@ -28,6 +28,7 @@ module PWN
28
28
  autoload :Fuzz, 'pwn/plugins/fuzz'
29
29
  autoload :Git, 'pwn/plugins/git'
30
30
  autoload :Github, 'pwn/plugins/github'
31
+ autoload :GQRX, 'pwn/plugins/gqrx'
31
32
  autoload :HackerOne, 'pwn/plugins/hacker_one'
32
33
  autoload :IBMAppscan, 'pwn/plugins/ibm_appscan'
33
34
  autoload :IPInfo, 'pwn/plugins/ip_info'
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.5.75'
4
+ VERSION = '0.5.77'
5
5
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe PWN::Plugins::GQRX do
6
+ it 'should display information for authors' do
7
+ authors_response = PWN::Plugins::GQRX
8
+ expect(authors_response).to respond_to :authors
9
+ end
10
+
11
+ it 'should display information for existing help method' do
12
+ help_response = PWN::Plugins::GQRX
13
+ expect(help_response).to respond_to :help
14
+ end
15
+ 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.5.75
4
+ version: 0.5.77
5
5
  platform: ruby
6
6
  authors:
7
7
  - 0day Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-26 00:00:00.000000000 Z
11
+ date: 2024-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -212,14 +212,14 @@ dependencies:
212
212
  requirements:
213
213
  - - '='
214
214
  - !ruby/object:Gem::Version
215
- version: 3.3.0
215
+ version: 3.3.1
216
216
  type: :runtime
217
217
  prerelease: false
218
218
  version_requirements: !ruby/object:Gem::Requirement
219
219
  requirements:
220
220
  - - '='
221
221
  - !ruby/object:Gem::Version
222
- version: 3.3.0
222
+ version: 3.3.1
223
223
  - !ruby/object:Gem::Dependency
224
224
  name: faye-websocket
225
225
  requirement: !ruby/object:Gem::Requirement
@@ -716,14 +716,14 @@ dependencies:
716
716
  requirements:
717
717
  - - '='
718
718
  - !ruby/object:Gem::Version
719
- version: 13.1.0
719
+ version: 13.2.0
720
720
  type: :development
721
721
  prerelease: false
722
722
  version_requirements: !ruby/object:Gem::Requirement
723
723
  requirements:
724
724
  - - '='
725
725
  - !ruby/object:Gem::Version
726
- version: 13.1.0
726
+ version: 13.2.0
727
727
  - !ruby/object:Gem::Dependency
728
728
  name: rb-readline
729
729
  requirement: !ruby/object:Gem::Requirement
@@ -884,14 +884,14 @@ dependencies:
884
884
  requirements:
885
885
  - - '='
886
886
  - !ruby/object:Gem::Version
887
- version: 2.27.1
887
+ version: 2.28.0
888
888
  type: :runtime
889
889
  prerelease: false
890
890
  version_requirements: !ruby/object:Gem::Requirement
891
891
  requirements:
892
892
  - - '='
893
893
  - !ruby/object:Gem::Version
894
- version: 2.27.1
894
+ version: 2.28.0
895
895
  - !ruby/object:Gem::Dependency
896
896
  name: ruby-audio
897
897
  requirement: !ruby/object:Gem::Requirement
@@ -968,14 +968,14 @@ dependencies:
968
968
  requirements:
969
969
  - - '='
970
970
  - !ruby/object:Gem::Version
971
- version: 0.122.0
971
+ version: 0.123.0
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.122.0
978
+ version: 0.123.0
979
979
  - !ruby/object:Gem::Dependency
980
980
  name: serialport
981
981
  requirement: !ruby/object:Gem::Requirement
@@ -1758,6 +1758,7 @@ files:
1758
1758
  - lib/pwn/plugins/fuzz.rb
1759
1759
  - lib/pwn/plugins/git.rb
1760
1760
  - lib/pwn/plugins/github.rb
1761
+ - lib/pwn/plugins/gqrx.rb
1761
1762
  - lib/pwn/plugins/hacker_one.rb
1762
1763
  - lib/pwn/plugins/ibm_appscan.rb
1763
1764
  - lib/pwn/plugins/ip_info.rb
@@ -2087,6 +2088,7 @@ files:
2087
2088
  - spec/lib/pwn/plugins/fuzz_spec.rb
2088
2089
  - spec/lib/pwn/plugins/git_spec.rb
2089
2090
  - spec/lib/pwn/plugins/github_spec.rb
2091
+ - spec/lib/pwn/plugins/gqrx_spec.rb
2090
2092
  - spec/lib/pwn/plugins/hacker_one_spec.rb
2091
2093
  - spec/lib/pwn/plugins/ibm_appscan_spec.rb
2092
2094
  - spec/lib/pwn/plugins/ip_info_spec.rb