pwn 0.5.622 → 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.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -2
- data/README.md +7 -1
- data/bin/pwn_gqrx_scanner +78 -9
- data/documentation/Agent-Tool-Registry.md +2 -2
- data/documentation/Configuration.md +11 -2
- data/documentation/Cron.md +5 -3
- data/documentation/Diagrams.md +1 -1
- data/documentation/Extrospection.md +472 -26
- data/documentation/FFI.md +72 -8
- data/documentation/Home.md +4 -4
- data/documentation/How-PWN-Works.md +7 -3
- data/documentation/Mistakes.md +9 -0
- data/documentation/SDR.md +83 -10
- data/documentation/Skills-Memory-Learning.md +100 -10
- data/documentation/diagrams/agent-tool-registry.svg +56 -55
- 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 +33 -6
- data/documentation/diagrams/dot/hardware-hacking.dot +3 -1
- data/documentation/diagrams/dot/memory-skills-detailed.dot +4 -2
- data/documentation/diagrams/dot/mistakes-negative-feedback.dot +4 -2
- data/documentation/diagrams/dot/overall-pwn-architecture.dot +3 -3
- data/documentation/diagrams/dot/persistence-filesystem.dot +3 -3
- data/documentation/diagrams/dot/pwn-ai-feedback-learning-loop.dot +9 -3
- data/documentation/diagrams/dot/sdr-radio-flow.dot +39 -16
- data/documentation/diagrams/driver-framework.svg +13 -13
- data/documentation/diagrams/extrospection-world-awareness.svg +383 -177
- data/documentation/diagrams/fuzzing-workflow.svg +24 -24
- data/documentation/diagrams/hardware-hacking.svg +84 -69
- data/documentation/diagrams/history-to-drivers.svg +18 -18
- data/documentation/diagrams/memory-skills-detailed.svg +137 -120
- data/documentation/diagrams/mistakes-negative-feedback.svg +152 -137
- data/documentation/diagrams/network-infra-testing.svg +27 -27
- data/documentation/diagrams/overall-pwn-architecture.svg +97 -97
- data/documentation/diagrams/penetration-testing-workflow.svg +30 -30
- data/documentation/diagrams/persistence-filesystem.svg +100 -94
- data/documentation/diagrams/plugin-ecosystem.svg +35 -35
- data/documentation/diagrams/pwn-ai-feedback-learning-loop.svg +254 -207
- 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 +223 -91
- 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 +14 -8
- data/documentation/pwn_silent_help_learn_demo.gif +0 -0
- data/lib/pwn/ai/agent/extrospection.rb +2561 -56
- data/lib/pwn/ai/agent/tools/extrospection.rb +311 -8
- data/lib/pwn/ffi/adalm_pluto.rb +498 -0
- data/lib/pwn/ffi/fftw.rb +192 -0
- data/lib/pwn/ffi/hack_rf.rb +193 -0
- data/lib/pwn/ffi/liquid.rb +244 -0
- data/lib/pwn/ffi/rtl_sdr.rb +210 -0
- data/lib/pwn/ffi/soapy_sdr.rb +177 -0
- data/lib/pwn/ffi/stdio.rb +9 -1
- data/lib/pwn/ffi/volk.rb +241 -0
- data/lib/pwn/ffi.rb +45 -2
- data/lib/pwn/sdr/decoder/adsb.rb +201 -12
- data/lib/pwn/sdr/decoder/apt.rb +19 -5
- data/lib/pwn/sdr/decoder/base.rb +314 -1
- data/lib/pwn/sdr/decoder/bluetooth.rb +91 -18
- data/lib/pwn/sdr/decoder/dect.rb +81 -23
- data/lib/pwn/sdr/decoder/dsp.rb +229 -15
- data/lib/pwn/sdr/decoder/flex.rb +23 -6
- data/lib/pwn/sdr/decoder/gps.rb +80 -18
- data/lib/pwn/sdr/decoder/gsm.rb +83 -28
- data/lib/pwn/sdr/decoder/iridium.rb +80 -18
- data/lib/pwn/sdr/decoder/lora.rb +84 -28
- data/lib/pwn/sdr/decoder/lte.rb +80 -18
- data/lib/pwn/sdr/decoder/morse.rb +23 -6
- data/lib/pwn/sdr/decoder/p25.rb +90 -31
- data/lib/pwn/sdr/decoder/pager.rb +23 -6
- data/lib/pwn/sdr/decoder/pocsag.rb +23 -6
- data/lib/pwn/sdr/decoder/rds.rb +219 -52
- data/lib/pwn/sdr/decoder/rfid.rb +81 -27
- data/lib/pwn/sdr/decoder/rtl433.rb +85 -27
- data/lib/pwn/sdr/decoder/rtty.rb +23 -6
- data/lib/pwn/sdr/decoder/wifi.rb +86 -32
- data/lib/pwn/sdr/decoder/zigbee.rb +88 -35
- data/lib/pwn/sdr/decoder.rb +6 -5
- data/lib/pwn/sdr/frequency_allocation.rb +124 -81
- data/lib/pwn/sdr/gqrx.rb +1512 -164
- data/lib/pwn/version.rb +1 -1
- data/spec/lib/pwn/ai/agent/extrospection_spec.rb +96 -0
- data/spec/lib/pwn/ai/agent/tools/extrospection_spec.rb +8 -24
- data/spec/lib/pwn/ffi/adalm_pluto_spec.rb +37 -0
- data/spec/lib/pwn/ffi/fftw_spec.rb +26 -0
- data/spec/lib/pwn/ffi/hack_rf_spec.rb +25 -0
- data/spec/lib/pwn/ffi/liquid_spec.rb +42 -0
- data/spec/lib/pwn/ffi/rtl_sdr_spec.rb +24 -0
- data/spec/lib/pwn/ffi/soapy_sdr_spec.rb +25 -0
- data/spec/lib/pwn/ffi/volk_spec.rb +36 -0
- data/spec/lib/pwn/sdr/decoder/base_iq_spec.rb +65 -0
- data/spec/lib/pwn/sdr/decoder/dsp_spec.rb +50 -4
- data/spec/lib/pwn/sdr/decoder/rds_spec.rb +45 -4
- data/third_party/pwn_rdoc.jsonl +232 -18
- metadata +17 -1
|
@@ -1,33 +1,73 @@
|
|
|
1
|
-
# Extrospection — World Awareness
|
|
1
|
+
# Extrospection — World Awareness (on-demand sensing)
|
|
2
2
|
|
|
3
3
|
`PWN::AI::Agent::Extrospection` is the **outward-facing** counterpart to
|
|
4
4
|
[Learning](Skills-Memory-Learning.md). Where Learning/Metrics/Mistakes ask
|
|
5
|
-
*"how well did **I** do?"*, Extrospection asks *"what does the **world**
|
|
6
|
-
|
|
5
|
+
*"how well did **I** do?"*, Extrospection asks *"what does the **outside world**
|
|
6
|
+
say when I need it for a better answer?"*
|
|
7
|
+
|
|
8
|
+
**Primary intent = sense tools on demand**, not ambient inventory of the local host.
|
|
9
|
+
|
|
10
|
+
| You need… | Call… |
|
|
11
|
+
|---|---|
|
|
12
|
+
| Weather / public page content | `extro_watch` / `extro_verify` / TransparentBrowser |
|
|
13
|
+
| Song on 101.1 FM (RDS) | **`extro_rf_tune(freq: "101.1")`** → RDS `now_playing` / `station` |
|
|
14
|
+
| CVE / Exploit-DB hit | `extro_intel` / `extro_verify(kind: :cve)` |
|
|
15
|
+
| Target DOM / TLS drift | `extro_watch(url:)` / `extro_snapshot(sections: [:web])` |
|
|
16
|
+
| Reverse phone / person / FCC ID / patent / IP pivot | **`extro_osint(query:)`** |
|
|
17
|
+
| Serial / USB-UART / AT-modem banner | **`extro_serial`** |
|
|
18
|
+
| SIP / VoIP / BareSIP status or dial | **`extro_telecomm`** |
|
|
19
|
+
| Live capture / pcap summary | **`extro_packet`** |
|
|
20
|
+
| OCR image / barcode-QR | **`extro_vision`** |
|
|
21
|
+
| Text-to-speech / speech-to-text | **`extro_voice`** |
|
|
22
|
+
|
|
23
|
+
**Secondary** — cheap ambient baseline (`snapshot` / `drift` / `correlate`) so the
|
|
24
|
+
agent can distinguish "I called the API wrong" from "the world moved"
|
|
25
|
+
(kernel upgrade, dongle unplugged). That baseline must never launch GUI / JVM /
|
|
26
|
+
heavy REPL binaries.
|
|
7
27
|
|
|
8
28
|

|
|
9
29
|
|
|
10
30
|
## Snapshot sections (`extro_snapshot(sections: […])`)
|
|
11
31
|
|
|
12
|
-
| Section | Probe | Captures |
|
|
13
|
-
|
|
14
|
-
| `:host` | `probe_host` | hostname · uname · distro · arch · CPU · mem |
|
|
15
|
-
| `:net` | `probe_net` | interfaces · listening ports · default route |
|
|
16
|
-
| `:toolchain` | `probe_toolchain` |
|
|
17
|
-
| `:repo` | `probe_repo` | HEAD · branch · dirty · origin |
|
|
18
|
-
| `:env` | `probe_env` | ruby / gem / bundler / PWN version |
|
|
19
|
-
| **`:rf`** | **`probe_rf`** | **RTL-SDR / HackRF presence · SoapySDR
|
|
20
|
-
| **`:web`**
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
32
|
+
| Section | Probe | Captures | Auto? |
|
|
33
|
+
|---|---|---|---|
|
|
34
|
+
| `:host` | `probe_host` | hostname · uname · distro · arch · CPU · mem | ✅ `AUTO_SECTIONS` |
|
|
35
|
+
| `:net` | `probe_net` | interfaces · listening ports · default route | ❌ on-demand |
|
|
36
|
+
| `:toolchain` | `probe_toolchain` | PATH presence; **safe** bins may get `timeout 2 <bin> --version` | ❌ on-demand |
|
|
37
|
+
| `:repo` | `probe_repo` | HEAD · branch · dirty · origin | ✅ `AUTO_SECTIONS` |
|
|
38
|
+
| `:env` | `probe_env` | ruby / gem / bundler / PWN version / AI engine | ✅ `AUTO_SECTIONS` |
|
|
39
|
+
| **`:rf`** | **`probe_rf`** | **RTL-SDR / HackRF presence · SoapySDR · GQRX sock · Flipper · serial · band-plans** | ❌ on-demand |
|
|
40
|
+
| **`:web`** | **`probe_web`** | **Headless render of `web_anchors` (status / title / DOM sha / TLS / screenshot)** | ❌ on-demand |
|
|
41
|
+
| **`:osint`** | **`probe_osint`** | **Public OSINT feed catalogue · keyed flags (Shodan/Hunter) · whois/dig bins** | ❌ on-demand |
|
|
42
|
+
| **`:serial`** | **`probe_serial`** | **`/dev/ttyUSB*` `/dev/ttyACM*` · by-id · minicom/picocom presence** | ❌ on-demand |
|
|
43
|
+
| **`:telecomm`** | **`probe_telecomm`** | **BareSIP HTTP · SIP ports · baresip/asterisk/linphone bins** | ❌ on-demand |
|
|
44
|
+
| **`:packet`** | **`probe_packet`** | **tshark/tcpdump/tcpreplay · ifaces · cap dir** | ❌ on-demand |
|
|
45
|
+
| **`:vision`** | **`probe_vision`** | **tesseract langs · zbarimg · convert/identify** | ❌ on-demand |
|
|
46
|
+
| **`:voice`** | **`probe_voice`** | **espeak-ng · festival · whisper · sox · spd-say** | ❌ on-demand |
|
|
47
|
+
|
|
48
|
+
### `PROBE_BINS` split (why Burp splash used to appear)
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
SAFE_VERSION_BINS = %w[nmap curl git ruby python3 gcc openssl docker] # --version OK
|
|
52
|
+
PRESENCE_ONLY_BINS = %w[burpsuite zaproxy msfconsole gqrx sqlmap] # path only — NEVER spawn
|
|
53
|
+
RF_BINS = %w[rtl_sdr rtl_test rtl_433 hackrf_info gqrx dump1090 multimon-ng SoapySDRUtil]
|
|
54
|
+
OSINT_BINS = %w[whois dig host curl jq]
|
|
55
|
+
SERIAL_BINS = %w[minicom picocom screen cu]
|
|
56
|
+
TELECOMM_BINS = %w[baresip asterisk linphone sngrep]
|
|
57
|
+
PACKET_BINS = %w[tshark tcpdump tcpreplay dumpcap]
|
|
58
|
+
VISION_BINS = %w[tesseract zbarimg qrencode convert identify]
|
|
59
|
+
VOICE_BINS = %w[sox espeak-ng espeak festival whisper spd-say arecord aplay]
|
|
60
|
+
AUTO_SECTIONS = %i[host repo env] # what auto_extrospect actually runs
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`burpsuite` is a Java launcher (`run_java -jar …/burpsuite.jar`). Running it for
|
|
64
|
+
`--version` opens the real GUI → splash screen after every pwn-ai turn when
|
|
65
|
+
`auto_extrospect` was wiring `probe_toolchain` into the default section set.
|
|
66
|
+
**That was the bug.** Presence-only bins + `AUTO_SECTIONS` remove it.
|
|
25
67
|
|
|
26
68
|
`DEFAULT_WEB_ANCHORS` = NVD CVE 2.0 API, Exploit-DB, upstream `pwn/version.rb`.
|
|
27
69
|
Override / extend via `PWN::Env[:ai][:agent][:extrospection][:web][:anchors]`; set
|
|
28
|
-
`allow_targets: true` to also fingerprint `PWN::Env[:targets]`.
|
|
29
|
-
run by `auto_extrospect`** — a headless browser is ~1–3 s cold vs ~50 ms for
|
|
30
|
-
`probe_host`, so it's opt-in (`extro_snapshot(sections: %i[web])`).
|
|
70
|
+
`allow_targets: true` to also fingerprint `PWN::Env[:targets]`.
|
|
31
71
|
|
|
32
72
|
## Verbs
|
|
33
73
|
|
|
@@ -35,15 +75,22 @@ run by `auto_extrospect`** — a headless browser is ~1–3 s cold vs ~50 ms for
|
|
|
35
75
|
|---|---|---|
|
|
36
76
|
| `extro_snapshot` | Fingerprint host/net/toolchain/repo/env/**rf**/*web* → hash | `extrospection.json` (`snapshot` + rotates `previous`) |
|
|
37
77
|
| `extro_drift` | Diff live-vs-stored (or stored-vs-previous) | — returns `{changed, added, removed}` with dotted keys |
|
|
38
|
-
| `extro_observe` | Record a fact — `category:` one of `recon vuln intel target network env` **`rf` `web`** `misc` | `observations[]` |
|
|
78
|
+
| `extro_observe` | Record a fact — `category:` one of `recon vuln intel target network env` **`rf` `web` `osint` `serial` `telecomm` `packet` `vision` `voice`** `misc` | `observations[]` |
|
|
39
79
|
| `extro_observations` | Query recorded facts by source/category/target/tag | — |
|
|
40
80
|
| `extro_intel` | Query NVD / CIRCL / Exploit-DB for keyword or CVE | optional `record: true` → `:intel` observations |
|
|
41
81
|
| **`extro_watch`** | **Render a URL headless, hash the *rendered* DOM, screenshot, diff vs prior** | `observations[]` (`category: :web`) |
|
|
42
82
|
| **`extro_verify`** | **Browser-backed self fact-check of a claim (`:cve` `:version` `:doc` `:generic`) → `:confirmed`/`:refuted`/`:unknown`** | `Mistakes.record` / `observe(:intel)` / `Learning.note_outcome` |
|
|
83
|
+
| **`extro_rf_tune`** | **Tune running GQRX + demod + strength + RDS sample → `now_playing` / `station`** | `observations[]` (`category: :rf`, ttl 300s) |
|
|
84
|
+
| **`extro_osint`** | **Aggregate public OSINT APIs (phone / IP / domain / FCC ID / patent / VIN / MAC / callsign / person / company / SEC / CourtListener / Federal Register / UK Police / OTX / URLHaus / openFDA / NPPES / Nominatim / EPSS / CISA KEV / Microlink / vital records / Shodan / Hunter / AbuseIPDB / VT / HIBP / Wayback)** | `observations[]` (`category: :osint`) |
|
|
85
|
+
| **`extro_serial`** | **Open serial device · optional payload · drain response · disconnect** | `observations[]` (`category: :serial`) |
|
|
86
|
+
| **`extro_telecomm`** | **BareSIP inventory / status / dial / hangup (never launches baresip)** | `observations[]` (`category: :telecomm`) |
|
|
87
|
+
| **`extro_packet`** | **Inventory · bounded live capture · pcap summarise (tshark/PacketFu)** | `observations[]` (`category: :packet`) |
|
|
88
|
+
| **`extro_vision`** | **OCR (tesseract/RTesseract) · barcode/QR (zbarimg)** | `observations[]` (`category: :vision`) |
|
|
89
|
+
| **`extro_voice`** | **TTS (espeak-ng/festival/spd-say) · STT (whisper) · inventory** | `observations[]` (`category: :voice`) |
|
|
43
90
|
| `extro_correlate` | **Join** introspection ↔ extrospection | — actionable findings |
|
|
44
91
|
| `extro_stats` | snapshot age · observation count · drift counts · **rf_devices** · **web_anchors** | — |
|
|
45
92
|
| `extro_reset` | Wipe snapshot + observations (new engagement) | — |
|
|
46
|
-
| `extro_auto_toggle` | Enable/disable
|
|
93
|
+
| `extro_auto_toggle` | Enable/disable ambient baseline (`AUTO_SECTIONS` only) after every final answer | `PWN::Env[:ai][:agent][:auto_extrospect]` |
|
|
47
94
|
|
|
48
95
|
## `extro_correlate` — the point of the whole thing
|
|
49
96
|
|
|
@@ -65,8 +112,7 @@ iterations rediscovering it.
|
|
|
65
112
|
|
|
66
113
|
## `extro_verify` — proactive fact-checking (the browser as a sense organ)
|
|
67
114
|
|
|
68
|
-
`probe_rf`
|
|
69
|
-
it **eyes**. `extro_verify(claim:)` renders a canonical source *with JavaScript
|
|
115
|
+
`probe_rf` is a passive **ear inventory**; `extro_rf_tune` actually **listens** (tune + RDS). `PWN::Plugins::TransparentBrowser` gives Extrospection **eyes**. `extro_verify(claim:)` renders a canonical source *with JavaScript
|
|
70
116
|
executed* and returns a verdict:
|
|
71
117
|
|
|
72
118
|
| `kind:` | Canonical source (rendered headless) | Verdict logic |
|
|
@@ -88,7 +134,261 @@ This adds a **proactive** trigger to the negative-feedback loop: today
|
|
|
88
134
|
the world **before** a human does. `commit: false` returns the verdict without
|
|
89
135
|
side-effects.
|
|
90
136
|
|
|
91
|
-
|
|
137
|
+
## `extro_rf_tune` — the radio as a sense organ
|
|
138
|
+
|
|
139
|
+
`probe_rf` is a **passive inventory** (what radios are attached / is GQRX
|
|
140
|
+
listening?). `extro_rf_tune` is the **active RF sense organ** — the radio
|
|
141
|
+
analogue of `extro_watch` / `extro_verify`. It never launches GQRX (presence-
|
|
142
|
+
only bin); it connects to an already-running remote-control socket, tunes,
|
|
143
|
+
demodulates, measures strength, and — for FM broadcast — samples RDS:
|
|
144
|
+
|
|
145
|
+
```text
|
|
146
|
+
extro_rf_tune(freq: "101.1")
|
|
147
|
+
→ connect GQRX :7356
|
|
148
|
+
→ M WFM_ST 200000 ; F 101100000
|
|
149
|
+
→ sample RDS for settle_secs (default 8s)
|
|
150
|
+
→ { ok, freq, strength_dbfs, station, now_playing, rds:{pi,ps_name,radiotext}, summary }
|
|
151
|
+
→ observe(category: :rf, ttl: 300) # ephemeral — songs change
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
RDS sampling is **`PWN::SDR::Decoder::RDS.sample`** (non-interactive Hash:
|
|
155
|
+
`pi` / `ps_name` / `radiotext` / `station`). The TTY spinner
|
|
156
|
+
(`Decoder::RDS.decode`) stays the human path used by
|
|
157
|
+
`GQRX.init_freq(decoder: :rds)` (default `interactive: true`). Agents and
|
|
158
|
+
cron pass `interactive: false` (or just call `.sample` / `extro_rf_tune`).
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
Frequency parsing is free-form: `"101.1"`, `"101.1 FM"`, `"101.1 MHz"`,
|
|
162
|
+
`"101.100.000"`, `101100000`, `"433.92"` all work. Band plan is matched via
|
|
163
|
+
`PWN::SDR::FrequencyAllocation` (`fm_radio` → `WFM_ST` + RDS decoder; AM → AM;
|
|
164
|
+
etc.). Override with `demodulator_mode:` / `bandwidth:` / `rds:`.
|
|
165
|
+
|
|
166
|
+
Requires GQRX remote control listening and an SDR attached; returns
|
|
167
|
+
`{ok:false, advice:…}` with a concrete recovery hint otherwise. Configure:
|
|
168
|
+
|
|
169
|
+
```ruby
|
|
170
|
+
PWN::Env[:ai][:agent][:extrospection][:rf] = {
|
|
171
|
+
host: '127.0.0.1', port: 7356, settle_secs: 8, ttl: 300
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## `extro_osint` — OSINT sense organ
|
|
176
|
+
|
|
177
|
+
Aggregates as many **public / free** OSINT APIs as practical into one verb.
|
|
178
|
+
Optional keyed feeds (Shodan / Hunter) unlock when `SHODAN_API_KEY` /
|
|
179
|
+
`HUNTER_API_KEY` or `PWN::Env` keys are present. Every feed is best-effort —
|
|
180
|
+
unreachable endpoints return `{error:…}` instead of raising.
|
|
181
|
+
|
|
182
|
+
### Auto-detected kinds
|
|
183
|
+
|
|
184
|
+
| Kind | Trigger | Default feeds |
|
|
185
|
+
|---|---|---|
|
|
186
|
+
| `:ip` | IPv4 / IPv6 | ip · geo · ipapi_is · iplocate · ipwhois · dns · rdap · bgpview · otx · abuseipdb · greynoise · shodan · hackertarget |
|
|
187
|
+
| `:geo` | street-like address / geo query | geo · nominatim · ip |
|
|
188
|
+
| `:domain` / `:dns` / `:whois` / `:rdap` | FQDN | dns · whois · rdap · crtsh · certspotter · wayback · otx · urlhaus · urlscan · shodan · securitytrails · hackertarget |
|
|
189
|
+
| `:url` | `http(s)://…` | urlscan · otx · urlhaus · wayback · microlink · virustotal |
|
|
190
|
+
| `:email` | `a@b.c` | hunter · person · github · haveibeenpwned |
|
|
191
|
+
| `:phone` | E.164 / NANP | phone · person |
|
|
192
|
+
| `:fcc_id` | `2ABIP-ESP32` style | fcc_id |
|
|
193
|
+
| `:patent` | `US10123456` / `patent …` | patent |
|
|
194
|
+
| `:person` | `Jane Doe` | person · username · github · open_sanctions · agify · genderize · nationalize · vital_records |
|
|
195
|
+
| `:username` / `:github` | `@handle` / `gh:` | username · github |
|
|
196
|
+
| `:company` | `… Inc.` / `LLC` / `Ltd` | opencorporates · sec_edgar · federal_register · person · courtlistener |
|
|
197
|
+
| `:cik` | 10-digit CIK | sec_edgar · opencorporates |
|
|
198
|
+
| `:vital_records` | birth/death/marriage keywords | vital_records · person |
|
|
199
|
+
| `:threat` | forced | otx · urlhaus · threatfox · abuseipdb · greynoise · virustotal · epss · cisa_kev |
|
|
200
|
+
| `:openfda` | forced | openfda |
|
|
201
|
+
| `:vin` | 17-char ISO 3779 VIN | nhtsa (NHTSA vPIC / `PWN::Plugins::VIN`) |
|
|
202
|
+
| `:mac` | `00:11:22:33:44:55` / bare hex / Cisco form | mac_vendor |
|
|
203
|
+
| `:callsign` | amateur radio e.g. `W1AW` | callook |
|
|
204
|
+
| `:npi` | `NPI 1679576722` (prefixed) | nppes |
|
|
205
|
+
| `:cve` | `CVE-YYYY-NNNN` | epss · cisa_kev |
|
|
206
|
+
|
|
207
|
+
### Public feed catalogue (no key unless noted)
|
|
208
|
+
|
|
209
|
+
| Feed | Sources | Notes |
|
|
210
|
+
|---|---|---|
|
|
211
|
+
| `:ip` / `:geo` | ip-api.com + `PWN::Plugins::IPInfo` · ipwho.is | ISP/ASN/geo/proxy flags |
|
|
212
|
+
| `:dns` | dig + dns.google DoH | A/AAAA/MX/NS/TXT |
|
|
213
|
+
| `:whois` | system `whois` | first 4 kB |
|
|
214
|
+
| `:rdap` | rdap.org domain/IP bootstrap | JSON |
|
|
215
|
+
| `:crtsh` | crt.sh Certificate Transparency | name + issuer + validity |
|
|
216
|
+
| `:bgpview` | api.bgpview.io | IP/ASN/search |
|
|
217
|
+
| `:shodan` | `PWN::Plugins::Shodan` | **needs** `SHODAN_API_KEY` |
|
|
218
|
+
| `:hunter` | `PWN::Plugins::Hunter` | **needs** `HUNTER_API_KEY` |
|
|
219
|
+
| `:phone` | NANP/E.164 heuristic + reverse-lookup search targets | country, area-code structure, people-search URLs |
|
|
220
|
+
| `:fcc_id` | fccid.io · device.report · fcc.gov OET | grantee/product, MHz excerpts |
|
|
221
|
+
| `:patent` | Google Patents HTML + PatentsView API | title, number, assignee, date |
|
|
222
|
+
| `:person` | Wikipedia · Wikidata · OpenSanctions + NamUs/FBI/Charley targets | missing-person pivot plan |
|
|
223
|
+
| `:username` / `:github` | GitHub · GitLab · Reddit public APIs | profile pivots |
|
|
224
|
+
| `:wayback` | archive.org availability + CDX | snapshots |
|
|
225
|
+
| `:otx` | AlienVault OTX indicators + passive DNS | IP/domain/url |
|
|
226
|
+
| `:urlhaus` | abuse.ch URLHaus host/url API | malware distribution URLs |
|
|
227
|
+
| `:threatfox` | abuse.ch ThreatFox IOC search | malware C2 IOCs |
|
|
228
|
+
| `:urlscan` | urlscan.io public search | recent scans / screenshots |
|
|
229
|
+
| `:hackertarget` | api.hackertarget.com | whois/dns/geoip/headers (rate-limited) |
|
|
230
|
+
| `:openfda` | api.fda.gov device 510(k) · drug label · enforcement | FDA public datasets |
|
|
231
|
+
| `:nominatim` | OpenStreetMap Nominatim | geocode / reverse address |
|
|
232
|
+
| `:opencorporates` | api.opencorporates.com | company search (rate-limited free tier) |
|
|
233
|
+
| `:courtlistener` | CourtListener v4 search / people | RECAP opinions + judges |
|
|
234
|
+
| `:sec_edgar` | sec.gov company_tickers + EFTS | CIK/ticker/filings |
|
|
235
|
+
| `:vital_records` | structured public-record plan | FamilySearch · FindAGrave · CDC W2W · NamUs (live certificates are state-restricted) |
|
|
236
|
+
| `:ipapi_is` | api.ipapi.is | IP company/ASN/hosting/proxy/crawler flags (free) |
|
|
237
|
+
| `:iplocate` | iplocate.io | IP geo + threat (proxy/VPN/hosting) |
|
|
238
|
+
| `:ipwhois` | ipwho.is | Free IP geo / connection / timezone |
|
|
239
|
+
| `:abuseipdb` | api.abuseipdb.com | IP reputation — **needs** `ABUSEIPDB_API_KEY` |
|
|
240
|
+
| `:virustotal` | virustotal.com API v3 | URL/domain/IP analysis — **needs** `VIRUSTOTAL_API_KEY` |
|
|
241
|
+
| `:greynoise` | greynoise.io community / v2 | Internet scanner noise (community free; key upgrades) |
|
|
242
|
+
| `:certspotter` | api.certspotter.com | Certificate Transparency issuances |
|
|
243
|
+
| `:epss` | api.first.org/data/v1/epss | Exploit Prediction Scoring System for a CVE |
|
|
244
|
+
| `:cisa_kev` | CISA Known Exploited Vulnerabilities catalog | KEV membership / ransomware flag |
|
|
245
|
+
| `:nhtsa` | vpic.nhtsa.dot.gov + `PWN::Plugins::VIN` | VIN decode / make-model |
|
|
246
|
+
| `:nppes` | npiregistry.cms.hhs.gov | US healthcare NPI provider lookup |
|
|
247
|
+
| `:federal_register` | federalregister.gov API | US Federal Register document search |
|
|
248
|
+
| `:uk_police` | data.police.uk | UK street-level crime / force catalogue |
|
|
249
|
+
| `:callook` | callook.info | US amateur-radio callsign (FCC ULS) |
|
|
250
|
+
| `:mac_vendor` | maclookup.app · macvendors.com | MAC OUI → vendor |
|
|
251
|
+
| `:universities` | universities.hipolabs.com | University name / domain / country |
|
|
252
|
+
| `:microlink` | api.microlink.io | Link unfurl (OG title/desc/image) |
|
|
253
|
+
| `:agify` / `:genderize` / `:nationalize` | agify.io · genderize.io · nationalize.io | First-name age/gender/nationality estimates |
|
|
254
|
+
| `:haveibeenpwned` | haveibeenpwned.com v3 | Breach membership — **needs** `HIBP_API_KEY` |
|
|
255
|
+
| `:securitytrails` | api.securitytrails.com | Domain DNS history — **needs** `SECURITYTRAILS_API_KEY` |
|
|
256
|
+
|
|
257
|
+
> Feed selection inspired by [public-api-lists/public-api-lists](https://github.com/public-api-lists/public-api-lists) (Anti-Malware, Security, Geocoding, Government, Health, Open Data, Vehicle, Development).
|
|
258
|
+
|
|
259
|
+
### Examples
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
extro_osint(query: "+13125551212")
|
|
263
|
+
→ kind=:phone · feeds.phone = {country_guess, nanp, reverse_lookup_targets}
|
|
264
|
+
|
|
265
|
+
extro_osint(query: "2ABIP-ESP32", kind: :fcc_id)
|
|
266
|
+
→ fccid.io / device.report excerpts + MHz list
|
|
267
|
+
|
|
268
|
+
extro_osint(query: "US10123456", kind: :patent)
|
|
269
|
+
→ google patents titles + patentsview JSON
|
|
270
|
+
|
|
271
|
+
extro_osint(query: "8.8.8.8")
|
|
272
|
+
→ ip-api geo + RDAP + BGPView + OTX pulses
|
|
273
|
+
|
|
274
|
+
extro_osint(query: "Ada Lovelace", kind: :person)
|
|
275
|
+
→ Wikipedia / Wikidata / OpenSanctions + missing-person targets
|
|
276
|
+
|
|
277
|
+
extro_osint(query: "Acme Robotics LLC", kind: :company)
|
|
278
|
+
→ OpenCorporates + SEC EDGAR tickers + CourtListener
|
|
279
|
+
|
|
280
|
+
extro_osint(query: "birth record Jane Doe", kind: :vital_records)
|
|
281
|
+
→ public genealogy + state vital-records index (no closed B2B scrape)
|
|
282
|
+
|
|
283
|
+
extro_osint(query: "1HGCM82633A004352")
|
|
284
|
+
→ kind=:vin · NHTSA vPIC decode (make/model/year/plant)
|
|
285
|
+
|
|
286
|
+
extro_osint(query: "00:11:22:33:44:55")
|
|
287
|
+
→ kind=:mac · OUI vendor (maclookup / macvendors)
|
|
288
|
+
|
|
289
|
+
extro_osint(query: "W1AW")
|
|
290
|
+
→ kind=:callsign · Callook FCC ULS (trustee, class, grid)
|
|
291
|
+
|
|
292
|
+
extro_osint(query: "CVE-2021-44228")
|
|
293
|
+
→ kind=:cve · FIRST EPSS score + CISA KEV membership
|
|
294
|
+
|
|
295
|
+
extro_osint(query: "8.8.8.8", feeds: ["ipapi_is", "iplocate", "greynoise", "abuseipdb"])
|
|
296
|
+
→ multi-source IP threat/geo (keyed feeds skip cleanly when no key)
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Configure:
|
|
300
|
+
|
|
301
|
+
```ruby
|
|
302
|
+
PWN::Env[:ai][:agent][:extrospection][:osint] = {
|
|
303
|
+
ttl: 86_400,
|
|
304
|
+
api_keys: {
|
|
305
|
+
shodan: '…',
|
|
306
|
+
hunter: '…',
|
|
307
|
+
abuseipdb: '…',
|
|
308
|
+
virustotal: '…',
|
|
309
|
+
greynoise: '…',
|
|
310
|
+
haveibeenpwned: '…',
|
|
311
|
+
securitytrails: '…'
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
# ENV fallbacks also accepted:
|
|
315
|
+
# SHODAN_API_KEY, HUNTER_API_KEY, ABUSEIPDB_API_KEY, VIRUSTOTAL_API_KEY,
|
|
316
|
+
# GREYNOISE_API_KEY, HIBP_API_KEY, SECURITYTRAILS_API_KEY
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
## `extro_serial` — Serial sense organ
|
|
321
|
+
|
|
322
|
+
Passive inventory via `snapshot(sections: [:serial])` (`/dev/ttyUSB*`,
|
|
323
|
+
`/dev/ttyACM*`, `/dev/serial/by-id/*`). The active verb opens a device through
|
|
324
|
+
`PWN::Plugins::Serial`, optionally writes a payload (AT command or bytes),
|
|
325
|
+
drains the response for `settle_secs`, and **always disconnects** so other
|
|
326
|
+
tools can reclaim the bus:
|
|
327
|
+
|
|
328
|
+
```text
|
|
329
|
+
extro_serial(block_dev: "/dev/ttyUSB0", baud: 115200, payload: "ATI\r")
|
|
330
|
+
→ { ok, text, hex, line_state, modem_params, bytes }
|
|
331
|
+
→ observe(category: :serial)
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## `extro_telecomm` — SIP / VoIP / PSTN sense organ
|
|
335
|
+
|
|
336
|
+
Telecomm analogue of `extro_rf_tune`. Talks to a **running** BareSIP HTTP
|
|
337
|
+
control socket (never launches it). Actions:
|
|
338
|
+
|
|
339
|
+
| action | Effect |
|
|
340
|
+
|---|---|
|
|
341
|
+
| `:inventory` / `:status` | bins · SIP listen ports · BareSIP HTTP reachability · status text |
|
|
342
|
+
| `:dial` | require `target:` SIP URI or E.164 — **OPSEC: real call** |
|
|
343
|
+
| `:hangup` | hang up active call |
|
|
344
|
+
|
|
345
|
+
```ruby
|
|
346
|
+
PWN::Env[:ai][:agent][:extrospection][:telecomm] = {
|
|
347
|
+
host: '127.0.0.1', port: 8000, ttl: 600
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## `extro_packet` — Packet sense organ
|
|
352
|
+
|
|
353
|
+
Bounded L2/L3 sensing via `tshark` / `tcpdump` + pcap summarisation through
|
|
354
|
+
`PWN::Plugins::Packet` / tshark hierarchy & conversations:
|
|
355
|
+
|
|
356
|
+
| action | Effect |
|
|
357
|
+
|---|---|
|
|
358
|
+
| `:inventory` | ifaces + PACKET_BINS presence |
|
|
359
|
+
| `:capture` | short capture → `~/.pwn/extrospection/packet/*.pcap` + summary |
|
|
360
|
+
| `:summarize_pcap` | parse `path:` pcap (protocol hierarchy, IP conversations) |
|
|
361
|
+
|
|
362
|
+
Capture is hard-capped (`count` ≤ 200, `timeout` ≤ 60s) so the agent never
|
|
363
|
+
hangs mid-turn.
|
|
364
|
+
|
|
365
|
+
## `extro_vision` — Vision / OCR sense organ
|
|
366
|
+
|
|
367
|
+
Eyes on the host:
|
|
368
|
+
|
|
369
|
+
| action | Backend |
|
|
370
|
+
|---|---|
|
|
371
|
+
| `:ocr` | `PWN::Plugins::OCR` (RTesseract) → `tesseract` CLI fallback |
|
|
372
|
+
| `:barcode` | `zbarimg` for barcodes / QR |
|
|
373
|
+
| `:inventory` | tesseract langs + vision bins |
|
|
374
|
+
|
|
375
|
+
```text
|
|
376
|
+
extro_vision(file: "/tmp/shot.png", action: :ocr)
|
|
377
|
+
→ { text, chars, preview } → observe(category: :vision)
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## `extro_voice` — Voice (TTS / STT) sense organ
|
|
381
|
+
|
|
382
|
+
| action | Backend |
|
|
383
|
+
|---|---|
|
|
384
|
+
| `:tts` | espeak-ng → spd-say → festival (`PWN::Plugins::Voice`) |
|
|
385
|
+
| `:stt` | OpenAI whisper binary / `PWN::Plugins::Voice.speech_to_text` |
|
|
386
|
+
| `:inventory` | VOICE_BINS presence |
|
|
387
|
+
|
|
388
|
+
Artefacts land under `~/.pwn/extrospection/voice/`.
|
|
389
|
+
|
|
390
|
+
## `revalidate_memory` — the browser as GC for `PWN::Memory`
|
|
391
|
+
|
|
92
392
|
|
|
93
393
|
`learning_consolidate` only dedupes/truncates; it never asks *"is this still
|
|
94
394
|
true?"*. `PWN::AI::Agent::Extrospection.revalidate_memory` walks every
|
|
@@ -101,7 +401,7 @@ cron_create(name: 'memory_revalidate', schedule: '0 4 * * 0',
|
|
|
101
401
|
ruby: 'PWN::AI::Agent::Extrospection.revalidate_memory')
|
|
102
402
|
```
|
|
103
403
|
|
|
104
|
-
|
|
404
|
+
## Configuration
|
|
105
405
|
|
|
106
406
|
```ruby
|
|
107
407
|
PWN::Env[:ai][:agent][:extrospection][:web] = {
|
|
@@ -119,12 +419,19 @@ PWN::Env[:ai][:agent][:extrospection][:web] = {
|
|
|
119
419
|
|
|
120
420
|
```ruby
|
|
121
421
|
extro_reset(confirm: true) # clean slate for new scope
|
|
122
|
-
extro_snapshot # baseline (
|
|
422
|
+
extro_snapshot # baseline (host/net/toolchain/repo/env/rf; add sections:%i[web] for anchors)
|
|
123
423
|
# … recon …
|
|
124
424
|
extro_observe(source: 'nmap', target: '10.0.0.5',
|
|
125
425
|
category: 'recon', data: 'OpenSSH 8.2p1 Ubuntu')
|
|
126
426
|
extro_observe(source: 'gqrx', target: '433.920MHz',
|
|
127
427
|
category: 'rf', data: 'peak -34.2 dBFS bw=200k FSK — likely garage remote')
|
|
428
|
+
extro_rf_tune(freq: '101.1') # live RDS → now_playing / station (category: :rf)
|
|
429
|
+
extro_osint(query: '10.0.0.5', kind: :ip)
|
|
430
|
+
extro_osint(query: '2ABIP-ESP32', kind: :fcc_id)
|
|
431
|
+
extro_serial(payload: "ATI\r")
|
|
432
|
+
extro_packet(action: :capture, filter: 'tcp port 22', count: 20)
|
|
433
|
+
extro_vision(file: '/tmp/badge.png', action: :ocr)
|
|
434
|
+
extro_voice(action: :tts, text: 'recon complete')
|
|
128
435
|
extro_intel(query: 'OpenSSH 8.2p1', record: true)
|
|
129
436
|
extro_watch(url: 'https://target.acme/api/version') # DOM-hash + screenshot; changed:true on next run
|
|
130
437
|
extro_verify(claim: 'CVE-2026-12345 affects OpenSSL 3.2.1') # → Mistakes/Memory/observe on verdict
|
|
@@ -133,6 +440,145 @@ extro_drift # what moved?
|
|
|
133
440
|
extro_correlate # why did it break?
|
|
134
441
|
```
|
|
135
442
|
|
|
443
|
+
## Example questions that trigger Extrospection
|
|
444
|
+
|
|
445
|
+
Natural-language prompts that should fire **outward** sensing (grouped by sense organ).
|
|
446
|
+
Location-specific details use **Chicago** as the canonical city so the catalog stays
|
|
447
|
+
portable across deployments.
|
|
448
|
+
|
|
449
|
+
### RF sense organ (`extro_rf_tune` + RF observations)
|
|
450
|
+
|
|
451
|
+
- “What’s playing on 101.1 right now?”
|
|
452
|
+
- “What’s on Q101 / 101.1 FM in Chicago?”
|
|
453
|
+
- “Is NOAA weather radio for the Chicago area broadcasting an alert?”
|
|
454
|
+
- “Tune 433.92 MHz and report signal strength.”
|
|
455
|
+
- “Any ADS-B traffic near Chicago O’Hare (ORD) right now?”
|
|
456
|
+
- “Sample RDS on 93.1 for 15 seconds — station name and radiotext?”
|
|
457
|
+
- “Is the local Chicago 2 m repeater on 146.x active?”
|
|
458
|
+
|
|
459
|
+
### Web sense organ (`extro_watch`, `extro_verify`, `snapshot(sections: [:web])`)
|
|
460
|
+
|
|
461
|
+
- “Did the vendor status page change since last check?”
|
|
462
|
+
- “Watch https://status.example.com for DOM changes.”
|
|
463
|
+
- “Has the bug-bounty scope page been updated?”
|
|
464
|
+
- “What’s the weather in Chicago today?” *(live external page)*
|
|
465
|
+
- “Fingerprint that login portal’s generator / title / tech stack.”
|
|
466
|
+
- “Screenshot + hash https://target/app/version for drift tracking.”
|
|
467
|
+
|
|
468
|
+
### OSINT sense organ (`extro_osint`)
|
|
469
|
+
|
|
470
|
+
- “Reverse lookup +1 312 555 1212.”
|
|
471
|
+
- “Who is the registrant for example.com?”
|
|
472
|
+
- “What device is FCC ID 2ABIP-ESP32?”
|
|
473
|
+
- “Find patents related to software-defined radio receivers.”
|
|
474
|
+
- “Pivot on username @octocat across GitHub/GitLab/Reddit.”
|
|
475
|
+
- “Is Jane Doe listed on OpenSanctions / Wikipedia?”
|
|
476
|
+
- “CT certs for target.acme via crt.sh.”
|
|
477
|
+
- “ASN / BGP neighbours for 1.1.1.1.”
|
|
478
|
+
- “Any Wayback snapshots of https://target.acme/login?”
|
|
479
|
+
|
|
480
|
+
### Serial sense organ (`extro_serial`)
|
|
481
|
+
|
|
482
|
+
- “What USB serial devices are attached?”
|
|
483
|
+
- “Send ATI to the modem on /dev/ttyUSB0 and show the banner.”
|
|
484
|
+
- “Talk to the Flipper / RFID reader on ttyACM and dump response hex.”
|
|
485
|
+
- “Probe the Arduino console at 115200 8N1.”
|
|
486
|
+
|
|
487
|
+
### Telecomm sense organ (`extro_telecomm`)
|
|
488
|
+
|
|
489
|
+
- “Is BareSIP running and what is its status?”
|
|
490
|
+
- “List SIP ports listening on this host.”
|
|
491
|
+
- “Dial sip:echo@example.com via BareSIP.” *(OPSEC: real call)*
|
|
492
|
+
- “Hang up the active VoIP call.”
|
|
493
|
+
|
|
494
|
+
### Packet sense organ (`extro_packet`)
|
|
495
|
+
|
|
496
|
+
- “Inventory capture-capable interfaces and tshark/tcpdump.”
|
|
497
|
+
- “Capture 20 packets on eth0 for tcp/443 and summarise.”
|
|
498
|
+
- “Summarise this pcap: /tmp/eng.pcap.”
|
|
499
|
+
- “What IP conversations dominate that capture?”
|
|
500
|
+
|
|
501
|
+
### Vision / OCR sense organ (`extro_vision`)
|
|
502
|
+
|
|
503
|
+
- “OCR this screenshot of the login page.”
|
|
504
|
+
- “Decode the QR code on /tmp/badge.png.”
|
|
505
|
+
- “What languages does tesseract have installed?”
|
|
506
|
+
|
|
507
|
+
### Voice sense organ (`extro_voice`)
|
|
508
|
+
|
|
509
|
+
- “Speak ‘engagement complete’ via TTS.”
|
|
510
|
+
- “Transcribe /tmp/voicemail.wav.”
|
|
511
|
+
- “What TTS/STT engines are available on this host?”
|
|
512
|
+
|
|
513
|
+
### Fact-check / claim verification (`extro_verify`)
|
|
514
|
+
|
|
515
|
+
- “Is CVE-2024-3094 still rated Critical on NVD?”
|
|
516
|
+
- “Confirm the latest `pwn` gem on RubyGems is 0.5.x.”
|
|
517
|
+
- “Is it true that OpenSSH 9.8p1 is the current stable?”
|
|
518
|
+
- “Verify this claim from the advisory against the official page.”
|
|
519
|
+
- “Does that docs page actually say what we quoted?”
|
|
520
|
+
|
|
521
|
+
### Threat intel (`extro_intel` ± `record:true`)
|
|
522
|
+
|
|
523
|
+
- “Any known exploits for Apache 2.4.58?”
|
|
524
|
+
- “Look up CVE-2025-XXXX across NVD / CIRCL / Exploit-DB.”
|
|
525
|
+
- “What CVEs hit `libssl` in the last year?”
|
|
526
|
+
- “Is there a public PoC for that JetBrains CVE?”
|
|
527
|
+
- “Correlate installed nmap version against known CVEs.”
|
|
528
|
+
|
|
529
|
+
### Host / env / toolchain drift (`extro_snapshot`, `extro_drift`, `extro_stats`)
|
|
530
|
+
|
|
531
|
+
- “Did the environment change under us since last session?”
|
|
532
|
+
- “Take a full extrospection snapshot and show drift.”
|
|
533
|
+
- “Is nmap / gqrx / SoapySDR still the version we expect?”
|
|
534
|
+
- “What’s listening on this host right now?”
|
|
535
|
+
- “Show toolchain + repo HEAD fingerprint.”
|
|
536
|
+
- “Why did that tool start failing — world drift or operator error?” → pairs with `extro_correlate`
|
|
537
|
+
|
|
538
|
+
### Recon memory / observations (`extro_observe`, `extro_observations`)
|
|
539
|
+
|
|
540
|
+
- “Remember that target X bannered as nginx/1.25.3 on 443.”
|
|
541
|
+
- “What recon findings do we have for 10.0.0.5?”
|
|
542
|
+
- “List RF observations from today.”
|
|
543
|
+
- “Any :web watches that changed this week?”
|
|
544
|
+
- “Show intel hits we recorded against this product.”
|
|
545
|
+
|
|
546
|
+
### Correlation / “am I wrong or did the world move?” (`extro_correlate`)
|
|
547
|
+
|
|
548
|
+
- “Cross-check recent tool failures against host/toolchain drift.”
|
|
549
|
+
- “Did any of our recorded CVEs match installed package versions?”
|
|
550
|
+
- “Is that failed shell call explained by missing binaries?”
|
|
551
|
+
- “Any refuted claims that should invalidate old memory facts?”
|
|
552
|
+
|
|
553
|
+
### Operational / lifecycle
|
|
554
|
+
|
|
555
|
+
- “Enable ambient auto-extrospect after every answer.”
|
|
556
|
+
- “Reset extrospection for a new engagement.” *(destructive)*
|
|
557
|
+
- “How stale is the current world snapshot?”
|
|
558
|
+
- “Toggle auto-extrospect off while we fuzz.”
|
|
559
|
+
|
|
560
|
+
### Short “trigger” patterns the agent should recognize
|
|
561
|
+
|
|
562
|
+
| Pattern | Likely tools |
|
|
563
|
+
|--------|----------------|
|
|
564
|
+
| “What’s on … MHz / FM / station” | `extro_rf_tune` |
|
|
565
|
+
| “Reverse phone / FCC ID / patent / whois / person” | `extro_osint` |
|
|
566
|
+
| “Serial / AT modem / ttyUSB / Flipper console” | `extro_serial` |
|
|
567
|
+
| “SIP / VoIP / BareSIP / dial” | `extro_telecomm` |
|
|
568
|
+
| “Capture packets / summarise pcap” | `extro_packet` |
|
|
569
|
+
| “OCR / barcode / QR this image” | `extro_vision` |
|
|
570
|
+
| “Speak this / transcribe that audio” | `extro_voice` |
|
|
571
|
+
| “Did … page change / watch URL” | `extro_watch` |
|
|
572
|
+
| “Is it true that… / confirm CVE / latest version” | `extro_verify` |
|
|
573
|
+
| “Known vulns / CVE / exploit for…” | `extro_intel` |
|
|
574
|
+
| “What changed on this host / drift” | `extro_snapshot` + `extro_drift` |
|
|
575
|
+
| “Remember this finding about…” | `extro_observe` |
|
|
576
|
+
| “Why did X start failing?” | `extro_correlate` + metrics/mistakes |
|
|
577
|
+
| “Weather in Chicago / public page content” | `extro_watch` / TransparentBrowser |
|
|
578
|
+
|
|
579
|
+
The **inward** half of the loop (Memory · Skills · Learning · Mistakes · Metrics)
|
|
580
|
+
has a matching example catalog in [Skills, Memory & Learning](Skills-Memory-Learning.md#example-questions-that-trigger-introspection).
|
|
581
|
+
|
|
136
582
|
**See also:** [Skills, Memory & Learning](Skills-Memory-Learning.md) ·
|
|
137
583
|
[Mistakes](Mistakes.md) · [SDR](SDR.md) · [Transparent Browser](Transparent-Browser.md) · [Cron](Cron.md) · [pwn-ai Agent](pwn-ai-Agent.md)
|
|
138
584
|
|
data/documentation/FFI.md
CHANGED
|
@@ -1,14 +1,78 @@
|
|
|
1
|
-
# `PWN::FFI` — Native Calls
|
|
1
|
+
# `PWN::FFI` — Native Calls for DSP & RF
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Thin `ffi`-gem bindings to **already-installed** system shared objects. Nothing
|
|
4
|
+
is compiled at `gem install` time, nothing shells out. If a `.so` is missing the
|
|
5
|
+
module still loads and `.available?` returns `false` so callers fall back to
|
|
6
|
+
pure Ruby.
|
|
6
7
|
|
|
7
8
|
```ruby
|
|
8
|
-
PWN::FFI
|
|
9
|
+
PWN::FFI.backends
|
|
10
|
+
# => {FFTW: true, HackRF: true, Liquid: true, RTLSdr: true, SoapySDR: true, Volk: true}
|
|
11
|
+
|
|
12
|
+
PWN::FFI.available?(mod: :Volk) # => true/false
|
|
9
13
|
```
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
## Modules (`lib/pwn/ffi/*.rb`)
|
|
16
|
+
|
|
17
|
+
| Module | Shared object | Role |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| **`Volk`** | `libvolk` | SIMD kernels: s16→f32 convert, accumulate, \|z\|², scale, dot-product. Backs `Decoder::DSP.unpack_s16le` / `rms_dbfs`. |
|
|
20
|
+
| **`Liquid`** | `libliquid` | liquid-dsp: `freqdem` (FM demod), `msresamp_rrrf` (arbitrary resample), Kaiser FIR, DC blocker. Backs `Decoder::DSP.resample` / `dc_block`. |
|
|
21
|
+
| **`FFTW`** | `libfftw3f` | Single-precision FFTW3: real & complex 1-D FFTs, magnitude / power-dB helpers for spectrum work. |
|
|
22
|
+
| **`HackRF`** | `libhackrf` | Control plane (init/open/tune/rate/gains) + device info for Extrospection `probe_rf` and wideband I/Q capture. |
|
|
23
|
+
| **`RTLSdr`** | `librtlsdr` | Device list, tune, gain, blocking `read_sync` of raw u8 I/Q. |
|
|
24
|
+
| **`SoapySDR`** | `libSoapySDR` | Enumerate every Soapy-backed front-end (RTL-SDR, HackRF, Airspy, Pluto, UHD, …); API/ABI/lib version. |
|
|
25
|
+
| `Stdio` | `libc` | Classic `puts` / `printf` / `scanf` for shellcode / format-string research. |
|
|
26
|
+
|
|
27
|
+
## Design rules
|
|
28
|
+
|
|
29
|
+
1. **Thin & optional.** Attach a minimal surface; prefer high-level Ruby wrappers
|
|
30
|
+
(`Liquid.freq_demod`, `Volk.unpack_s16le`) over raw C pointers in call sites.
|
|
31
|
+
2. **No install-time compile.** Use the system package (`libvolk-dev`,
|
|
32
|
+
`libliquid-dev`, `libfftw3-dev`, `libhackrf-dev`, …). On hosts without them
|
|
33
|
+
every `.available?` is `false` and pure-Ruby paths keep working.
|
|
34
|
+
3. **Namespace hygiene.** `PubFFI = ::FFI` (defined once in `lib/pwn/ffi.rb`)
|
|
35
|
+
avoids the `PWN::FFI` ↔ `::FFI` collision when modules `extend PubFFI::Library`.
|
|
36
|
+
4. **Fallbacks in DSP.** `PWN::SDR::Decoder::DSP` probes `PWN::FFI.available?`
|
|
37
|
+
and rescues into pure Ruby. Toggle globally with
|
|
38
|
+
`PWN::SDR::Decoder::DSP.native = false`.
|
|
39
|
+
|
|
40
|
+
## REPL examples
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
# SIMD-unpack GQRX audio
|
|
44
|
+
raw = udp_chunk # s16le bytes
|
|
45
|
+
samples = PWN::FFI::Volk.unpack_s16le(data: raw)
|
|
46
|
+
|
|
47
|
+
# FM demod of complex baseband
|
|
48
|
+
audio = PWN::FFI::Liquid.freq_demod(iq: interleaved_iq, kf: 0.5)
|
|
49
|
+
|
|
50
|
+
# Real FFT power spectrum
|
|
51
|
+
db = PWN::FFI::FFTW.rfft_power_db(samples: audio, n: 4096)
|
|
52
|
+
|
|
53
|
+
# RF inventory
|
|
54
|
+
PWN::FFI::SoapySDR.list_devices
|
|
55
|
+
PWN::FFI::HackRF.info
|
|
56
|
+
PWN::FFI::RTLSdr.list_devices
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## How this accelerates `PWN::SDR::Decoder::*`
|
|
60
|
+
|
|
61
|
+
Audio-rate protocols (POCSAG, FLEX, Morse, RTTY, APT, …) stay on the GQRX
|
|
62
|
+
48 kHz UDP tap and now automatically pick up VOLK/liquid for unpack + resample
|
|
63
|
+
hot loops.
|
|
64
|
+
|
|
65
|
+
Wideband protocols (ADS-B, GSM, LTE, LoRa, WiFi, …) still characterise bursts
|
|
66
|
+
from the audio tap via `Base.run_detector`, but can graduate to true
|
|
67
|
+
demodulation by:
|
|
68
|
+
|
|
69
|
+
1. Opening a front-end via `PWN::FFI::RTLSdr` / `HackRF` / `SoapySDR`
|
|
70
|
+
2. Reading raw I/Q
|
|
71
|
+
3. Running native DSP (`Liquid.freq_demod`, `FFTW.rfft`, VOLK magnitude)
|
|
72
|
+
4. Emitting the same Hash frames decoders already JSONL-log
|
|
73
|
+
|
|
74
|
+
No decoder shells out; Ruby remains the orchestrator.
|
|
75
|
+
|
|
76
|
+
**See also:** [SDR](SDR.md) · [Hardware](Hardware.md)
|
|
13
77
|
|
|
14
|
-
[← Home](Home.md)
|
|
78
|
+
[← Home](Home.md)
|