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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/documentation/Agent-Tool-Registry.md +2 -2
  4. data/documentation/Cron.md +13 -0
  5. data/documentation/Diagrams.md +1 -1
  6. data/documentation/Extrospection.md +71 -5
  7. data/documentation/Home.md +2 -2
  8. data/documentation/How-PWN-Works.md +1 -1
  9. data/documentation/Mistakes.md +2 -1
  10. data/documentation/Persistence.md +2 -1
  11. data/documentation/Skills-Memory-Learning.md +1 -0
  12. data/documentation/Transparent-Browser.md +18 -1
  13. data/documentation/diagrams/agent-tool-registry.svg +55 -54
  14. data/documentation/diagrams/ai-integration-tool-calling.svg +24 -24
  15. data/documentation/diagrams/aws-cloud-security.svg +25 -25
  16. data/documentation/diagrams/burp-vs-zap-preference.svg +12 -12
  17. data/documentation/diagrams/code-scanning-sast.svg +25 -25
  18. data/documentation/diagrams/cron-scheduling.svg +23 -23
  19. data/documentation/diagrams/dot/agent-tool-registry.dot +2 -2
  20. data/documentation/diagrams/dot/extrospection-world-awareness.dot +29 -8
  21. data/documentation/diagrams/dot/memory-skills-detailed.dot +4 -0
  22. data/documentation/diagrams/dot/overall-pwn-architecture.dot +2 -2
  23. data/documentation/diagrams/dot/persistence-filesystem.dot +2 -1
  24. data/documentation/diagrams/dot/pwn-ai-feedback-learning-loop.dot +10 -4
  25. data/documentation/diagrams/driver-framework.svg +13 -13
  26. data/documentation/diagrams/extrospection-world-awareness.svg +229 -99
  27. data/documentation/diagrams/fuzzing-workflow.svg +24 -24
  28. data/documentation/diagrams/hardware-hacking.svg +18 -18
  29. data/documentation/diagrams/history-to-drivers.svg +18 -18
  30. data/documentation/diagrams/memory-skills-detailed.svg +124 -101
  31. data/documentation/diagrams/mistakes-negative-feedback.svg +55 -55
  32. data/documentation/diagrams/network-infra-testing.svg +27 -27
  33. data/documentation/diagrams/overall-pwn-architecture.svg +85 -85
  34. data/documentation/diagrams/penetration-testing-workflow.svg +30 -30
  35. data/documentation/diagrams/persistence-filesystem.svg +94 -85
  36. data/documentation/diagrams/plugin-ecosystem.svg +35 -35
  37. data/documentation/diagrams/pwn-ai-feedback-learning-loop.svg +226 -180
  38. data/documentation/diagrams/pwn-repl-prototyping.svg +20 -20
  39. data/documentation/diagrams/reporting-pipeline.svg +18 -18
  40. data/documentation/diagrams/reverse-engineering-flow.svg +21 -21
  41. data/documentation/diagrams/sdr-radio-flow.svg +31 -31
  42. data/documentation/diagrams/sessions-cron-automation.svg +18 -18
  43. data/documentation/diagrams/swarm-multi-agent.svg +39 -39
  44. data/documentation/diagrams/web-application-testing.svg +26 -26
  45. data/documentation/diagrams/zero-day-research-flow.svg +25 -25
  46. data/documentation/pwn-ai-Agent.md +1 -1
  47. data/lib/pwn/ai/agent/extrospection.rb +433 -4
  48. data/lib/pwn/ai/agent/tools/extrospection.rb +88 -3
  49. data/lib/pwn/sdr/decoder/adsb.rb +14 -33
  50. data/lib/pwn/sdr/decoder/apt.rb +97 -36
  51. data/lib/pwn/sdr/decoder/base.rb +258 -171
  52. data/lib/pwn/sdr/decoder/bluetooth.rb +13 -20
  53. data/lib/pwn/sdr/decoder/dect.rb +13 -27
  54. data/lib/pwn/sdr/decoder/dsp.rb +396 -0
  55. data/lib/pwn/sdr/decoder/flex.rb +177 -210
  56. data/lib/pwn/sdr/decoder/gps.rb +12 -21
  57. data/lib/pwn/sdr/decoder/gsm.rb +21 -73
  58. data/lib/pwn/sdr/decoder/iridium.rb +11 -26
  59. data/lib/pwn/sdr/decoder/lora.rb +16 -23
  60. data/lib/pwn/sdr/decoder/lte.rb +11 -32
  61. data/lib/pwn/sdr/decoder/morse.rb +95 -21
  62. data/lib/pwn/sdr/decoder/p25.rb +19 -16
  63. data/lib/pwn/sdr/decoder/pager.rb +22 -38
  64. data/lib/pwn/sdr/decoder/pocsag.rb +175 -68
  65. data/lib/pwn/sdr/decoder/rfid.rb +24 -33
  66. data/lib/pwn/sdr/decoder/rtl433.rb +21 -30
  67. data/lib/pwn/sdr/decoder/rtty.rb +100 -27
  68. data/lib/pwn/sdr/decoder/wifi.rb +21 -42
  69. data/lib/pwn/sdr/decoder/zigbee.rb +18 -40
  70. data/lib/pwn/sdr/decoder.rb +8 -0
  71. data/lib/pwn/version.rb +1 -1
  72. data/spec/lib/pwn/sdr/decoder/dsp_spec.rb +15 -0
  73. data/third_party/pwn_rdoc.jsonl +24 -3
  74. metadata +3 -1
@@ -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 (Automatic Dependent Surveillance Broadcast) decoder for
9
- # aircraft transponder squitters on 1090 MHz (Mode-S / ES) and 978 MHz
10
- # (UAT). 2 Mbit/s PPM cannot be recovered from GQRX audio, so this
11
- # module drives `dump1090` (or `dump978-fa`) directly against the SDR
12
- # and structures each SBS-1/BaseStation CSV line it emits on stdout.
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
- raise 'ERROR: :freq_obj is required' unless freq_obj.is_a?(Hash)
29
-
30
- hz = PWN::SDR.hz_to_i(freq: freq_obj[:freq])
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
- required_bins: uat ? %w[dump978-fa uat2text] : %w[dump1090],
47
- direct_cmd: direct_cmd,
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
@@ -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 137 MHz
9
- # polar-orbiting weather satellites (NOAA-15/18/19). APT is a 2400 Hz
10
- # AM subcarrier inside a 34 kHz-wide FM downlink; GQRX's UDP audio is
11
- # recorded to a WAV, then handed to `noaa-apt` (or `satdump`) to render
12
- # the two-channel visible/IR image strip.
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
- raise 'ERROR: :freq_obj is required' unless freq_obj.is_a?(Hash)
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
- required_bins: %w[sox noaa-apt],
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: Requires `sox` and `noaa-apt`. Set GQRX to FM, ~34 kHz BW.
67
- Records the pass to /tmp/apt_<ts>.wav, decodes to PNG on exit.
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
  "