pwn 0.5.621 → 0.5.626

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 (124) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -2
  3. data/Gemfile +1 -1
  4. data/README.md +7 -1
  5. data/bin/pwn_gqrx_scanner +78 -9
  6. data/documentation/Agent-Tool-Registry.md +3 -3
  7. data/documentation/Configuration.md +301 -47
  8. data/documentation/Cron.md +5 -3
  9. data/documentation/Diagrams.md +1 -1
  10. data/documentation/Extrospection.md +472 -26
  11. data/documentation/FFI.md +72 -8
  12. data/documentation/Home.md +4 -4
  13. data/documentation/How-PWN-Works.md +7 -3
  14. data/documentation/Mistakes.md +9 -0
  15. data/documentation/SDR.md +83 -10
  16. data/documentation/Skills-Memory-Learning.md +101 -11
  17. data/documentation/diagrams/agent-tool-registry.svg +56 -55
  18. data/documentation/diagrams/ai-integration-tool-calling.svg +24 -24
  19. data/documentation/diagrams/aws-cloud-security.svg +25 -25
  20. data/documentation/diagrams/burp-vs-zap-preference.svg +12 -12
  21. data/documentation/diagrams/code-scanning-sast.svg +25 -25
  22. data/documentation/diagrams/cron-scheduling.svg +23 -23
  23. data/documentation/diagrams/dot/agent-tool-registry.dot +2 -2
  24. data/documentation/diagrams/dot/extrospection-world-awareness.dot +33 -6
  25. data/documentation/diagrams/dot/hardware-hacking.dot +3 -1
  26. data/documentation/diagrams/dot/memory-skills-detailed.dot +4 -2
  27. data/documentation/diagrams/dot/mistakes-negative-feedback.dot +4 -2
  28. data/documentation/diagrams/dot/overall-pwn-architecture.dot +3 -3
  29. data/documentation/diagrams/dot/persistence-filesystem.dot +3 -3
  30. data/documentation/diagrams/dot/pwn-ai-feedback-learning-loop.dot +10 -4
  31. data/documentation/diagrams/dot/sdr-radio-flow.dot +39 -16
  32. data/documentation/diagrams/driver-framework.svg +13 -13
  33. data/documentation/diagrams/extrospection-world-awareness.svg +383 -177
  34. data/documentation/diagrams/fuzzing-workflow.svg +24 -24
  35. data/documentation/diagrams/hardware-hacking.svg +84 -69
  36. data/documentation/diagrams/history-to-drivers.svg +18 -18
  37. data/documentation/diagrams/memory-skills-detailed.svg +137 -120
  38. data/documentation/diagrams/mistakes-negative-feedback.svg +152 -137
  39. data/documentation/diagrams/network-infra-testing.svg +27 -27
  40. data/documentation/diagrams/overall-pwn-architecture.svg +97 -97
  41. data/documentation/diagrams/penetration-testing-workflow.svg +30 -30
  42. data/documentation/diagrams/persistence-filesystem.svg +100 -94
  43. data/documentation/diagrams/plugin-ecosystem.svg +35 -35
  44. data/documentation/diagrams/pwn-ai-feedback-learning-loop.svg +254 -207
  45. data/documentation/diagrams/pwn-repl-prototyping.svg +20 -20
  46. data/documentation/diagrams/reporting-pipeline.svg +18 -18
  47. data/documentation/diagrams/reverse-engineering-flow.svg +21 -21
  48. data/documentation/diagrams/sdr-radio-flow.svg +223 -91
  49. data/documentation/diagrams/sessions-cron-automation.svg +18 -18
  50. data/documentation/diagrams/swarm-multi-agent.svg +39 -39
  51. data/documentation/diagrams/web-application-testing.svg +26 -26
  52. data/documentation/diagrams/zero-day-research-flow.svg +25 -25
  53. data/documentation/pwn-ai-Agent.md +16 -10
  54. data/documentation/pwn_silent_help_learn_demo.gif +0 -0
  55. data/lib/pwn/ai/agent/assembly.rb +1 -1
  56. data/lib/pwn/ai/agent/btc.rb +1 -1
  57. data/lib/pwn/ai/agent/burp_suite.rb +1 -1
  58. data/lib/pwn/ai/agent/extrospection.rb +2562 -57
  59. data/lib/pwn/ai/agent/gqrx.rb +2 -2
  60. data/lib/pwn/ai/agent/hacker_one.rb +1 -1
  61. data/lib/pwn/ai/agent/learning.rb +16 -16
  62. data/lib/pwn/ai/agent/loop.rb +1 -1
  63. data/lib/pwn/ai/agent/{introspection.rb → reflect.rb} +12 -12
  64. data/lib/pwn/ai/agent/sast.rb +1 -1
  65. data/lib/pwn/ai/agent/tools/extrospection.rb +311 -8
  66. data/lib/pwn/ai/agent/tools/learning.rb +7 -7
  67. data/lib/pwn/ai/agent/transparent_browser.rb +1 -1
  68. data/lib/pwn/ai/agent/vuln_gen.rb +2 -2
  69. data/lib/pwn/ai/agent.rb +1 -1
  70. data/lib/pwn/ai/open_ai.rb +10 -6
  71. data/lib/pwn/config.rb +5 -4
  72. data/lib/pwn/ffi/adalm_pluto.rb +498 -0
  73. data/lib/pwn/ffi/fftw.rb +192 -0
  74. data/lib/pwn/ffi/hack_rf.rb +193 -0
  75. data/lib/pwn/ffi/liquid.rb +244 -0
  76. data/lib/pwn/ffi/rtl_sdr.rb +210 -0
  77. data/lib/pwn/ffi/soapy_sdr.rb +177 -0
  78. data/lib/pwn/ffi/stdio.rb +9 -1
  79. data/lib/pwn/ffi/volk.rb +241 -0
  80. data/lib/pwn/ffi.rb +45 -2
  81. data/lib/pwn/plugins/burp_suite.rb +2 -2
  82. data/lib/pwn/sast/pom_version.rb +2 -2
  83. data/lib/pwn/sast/test_case_engine.rb +1 -1
  84. data/lib/pwn/sdr/decoder/adsb.rb +201 -12
  85. data/lib/pwn/sdr/decoder/apt.rb +19 -5
  86. data/lib/pwn/sdr/decoder/base.rb +314 -1
  87. data/lib/pwn/sdr/decoder/bluetooth.rb +91 -18
  88. data/lib/pwn/sdr/decoder/dect.rb +81 -23
  89. data/lib/pwn/sdr/decoder/dsp.rb +229 -15
  90. data/lib/pwn/sdr/decoder/flex.rb +23 -6
  91. data/lib/pwn/sdr/decoder/gps.rb +80 -18
  92. data/lib/pwn/sdr/decoder/gsm.rb +83 -28
  93. data/lib/pwn/sdr/decoder/iridium.rb +80 -18
  94. data/lib/pwn/sdr/decoder/lora.rb +84 -28
  95. data/lib/pwn/sdr/decoder/lte.rb +80 -18
  96. data/lib/pwn/sdr/decoder/morse.rb +23 -6
  97. data/lib/pwn/sdr/decoder/p25.rb +90 -31
  98. data/lib/pwn/sdr/decoder/pager.rb +23 -6
  99. data/lib/pwn/sdr/decoder/pocsag.rb +23 -6
  100. data/lib/pwn/sdr/decoder/rds.rb +219 -52
  101. data/lib/pwn/sdr/decoder/rfid.rb +81 -27
  102. data/lib/pwn/sdr/decoder/rtl433.rb +85 -27
  103. data/lib/pwn/sdr/decoder/rtty.rb +23 -6
  104. data/lib/pwn/sdr/decoder/wifi.rb +86 -32
  105. data/lib/pwn/sdr/decoder/zigbee.rb +88 -35
  106. data/lib/pwn/sdr/decoder.rb +6 -5
  107. data/lib/pwn/sdr/frequency_allocation.rb +124 -81
  108. data/lib/pwn/sdr/gqrx.rb +1513 -165
  109. data/lib/pwn/version.rb +1 -1
  110. data/spec/lib/pwn/ai/agent/extrospection_spec.rb +96 -0
  111. data/spec/lib/pwn/ai/agent/{introspection_spec.rb → reflect_spec.rb} +3 -3
  112. data/spec/lib/pwn/ai/agent/tools/extrospection_spec.rb +8 -24
  113. data/spec/lib/pwn/ffi/adalm_pluto_spec.rb +37 -0
  114. data/spec/lib/pwn/ffi/fftw_spec.rb +26 -0
  115. data/spec/lib/pwn/ffi/hack_rf_spec.rb +25 -0
  116. data/spec/lib/pwn/ffi/liquid_spec.rb +42 -0
  117. data/spec/lib/pwn/ffi/rtl_sdr_spec.rb +24 -0
  118. data/spec/lib/pwn/ffi/soapy_sdr_spec.rb +25 -0
  119. data/spec/lib/pwn/ffi/volk_spec.rb +36 -0
  120. data/spec/lib/pwn/sdr/decoder/base_iq_spec.rb +65 -0
  121. data/spec/lib/pwn/sdr/decoder/dsp_spec.rb +50 -4
  122. data/spec/lib/pwn/sdr/decoder/rds_spec.rb +45 -4
  123. data/third_party/pwn_rdoc.jsonl +279 -30
  124. metadata +21 -5
@@ -106,11 +106,28 @@ module PWN
106
106
 
107
107
  public_class_method def self.decode(opts = {})
108
108
  freq_obj = opts[:freq_obj]
109
- PWN::SDR::Decoder::Base.run_native(
110
- freq_obj: freq_obj,
111
- protocol: 'RTTY',
112
- demod: Demod.new
113
- )
109
+ # Prefer true-air I/Q (FM-demod → existing audio demod) when the
110
+ # operator asks for a source/file or sets freq_obj[:iq_source].
111
+ # Otherwise keep the GQRX 48 kHz UDP audio path (run_native).
112
+ want_iq = opts[:source] || opts[:file] || freq_obj[:iq_source] || freq_obj[:iq_file]
113
+ if want_iq
114
+ PWN::SDR::Decoder::Base.run_iq(
115
+ freq_obj: freq_obj,
116
+ protocol: 'RTTY',
117
+ demod: Demod.new,
118
+ sample_rate: (opts[:sample_rate] || freq_obj[:iq_rate] || 48_000).to_i,
119
+ source: opts[:source],
120
+ file: opts[:file],
121
+ fm_demod: true,
122
+ note: 'RTTY true-air: FM-demod I/Q then native bit recovery; falls back to detector without SDR hardware.'
123
+ )
124
+ else
125
+ PWN::SDR::Decoder::Base.run_native(
126
+ freq_obj: freq_obj,
127
+ protocol: 'RTTY',
128
+ demod: Demod.new
129
+ )
130
+ end
114
131
  end
115
132
 
116
133
  # Author(s):: 0day Inc. <support@0dayinc.com>
@@ -122,7 +139,7 @@ module PWN
122
139
  # Display Usage for this Module
123
140
 
124
141
  public_class_method def self.help
125
- puts "USAGE (ruby-native 2-FSK ITA2, no external binaries):
142
+ puts "USAGE (true-air I/Q + GQRX-audio native paths, no external binaries):
126
143
  #{self}.decode(
127
144
  freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq'
128
145
  )
@@ -3,17 +3,68 @@
3
3
  module PWN
4
4
  module SDR
5
5
  module Decoder
6
- # Pure-Ruby 802.11 (WiFi) activity detector.
7
- #
8
- # 20+ MHz OFDM cannot be demodulated in interpreted Ruby in real
9
- # time. Native mode reports channel occupancy/duty and maps
10
- # freq_obj to a WLAN channel number. `parse_line` retained for
11
- # offline pipe-delimited tshark-fields analysis.
6
+ # True-air + detector-fallback decoder for WiFi.
7
+ # Prefers PWN::FFI I/Q (RTL-SDR / ADALM-Pluto / HackRF / capture file)
8
+ # via Base.run_iq; degrades to Base.run_detector with no hardware.
12
9
  module WiFi
13
- TSHARK_FIELDS = %w[
14
- frame.time_relative wlan.fc.type_subtype wlan.bssid wlan.sa
15
- wlan.da wlan_radio.channel wlan_radio.signal_dbm wlan.ssid
16
- ].freeze
10
+ # Streaming I/Q energy/burst demod for Base.run_iq.
11
+ class DemodIQ
12
+ def initialize(rate:, protocol:, modulation:, extra: {})
13
+ @rate = rate.to_f
14
+ @protocol = protocol
15
+ @modulation = modulation
16
+ @extra = extra
17
+ @floor = nil
18
+ @in_burst = false
19
+ @burst_t0 = nil
20
+ @peak = -200.0
21
+ @burst_n = 0
22
+ @threshold = (extra[:threshold] || 8.0).to_f
23
+ end
24
+
25
+ def feed_iq(samples, rate: nil, &)
26
+ @rate = rate.to_f if rate
27
+ m2 = PWN::SDR::Decoder::DSP.mag_sq(iq: samples)
28
+ hop = [(@rate / 1000.0).round, 1].max
29
+ i = 0
30
+ while i < m2.length
31
+ win = m2[i, hop]
32
+ break if win.nil? || win.empty?
33
+
34
+ ms = win.sum / win.length
35
+ lvl = ms.positive? ? (10.0 * Math.log10(ms)) : -120.0
36
+ @floor = @floor.nil? ? lvl : ((@floor * 0.98) + (lvl * 0.02))
37
+ delta = lvl - @floor
38
+ if delta >= @threshold
39
+ unless @in_burst
40
+ @in_burst = true
41
+ @burst_t0 = Time.now
42
+ @peak = lvl
43
+ end
44
+ @peak = lvl if lvl > @peak
45
+ elsif @in_burst
46
+ @in_burst = false
47
+ @burst_n += 1
48
+ dur_ms = ((Time.now - @burst_t0) * 1000).round
49
+ msg = {
50
+ protocol: @protocol, event: 'burst', source: 'iq',
51
+ burst_no: @burst_n, peak_dbfs: @peak.round(1),
52
+ floor_dbfs: @floor.round(1), delta_db: (@peak - @floor).round(1),
53
+ duration_ms: dur_ms, modulation: @modulation,
54
+ sample_rate: @rate.to_i
55
+ }.merge(@extra.except(:threshold))
56
+ # protocol-specific enrichment
57
+ msg.merge!(self.class.enrich(msg)) if self.class.respond_to?(:enrich)
58
+ msg[:summary] = format(
59
+ '%<p>s IQ-burst #%<n>d peak=%<pk>+.1f dBFS Δ=%<d>.1f dB dur=%<ms>d ms',
60
+ p: @protocol, n: @burst_n, pk: @peak, d: @peak - @floor, ms: dur_ms
61
+ )
62
+ yield msg if block_given?
63
+ end
64
+ i += hop
65
+ end
66
+ end
67
+ end
17
68
 
18
69
  # Supported Method Parameters::
19
70
  # PWN::SDR::Decoder::WiFi.decode(
@@ -22,33 +73,38 @@ module PWN
22
73
 
23
74
  public_class_method def self.decode(opts = {})
24
75
  freq_obj = opts[:freq_obj]
25
- hz = PWN::SDR.hz_to_i(freq: freq_obj[:freq])
26
- mhz = (hz / 1_000_000.0).round
27
- ch = case mhz
28
- when 2412..2472 then ((mhz - 2412) / 5) + 1
29
- when 2484 then 14
30
- when 5000..5900 then (mhz - 5000) / 5
31
- else 0
32
- end
33
- PWN::SDR::Decoder::Base.run_detector(
76
+
77
+ rate = (opts[:sample_rate] || freq_obj[:iq_rate] || 2_000_000).to_i
78
+ proto = 'WiFi-802.11'
79
+ demod = DemodIQ.new(
80
+ rate: rate, protocol: proto, modulation: 'OFDM',
81
+ extra: { threshold: 6.0 }
82
+ )
83
+ PWN::SDR::Decoder::Base.run_iq(
34
84
  freq_obj: freq_obj,
35
- protocol: 'WiFi-802.11',
36
- note: '20+ MHz OFDM — native mode reports channel occupancy/duty only.',
85
+ protocol: proto,
86
+ sample_rate: rate,
87
+ source: opts[:source],
88
+ file: opts[:file],
89
+ demod: demod,
37
90
  threshold: 6.0,
38
- describe: proc { |b| { modulation: 'OFDM', channel: ch, mhz: mhz, airtime_ms: b[:duration_ms] } }
91
+ note: '20+ MHz OFDM true-air I/Q path reports channel occupancy/duty.',
92
+ describe: proc { |b| { modulation: 'OFDM', airtime_ms: b[:duration_ms] } }
39
93
  )
40
94
  end
41
95
 
42
- # Supported Method Parameters::
43
- # PWN::SDR::Decoder::WiFi.parse_line(line: 't|subtype|bssid|sa|da|ch|rssi|ssid')
96
+ TSHARK_FIELDS = %w[
97
+ frame.time_relative wlan.fc.type_subtype wlan.bssid wlan.sa
98
+ wlan.da wlan_radio.channel wlan_radio.signal_dbm wlan.ssid
99
+ ].freeze
44
100
 
45
101
  public_class_method def self.parse_line(opts = {})
46
102
  f = opts[:line].to_s.split('|', -1)
47
103
  out = {
48
104
  protocol: 'WiFi', subtype: f[1], bssid: f[2], sa: f[3], da: f[4],
49
- channel: f[5], rssi_dbm: f[6], ssid: f[7]
105
+ channel: f[5], rssi: f[6], ssid: f[7]
50
106
  }.reject { |_, v| v.to_s.empty? }
51
- out[:summary] = "WiFi ch#{out[:channel]} #{out[:bssid]} '#{out[:ssid]}' #{out[:rssi_dbm]}dBm"
107
+ out[:summary] = "WiFi ch=#{out[:channel]} BSSID=#{out[:bssid]} SSID=#{out[:ssid]} RSSI=#{out[:rssi]}"
52
108
  out
53
109
  end
54
110
 
@@ -58,16 +114,14 @@ module PWN
58
114
  "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n"
59
115
  end
60
116
 
61
- # Display Usage for this Module
62
-
63
117
  public_class_method def self.help
64
- puts "USAGE (ruby-native detector, no external binaries):
118
+ puts "USAGE (true-air I/Q via PWN::FFI + detector fallback):
65
119
  #{self}.decode(
66
- freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq'
120
+ freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq',
121
+ source: 'optional - :auto|:rtlsdr|:adalm_pluto|:file',
122
+ file: 'optional - .cu8/.cs16 capture'
67
123
  )
68
124
 
69
- #{self}.parse_line(line: '0.1|8|aa:bb:..|aa:bb:..|ff:ff:..|6|-42|linksys')
70
-
71
125
  #{self}.authors
72
126
  "
73
127
  end
@@ -3,17 +3,68 @@
3
3
  module PWN
4
4
  module SDR
5
5
  module Decoder
6
- # Pure-Ruby IEEE 802.15.4 / ZigBee activity detector.
7
- #
8
- # 250 kbit/s O-QPSK across 2 MHz channels — native mode reports
9
- # per-channel packet bursts and derives channel 11–26 from
10
- # freq_obj. `parse_line` retained for offline pipe-delimited
11
- # analysis.
6
+ # True-air + detector-fallback decoder for ZigBee.
7
+ # Prefers PWN::FFI I/Q (RTL-SDR / ADALM-Pluto / HackRF / capture file)
8
+ # via Base.run_iq; degrades to Base.run_detector with no hardware.
12
9
  module ZigBee
13
- TSHARK_FIELDS = %w[
14
- frame.time_relative wpan.src16 wpan.dst16 wpan.src64 wpan.dst64
15
- wpan.dst_pan wpan.frame_type zbee_nwk.cmd.id wpan.seq_no
16
- ].freeze
10
+ # Streaming I/Q energy/burst demod for Base.run_iq.
11
+ class DemodIQ
12
+ def initialize(rate:, protocol:, modulation:, extra: {})
13
+ @rate = rate.to_f
14
+ @protocol = protocol
15
+ @modulation = modulation
16
+ @extra = extra
17
+ @floor = nil
18
+ @in_burst = false
19
+ @burst_t0 = nil
20
+ @peak = -200.0
21
+ @burst_n = 0
22
+ @threshold = (extra[:threshold] || 8.0).to_f
23
+ end
24
+
25
+ def feed_iq(samples, rate: nil, &)
26
+ @rate = rate.to_f if rate
27
+ m2 = PWN::SDR::Decoder::DSP.mag_sq(iq: samples)
28
+ hop = [(@rate / 1000.0).round, 1].max
29
+ i = 0
30
+ while i < m2.length
31
+ win = m2[i, hop]
32
+ break if win.nil? || win.empty?
33
+
34
+ ms = win.sum / win.length
35
+ lvl = ms.positive? ? (10.0 * Math.log10(ms)) : -120.0
36
+ @floor = @floor.nil? ? lvl : ((@floor * 0.98) + (lvl * 0.02))
37
+ delta = lvl - @floor
38
+ if delta >= @threshold
39
+ unless @in_burst
40
+ @in_burst = true
41
+ @burst_t0 = Time.now
42
+ @peak = lvl
43
+ end
44
+ @peak = lvl if lvl > @peak
45
+ elsif @in_burst
46
+ @in_burst = false
47
+ @burst_n += 1
48
+ dur_ms = ((Time.now - @burst_t0) * 1000).round
49
+ msg = {
50
+ protocol: @protocol, event: 'burst', source: 'iq',
51
+ burst_no: @burst_n, peak_dbfs: @peak.round(1),
52
+ floor_dbfs: @floor.round(1), delta_db: (@peak - @floor).round(1),
53
+ duration_ms: dur_ms, modulation: @modulation,
54
+ sample_rate: @rate.to_i
55
+ }.merge(@extra.except(:threshold))
56
+ # protocol-specific enrichment
57
+ msg.merge!(self.class.enrich(msg)) if self.class.respond_to?(:enrich)
58
+ msg[:summary] = format(
59
+ '%<p>s IQ-burst #%<n>d peak=%<pk>+.1f dBFS Δ=%<d>.1f dB dur=%<ms>d ms',
60
+ p: @protocol, n: @burst_n, pk: @peak, d: @peak - @floor, ms: dur_ms
61
+ )
62
+ yield msg if block_given?
63
+ end
64
+ i += hop
65
+ end
66
+ end
67
+ end
17
68
 
18
69
  # Supported Method Parameters::
19
70
  # PWN::SDR::Decoder::ZigBee.decode(
@@ -22,31 +73,35 @@ module PWN
22
73
 
23
74
  public_class_method def self.decode(opts = {})
24
75
  freq_obj = opts[:freq_obj]
25
- hz = PWN::SDR.hz_to_i(freq: freq_obj[:freq])
26
- ch = (((hz - 2_405_000_000) / 5_000_000.0).round + 11).clamp(11, 26)
27
- PWN::SDR::Decoder::Base.run_detector(
76
+
77
+ rate = (opts[:sample_rate] || freq_obj[:iq_rate] || 2_000_000).to_i
78
+ proto = 'ZigBee'
79
+ demod = DemodIQ.new(
80
+ rate: rate, protocol: proto, modulation: 'O-QPSK',
81
+ extra: { threshold: 8.0 }
82
+ )
83
+ PWN::SDR::Decoder::Base.run_iq(
28
84
  freq_obj: freq_obj,
29
- protocol: 'ZigBee',
30
- note: '250 kbit/s O-QPSK — native mode reports 802.15.4 packet bursts only.',
85
+ protocol: proto,
86
+ sample_rate: rate,
87
+ source: opts[:source],
88
+ file: opts[:file],
89
+ demod: demod,
31
90
  threshold: 8.0,
32
- describe: proc { |b|
33
- octets = (b[:duration_ms] * 250 / 8).round
34
- { modulation: 'O-QPSK', channel: ch, est_octets: octets, classification: octets < 20 ? 'ACK/beacon' : 'data-frame' }
35
- }
91
+ note: 'O-QPSK 250 kbit/s DSSS — true-air I/Q path reports frame bursts on the tuned channel.',
92
+ describe: proc { |b| { modulation: 'O-QPSK', symbol_rate: 62_500, classification: b[:duration_ms] < 5 ? 'ACK' : 'MAC-frame' } }
36
93
  )
37
94
  end
38
95
 
39
- # Supported Method Parameters::
40
- # PWN::SDR::Decoder::ZigBee.parse_line(line: 't|src16|dst16|src64|dst64|pan|type|cmd|seq')
41
-
42
96
  public_class_method def self.parse_line(opts = {})
43
- f = opts[:line].to_s.split('|', -1)
44
- out = {
45
- protocol: 'ZigBee', src16: f[1], dst16: f[2], src64: f[3], dst64: f[4],
46
- pan_id: f[5], frame_type: f[6], nwk_cmd: f[7], seq: f[8]
47
- }.reject { |_, v| v.to_s.empty? }
48
- out[:summary] = "ZigBee PAN=#{out[:pan_id]} #{out[:src16] || out[:src64]}→#{out[:dst16] || out[:dst64]} type=#{out[:frame_type]}"
49
- out
97
+ line = opts[:line].to_s
98
+ out = { protocol: 'ZigBee' }
99
+ out[:pan] = ::Regexp.last_match(1) if line =~ /PAN[:= ]+([0-9A-Fa-f]+)/i
100
+ out[:src] = ::Regexp.last_match(1) if line =~ /src[:= ]+([0-9A-Fa-f:]+)/i
101
+ out[:dst] = ::Regexp.last_match(1) if line =~ /dst[:= ]+([0-9A-Fa-f:]+)/i
102
+ out[:cmd] = ::Regexp.last_match(1) if line =~ /\b(Beacon|Data|ACK|Cmd)\b/i
103
+ out[:summary] = "ZigBee #{out[:cmd]} PAN=#{out[:pan]} #{out[:src]}→#{out[:dst]}"
104
+ out.compact
50
105
  end
51
106
 
52
107
  # Author(s):: 0day Inc. <support@0dayinc.com>
@@ -55,16 +110,14 @@ module PWN
55
110
  "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n"
56
111
  end
57
112
 
58
- # Display Usage for this Module
59
-
60
113
  public_class_method def self.help
61
- puts "USAGE (ruby-native detector, no external binaries):
114
+ puts "USAGE (true-air I/Q via PWN::FFI + detector fallback):
62
115
  #{self}.decode(
63
- freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq'
116
+ freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq',
117
+ source: 'optional - :auto|:rtlsdr|:adalm_pluto|:file',
118
+ file: 'optional - .cu8/.cs16 capture'
64
119
  )
65
120
 
66
- #{self}.parse_line(line: '0.1|0x0001|0xffff||||0x01||42')
67
-
68
121
  #{self}.authors
69
122
  "
70
123
  end
@@ -11,11 +11,12 @@ module PWN
11
11
  # PWN::SDR::FrequencyAllocation.band_plans.
12
12
  #
13
13
  # 100 % ruby-native — no decoder in this namespace shells out to an
14
- # external binary. Audio-rate protocols (POCSAG, FLEX, Morse, RTTY,
15
- # APT, Pager) are fully demodulated in Ruby via PWN::SDR::Decoder::DSP;
16
- # wideband/I/Q-only protocols (ADS-B, GSM, LTE, GPS, LoRa, WiFi, DECT,
17
- # ZigBee, Bluetooth, Iridium, P25, RFID, RTL433) run a native
18
- # burst/energy characteriser (see Base.run_detector).
14
+ # external binary. Three pipelines (Base):
15
+ # run_native — GQRX 48 kHz audio tap (POCSAG/FLEX/Morse/RTTY/APT/Pager)
16
+ # run_iq — true-air I/Q via PWN::FFI::{RTLSdr,AdalmPluto,HackRF}
17
+ # or a .cu8/.cs16 capture file; all modules use this when
18
+ # hardware/file is present (ADS-B fully slices Mode-S PPM)
19
+ # run_detector — energy/burst characteriser fallback when no I/Q source
19
20
  module Decoder
20
21
  autoload :ADSB, 'pwn/sdr/decoder/adsb'
21
22
  autoload :APT, 'pwn/sdr/decoder/apt'