mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-10-28 12:01:13 -04:00
Sync + WIFICANARY: attribute synced detections to their node
Fixes found running WIFICANARY on a WiFi satellite node that pushes its
detections to a hub with no WiFi of its own.
Synced plugin objects were stored with syncHubNodeName = "decoded"
instead of the node's name. plugin.py took filename.split(".")[2], but by
the time the hub processes the file decode_and_rename_files() has renamed
it to last_result.<PREFIX>.decoded.<NodeName>.<N>.log, so index 2 is the
literal marker. The parsing now lives in
utils.plugin_utils.get_sync_hub_node_name(), next to the function that
produces these names; it keeps node names that contain dots and returns
"" for local result files.
WIFICANARY's absent_baseline_clone was evaluated per trusted_aps entry,
so with a main AP + range extender pair, a weak clone seen while only the
main AP was in range also raised absent_baseline_clone through the
extender's entry, on top of the correct evil_twin. The baseline now
counts as present if any trusted radio for that SSID is visible;
single-entry behaviour is unchanged.
Leaving WIFICANARY_IFACE blank is how such a hub ingests the node's
detections (core processes the synced files after the plugin runs), but
it logged an unconditional "not set - nothing to scan" every cycle. It is
now a verbose "hub-only mode" message, and the node + hub setup is
documented in the setting description and the plugin README.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PzCQWQVz9b2UzqLiGp2mPM
This commit is contained in:
1 parent
32e2ddd322
commit
ca4e92c32d
7 files changed
+113
-8
No files matched your search
@@ -15,6 +15,7 @@ Runs a periodic passive WiFi scan (`iw scan`, no monitor mode) and flags rogue A
|
||||
- Enable the plugin (`WIFICANARY_RUN` → `schedule`) and set a schedule in `WIFICANARY_RUN_SCHD`.
|
||||
- A detection creates a new, dangerous-by-default `Devices` entry for the rogue BSSID (even though it never associated with your network) - turn off `WIFICANARY_IMPORT_ON` if you'd rather tune your trusted-AP list against the plugin's history first, without devices being created yet.
|
||||
- Pwnagotchi and WiFi Pineapple signature checks run unconditionally, regardless of `WIFICANARY_trusted_aps`.
|
||||
- No WiFi on your main NetAlertX host? Run this plugin on a small WiFi-capable node (e.g. a Raspberry Pi) and push its findings with the [Sync Hub](../sync/README.md) plugin (`SYNC_plugins` = `WIFICANARY`). On the hub, load `WIFICANARY` too with `WIFICANARY_RUN` → `schedule` and `WIFICANARY_IFACE` left **blank**: it skips the local scan (hub-only mode) but its run is what makes core ingest the detections synced from the node, tagged with the node's name.
|
||||
- If a detected rogue BSSID turns out to already be a device NetAlertX knows from another source (ARP, DHCP, an importer...), the finding is escalated in place - the reason is rewritten to name the known device, and the motor gets a `_known_device` suffix (e.g. `evil_twin_known_device`) so a [Workflow](https://docs.netalertx.com/WORKFLOWS) rule can route it to a more urgent channel than a stranger's radio.
|
||||
|
||||
### Notes
|
||||
|
||||
@@ -611,7 +611,7 @@
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "The WiFi interface to scan with, e.g. <code>wlan0</code>. Station mode is enough - no monitor mode needed. Required."
|
||||
"string": "The WiFi interface to scan with, e.g. <code>wlan0</code>. Station mode is enough - no monitor mode needed. Leave blank on a sync hub without WiFi to only process detections synced from nodes."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -58,7 +58,10 @@ def main():
|
||||
|
||||
iface = get_setting_value('WIFICANARY_IFACE')
|
||||
if not iface:
|
||||
mylog('none', [f'[{pluginName}] WIFICANARY_IFACE is not set - nothing to scan'])
|
||||
# Hub-only mode (e.g. a sync hub with no WiFi hardware): no local scan,
|
||||
# but the run itself still matters - core processes the results synced
|
||||
# from WIFICANARY nodes after this script exits.
|
||||
mylog('verbose', [f'[{pluginName}] WIFICANARY_IFACE not set - hub-only mode, skipping local scan'])
|
||||
plugin_objects.write_result_file()
|
||||
return 0
|
||||
|
||||
@@ -263,8 +266,13 @@ def check_trusted_aps(aps, trusted_aps):
|
||||
|
||||
for trust in trusted_aps:
|
||||
matches = [ap for ap in aps if ap['ssid'] == trust['ssid']]
|
||||
other_trusted_bssids = trusted_bssids_by_ssid.get(trust['ssid'], set()) - {trust['bssid']}
|
||||
baseline_bssid_seen = any(ap['bssid'] == trust['bssid'] for ap in matches) if trust['bssid'] else True
|
||||
ssid_trusted_bssids = trusted_bssids_by_ssid.get(trust['ssid'], set())
|
||||
other_trusted_bssids = ssid_trusted_bssids - {trust['bssid']}
|
||||
# The baseline counts as present if ANY trusted radio for this SSID
|
||||
# is visible, not just this entry's own: with a main AP + extender
|
||||
# pair, an out-of-range extender while the main AP is up isn't an
|
||||
# "absent baseline" - the clone is a plain evil twin.
|
||||
baseline_bssid_seen = any(ap['bssid'] in ssid_trusted_bssids for ap in matches) if trust['bssid'] else True
|
||||
accepted = trust['security_set']
|
||||
expected_desc = ' or '.join(sorted(accepted))
|
||||
|
||||
|
||||
Reference in new issue
Block a user