pwn 0.5.620 → 0.5.621
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/README.md +1 -1
- data/documentation/Agent-Tool-Registry.md +2 -2
- data/documentation/Cron.md +13 -0
- data/documentation/Diagrams.md +1 -1
- data/documentation/Extrospection.md +71 -5
- data/documentation/Home.md +2 -2
- data/documentation/How-PWN-Works.md +1 -1
- data/documentation/Mistakes.md +2 -1
- data/documentation/Persistence.md +2 -1
- data/documentation/Skills-Memory-Learning.md +1 -0
- data/documentation/Transparent-Browser.md +18 -1
- data/documentation/diagrams/agent-tool-registry.svg +55 -54
- data/documentation/diagrams/ai-integration-tool-calling.svg +24 -24
- data/documentation/diagrams/aws-cloud-security.svg +25 -25
- data/documentation/diagrams/burp-vs-zap-preference.svg +12 -12
- data/documentation/diagrams/code-scanning-sast.svg +25 -25
- data/documentation/diagrams/cron-scheduling.svg +23 -23
- data/documentation/diagrams/dot/agent-tool-registry.dot +2 -2
- data/documentation/diagrams/dot/extrospection-world-awareness.dot +29 -8
- data/documentation/diagrams/dot/memory-skills-detailed.dot +4 -0
- data/documentation/diagrams/dot/overall-pwn-architecture.dot +2 -2
- data/documentation/diagrams/dot/persistence-filesystem.dot +2 -1
- data/documentation/diagrams/dot/pwn-ai-feedback-learning-loop.dot +10 -4
- data/documentation/diagrams/driver-framework.svg +13 -13
- data/documentation/diagrams/extrospection-world-awareness.svg +229 -99
- data/documentation/diagrams/fuzzing-workflow.svg +24 -24
- data/documentation/diagrams/hardware-hacking.svg +18 -18
- data/documentation/diagrams/history-to-drivers.svg +18 -18
- data/documentation/diagrams/memory-skills-detailed.svg +124 -101
- data/documentation/diagrams/mistakes-negative-feedback.svg +55 -55
- data/documentation/diagrams/network-infra-testing.svg +27 -27
- data/documentation/diagrams/overall-pwn-architecture.svg +85 -85
- data/documentation/diagrams/penetration-testing-workflow.svg +30 -30
- data/documentation/diagrams/persistence-filesystem.svg +94 -85
- data/documentation/diagrams/plugin-ecosystem.svg +35 -35
- data/documentation/diagrams/pwn-ai-feedback-learning-loop.svg +226 -180
- data/documentation/diagrams/pwn-repl-prototyping.svg +20 -20
- data/documentation/diagrams/reporting-pipeline.svg +18 -18
- data/documentation/diagrams/reverse-engineering-flow.svg +21 -21
- data/documentation/diagrams/sdr-radio-flow.svg +31 -31
- data/documentation/diagrams/sessions-cron-automation.svg +18 -18
- data/documentation/diagrams/swarm-multi-agent.svg +39 -39
- data/documentation/diagrams/web-application-testing.svg +26 -26
- data/documentation/diagrams/zero-day-research-flow.svg +25 -25
- data/documentation/pwn-ai-Agent.md +1 -1
- data/lib/pwn/ai/agent/extrospection.rb +433 -4
- data/lib/pwn/ai/agent/tools/extrospection.rb +88 -3
- data/lib/pwn/sdr/decoder/adsb.rb +14 -33
- data/lib/pwn/sdr/decoder/apt.rb +97 -36
- data/lib/pwn/sdr/decoder/base.rb +258 -171
- data/lib/pwn/sdr/decoder/bluetooth.rb +13 -20
- data/lib/pwn/sdr/decoder/dect.rb +13 -27
- data/lib/pwn/sdr/decoder/dsp.rb +396 -0
- data/lib/pwn/sdr/decoder/flex.rb +177 -210
- data/lib/pwn/sdr/decoder/gps.rb +12 -21
- data/lib/pwn/sdr/decoder/gsm.rb +21 -73
- data/lib/pwn/sdr/decoder/iridium.rb +11 -26
- data/lib/pwn/sdr/decoder/lora.rb +16 -23
- data/lib/pwn/sdr/decoder/lte.rb +11 -32
- data/lib/pwn/sdr/decoder/morse.rb +95 -21
- data/lib/pwn/sdr/decoder/p25.rb +19 -16
- data/lib/pwn/sdr/decoder/pager.rb +22 -38
- data/lib/pwn/sdr/decoder/pocsag.rb +175 -68
- data/lib/pwn/sdr/decoder/rfid.rb +24 -33
- data/lib/pwn/sdr/decoder/rtl433.rb +21 -30
- data/lib/pwn/sdr/decoder/rtty.rb +100 -27
- data/lib/pwn/sdr/decoder/wifi.rb +21 -42
- data/lib/pwn/sdr/decoder/zigbee.rb +18 -40
- data/lib/pwn/sdr/decoder.rb +8 -0
- data/lib/pwn/version.rb +1 -1
- data/spec/lib/pwn/sdr/decoder/dsp_spec.rb +15 -0
- data/third_party/pwn_rdoc.jsonl +24 -3
- metadata +3 -1
data/lib/pwn/sdr/decoder/adsb.rb
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'shellwords'
|
|
4
|
-
|
|
5
3
|
module PWN
|
|
6
4
|
module SDR
|
|
7
5
|
module Decoder
|
|
8
|
-
# ADS-B (
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
6
|
+
# Pure-Ruby ADS-B (1090 MHz Mode-S / 978 MHz UAT) activity detector.
|
|
7
|
+
#
|
|
8
|
+
# Mode-S Extended Squitter is 2 Mbit/s PPM with 8/120 μs frames on a
|
|
9
|
+
# 2 MHz-wide channel — physically unrecoverable from GQRX's 48 kHz
|
|
10
|
+
# demodulated-audio tap. Rather than shell out to `dump1090`, this
|
|
11
|
+
# module runs Base.run_detector to characterise squitter density
|
|
12
|
+
# (bursts/sec, peak dBFS, floor) natively in Ruby. `parse_line` is
|
|
13
|
+
# retained for offline SBS-1 CSV analysis.
|
|
13
14
|
module ADSB
|
|
14
15
|
SBS_FIELDS = %i[
|
|
15
16
|
msg_type tx_type session_id aircraft_id icao24 flight_id
|
|
@@ -25,28 +26,13 @@ module PWN
|
|
|
25
26
|
|
|
26
27
|
public_class_method def self.decode(opts = {})
|
|
27
28
|
freq_obj = opts[:freq_obj]
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
gain = (freq_obj[:rf_gain] || 40).to_s.to_f
|
|
32
|
-
uat = hz.between?(977_000_000, 979_000_000)
|
|
33
|
-
|
|
34
|
-
direct_cmd =
|
|
35
|
-
if uat && PWN::SDR::Decoder::Base.bin_available?(bin: 'dump978-fa')
|
|
36
|
-
"bash -c #{Shellwords.escape("dump978-fa --sdr driver=rtlsdr --sdr-gain #{gain} --raw-stdout 2>/dev/null | uat2text")}"
|
|
37
|
-
elsif PWN::SDR::Decoder::Base.bin_available?(bin: 'dump1090-fa')
|
|
38
|
-
"dump1090-fa --device-type rtlsdr --gain #{gain} --net-sbs-stdout --quiet"
|
|
39
|
-
else
|
|
40
|
-
"dump1090 --gain #{gain} --net-sbs-stdout --quiet"
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
PWN::SDR::Decoder::Base.run_pipeline(
|
|
29
|
+
hz = PWN::SDR.hz_to_i(freq: freq_obj[:freq])
|
|
30
|
+
uat = hz.between?(977_000_000, 979_000_000)
|
|
31
|
+
PWN::SDR::Decoder::Base.run_detector(
|
|
44
32
|
freq_obj: freq_obj,
|
|
45
33
|
protocol: uat ? 'ADSB-UAT978' : 'ADSB-1090ES',
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
line_match: /^(MSG,|-|\+)/,
|
|
49
|
-
parser: proc { |line| parse_line(line: line) }
|
|
34
|
+
note: '2 Mbit/s PPM squitters exceed the 48 kHz audio-tap Nyquist limit; native mode reports squitter-burst density only. Feed captured SBS-1 CSV to .parse_line for full field decode.',
|
|
35
|
+
describe: proc { |b| { modulation: 'PPM', frame_len_us: 120, classification: b[:duration_ms] < 5 ? 'squitter' : 'interrogation-train' } }
|
|
50
36
|
)
|
|
51
37
|
end
|
|
52
38
|
|
|
@@ -60,7 +46,6 @@ module PWN
|
|
|
60
46
|
f = line.split(',', -1)
|
|
61
47
|
out = { protocol: 'ADSB' }
|
|
62
48
|
SBS_FIELDS.each_with_index { |k, i| out[k] = f[i] unless f[i].to_s.empty? }
|
|
63
|
-
|
|
64
49
|
bits = []
|
|
65
50
|
bits << "ICAO=#{out[:icao24]}" if out[:icao24]
|
|
66
51
|
bits << "CS=#{out[:callsign].to_s.strip}" if out[:callsign]
|
|
@@ -81,15 +66,11 @@ module PWN
|
|
|
81
66
|
# Display Usage for this Module
|
|
82
67
|
|
|
83
68
|
public_class_method def self.help
|
|
84
|
-
puts "USAGE:
|
|
69
|
+
puts "USAGE (ruby-native detector, no external binaries):
|
|
85
70
|
#{self}.decode(
|
|
86
71
|
freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq'
|
|
87
72
|
)
|
|
88
73
|
|
|
89
|
-
NOTE: Requires `dump1090` (1090 MHz Mode-S/ES) or
|
|
90
|
-
`dump978-fa` + `uat2text` (978 MHz UAT). Owns the SDR
|
|
91
|
-
directly — set freq_obj[:sdr_args] if GQRX has device 0.
|
|
92
|
-
|
|
93
74
|
#{self}.parse_line(line: 'MSG,3,1,1,ABCDEF,1,...')
|
|
94
75
|
|
|
95
76
|
#{self}.authors
|
data/lib/pwn/sdr/decoder/apt.rb
CHANGED
|
@@ -1,16 +1,100 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'shellwords'
|
|
4
|
-
|
|
5
3
|
module PWN
|
|
6
4
|
module SDR
|
|
7
5
|
module Decoder
|
|
8
|
-
# NOAA APT (Automatic Picture Transmission) decoder for the
|
|
9
|
-
# polar-orbiting weather satellites (NOAA-15/18/19).
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
6
|
+
# Pure-Ruby NOAA APT (Automatic Picture Transmission) decoder for the
|
|
7
|
+
# 137 MHz polar-orbiting weather satellites (NOAA-15/18/19).
|
|
8
|
+
#
|
|
9
|
+
# APT is a 2400 Hz AM subcarrier inside a ~34 kHz-wide FM downlink
|
|
10
|
+
# carrying two 909-pixel image channels at 2 lines/second (4160
|
|
11
|
+
# words/line). This module envelope-demodulates the 2400 Hz carrier
|
|
12
|
+
# from GQRX's 48 kHz UDP audio, resamples to 4160 words/sec, aligns
|
|
13
|
+
# each line on the 7-pulse Sync-A pattern, and appends the resulting
|
|
14
|
+
# 8-bit greyscale rows to a Netpbm PGM (P5) file — all in Ruby.
|
|
15
|
+
# No `sox`, no `noaa-apt`.
|
|
13
16
|
module APT
|
|
17
|
+
WORDS_PER_LINE = 4160
|
|
18
|
+
LINES_PER_SEC = 2
|
|
19
|
+
WORD_RATE = WORDS_PER_LINE * LINES_PER_SEC # 8320 Hz
|
|
20
|
+
# Sync-A: 7 cycles of 1040 Hz square = 1 1 0 0 repeated 7 times
|
|
21
|
+
SYNC_A = ([1, 1, 0, 0] * 7).freeze
|
|
22
|
+
|
|
23
|
+
# Streaming APT demodulator fed by Base.run_native.
|
|
24
|
+
class Demod
|
|
25
|
+
def initialize(rate: 48_000, out_path: nil)
|
|
26
|
+
@rate = rate
|
|
27
|
+
@carrier = 2400.0
|
|
28
|
+
@env_win = (rate / @carrier).round # ≈20 samples per cycle
|
|
29
|
+
@stamp = Time.now.strftime('%Y%m%d_%H%M%S')
|
|
30
|
+
@pgm_path = out_path || "/tmp/apt_#{@stamp}.pgm"
|
|
31
|
+
@rows = []
|
|
32
|
+
@word_buf = []
|
|
33
|
+
@minv = 1.0
|
|
34
|
+
@maxv = 0.0
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def feed(samples, &)
|
|
38
|
+
env = PWN::SDR::Decoder::DSP.envelope(samples: samples, window: @env_win)
|
|
39
|
+
words = PWN::SDR::Decoder::DSP.resample(samples: env, src_rate: @rate, dst_rate: WORD_RATE)
|
|
40
|
+
@word_buf.concat(words)
|
|
41
|
+
extract_lines(&)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def extract_lines
|
|
47
|
+
while @word_buf.length >= WORDS_PER_LINE * 2
|
|
48
|
+
off = sync_offset(@word_buf[0, WORDS_PER_LINE])
|
|
49
|
+
@word_buf.shift(off) if off.positive?
|
|
50
|
+
break if @word_buf.length < WORDS_PER_LINE
|
|
51
|
+
|
|
52
|
+
row = @word_buf.shift(WORDS_PER_LINE)
|
|
53
|
+
lo, hi = row.minmax
|
|
54
|
+
@minv = lo if lo < @minv
|
|
55
|
+
@maxv = hi if hi > @maxv
|
|
56
|
+
@rows << row
|
|
57
|
+
write_pgm if (@rows.length % 20).zero?
|
|
58
|
+
yield(
|
|
59
|
+
protocol: 'NOAA-APT',
|
|
60
|
+
lines: @rows.length,
|
|
61
|
+
seconds: @rows.length / LINES_PER_SEC,
|
|
62
|
+
pgm: @pgm_path,
|
|
63
|
+
summary: "APT line #{@rows.length} (#{@rows.length / LINES_PER_SEC}s) → #{@pgm_path}"
|
|
64
|
+
)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def sync_offset(row)
|
|
69
|
+
mid = row.sum / row.length
|
|
70
|
+
best_off = 0
|
|
71
|
+
best_cor = -1.0
|
|
72
|
+
(0..(row.length - SYNC_A.length)).each do |o|
|
|
73
|
+
cor = 0.0
|
|
74
|
+
SYNC_A.each_with_index do |s, i|
|
|
75
|
+
cor += (row[o + i] - mid) * (s.zero? ? -1.0 : 1.0)
|
|
76
|
+
end
|
|
77
|
+
if cor > best_cor
|
|
78
|
+
best_cor = cor
|
|
79
|
+
best_off = o
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
best_off
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def write_pgm
|
|
86
|
+
span = @maxv - @minv
|
|
87
|
+
span = 1.0 if span <= 0
|
|
88
|
+
File.open(@pgm_path, 'wb') do |f|
|
|
89
|
+
f.write("P5\n#{WORDS_PER_LINE} #{@rows.length}\n255\n")
|
|
90
|
+
@rows.each do |row|
|
|
91
|
+
bytes = row.map { |v| (((v - @minv) / span) * 255).clamp(0, 255).round }
|
|
92
|
+
f.write(bytes.pack('C*'))
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
14
98
|
# Supported Method Parameters::
|
|
15
99
|
# PWN::SDR::Decoder::APT.decode(
|
|
16
100
|
# freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq'
|
|
@@ -18,35 +102,11 @@ module PWN
|
|
|
18
102
|
|
|
19
103
|
public_class_method def self.decode(opts = {})
|
|
20
104
|
freq_obj = opts[:freq_obj]
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
stamp = Time.now.strftime('%Y%m%d_%H%M%S')
|
|
24
|
-
wav_out = "/tmp/apt_#{stamp}.wav"
|
|
25
|
-
png_out = "/tmp/apt_#{stamp}.png"
|
|
26
|
-
|
|
27
|
-
# Record 11 025 Hz WAV (noaa-apt's native rate) until [ENTER],
|
|
28
|
-
# emitting a heartbeat line per second so the spinner stays live,
|
|
29
|
-
# then decode to PNG on exit.
|
|
30
|
-
inner = 'sox -t raw -e signed-integer -b 16 -r 22050 -c 1 - ' \
|
|
31
|
-
"-t wav -r 11025 #{Shellwords.escape(wav_out)} & SOXPID=$!; " \
|
|
32
|
-
'trap "kill $SOXPID 2>/dev/null" EXIT INT TERM; ' \
|
|
33
|
-
'while kill -0 $SOXPID 2>/dev/null; do ' \
|
|
34
|
-
"echo APT_REC seconds=$SECONDS file=#{wav_out}; sleep 1; done"
|
|
35
|
-
|
|
36
|
-
PWN::SDR::Decoder::Base.run_pipeline(
|
|
105
|
+
PWN::SDR::Decoder::Base.run_native(
|
|
37
106
|
freq_obj: freq_obj,
|
|
38
107
|
protocol: 'NOAA-APT',
|
|
39
|
-
|
|
40
|
-
decode_cmd: "bash -c #{Shellwords.escape(inner)}",
|
|
41
|
-
line_match: /^APT_REC/,
|
|
42
|
-
parser: proc { |line| { protocol: 'NOAA-APT', wav: wav_out, png: png_out, summary: line.strip } }
|
|
108
|
+
demod: Demod.new
|
|
43
109
|
)
|
|
44
|
-
|
|
45
|
-
return unless File.exist?(wav_out) && File.size(wav_out).positive?
|
|
46
|
-
|
|
47
|
-
system('noaa-apt', wav_out, '-o', png_out)
|
|
48
|
-
|
|
49
|
-
puts "[*] APT image written: #{png_out}" if File.exist?(png_out)
|
|
50
110
|
end
|
|
51
111
|
|
|
52
112
|
# Author(s):: 0day Inc. <support@0dayinc.com>
|
|
@@ -58,13 +118,14 @@ module PWN
|
|
|
58
118
|
# Display Usage for this Module
|
|
59
119
|
|
|
60
120
|
public_class_method def self.help
|
|
61
|
-
puts "USAGE:
|
|
121
|
+
puts "USAGE (ruby-native, no external binaries):
|
|
62
122
|
#{self}.decode(
|
|
63
123
|
freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq'
|
|
64
124
|
)
|
|
65
125
|
|
|
66
|
-
NOTE:
|
|
67
|
-
|
|
126
|
+
NOTE: Set GQRX to WFM (mono), ~34 kHz filter. Writes an 8-bit
|
|
127
|
+
greyscale Netpbm P5 image to /tmp/apt_<ts>.pgm every 10 s
|
|
128
|
+
of received pass. Both A/B channels are in one strip.
|
|
68
129
|
|
|
69
130
|
#{self}.authors
|
|
70
131
|
"
|