pwn 0.5.75 → 0.5.76
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/README.md +3 -3
- data/bin/pwn_gqrx_scanner +11 -287
- data/lib/pwn/plugins/gqrx.rb +361 -0
- data/lib/pwn/plugins.rb +1 -0
- data/lib/pwn/version.rb +1 -1
- data/spec/lib/pwn/plugins/gqrx_spec.rb +15 -0
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6341c999a95a8ef1867905f07a60fd054d0ad217912b5b50dbafa1d42c8c1aa9
|
4
|
+
data.tar.gz: dc476c26b6f833f7c78850e8a32f9ad5b68cb36f0110ca5b739b2d5e8a690a55
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 30126968532893656b7d1db6bd1afb32a46b59831d9156fe7d1b4eaa317609b5c8e5a268e468ab4c7bc922b0731049485db14a703d24f958c600c6da564d77d3
|
7
|
+
data.tar.gz: a6a8d6b2d84a71bf9730885b1a7b1c2d746d1e6ac8c22183e089f03260cc57eeed8ed79f619093e11e087c4267dd3ca113fd9175bc9837d685c4b6795ea099e0
|
data/Gemfile
CHANGED
@@ -81,7 +81,7 @@ 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.
|
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.
|
40
|
+
pwn[v0.5.76]: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.
|
55
|
+
pwn[v0.5.76]: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.
|
65
|
+
pwn[v0.5.76]: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:
|
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]
|
362
|
-
port = opts[:port]
|
85
|
+
host = opts[:host]
|
86
|
+
port = opts[:port]
|
363
87
|
|
364
88
|
puts "Connecting to GQRX at #{host}:#{port}..."
|
365
|
-
gqrx_sock = PWN::Plugins::
|
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::
|
181
|
+
gqrx_sock = PWN::Plugins::GQRX.disconnect(gqrx_sock: gqrx_sock)
|
458
182
|
end
|
@@ -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
@@ -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.
|
4
|
+
version: 0.5.76
|
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-
|
11
|
+
date: 2024-03-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -968,14 +968,14 @@ dependencies:
|
|
968
968
|
requirements:
|
969
969
|
- - '='
|
970
970
|
- !ruby/object:Gem::Version
|
971
|
-
version: 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.
|
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
|