Add Phase 1 utility modules: crypto, networking, logging, stealth, resource, permissions, config_loader, bettercap_api
9 files in utils/ providing the shared infrastructure layer: - crypto: AES-256-GCM file encryption, argon2id/PBKDF2 key derivation, HKDF network unlock, LUKS container management - networking: interface detection, MAC/IP helpers, BPF compilation via libpcap ctypes, gratuitous ARP, VLAN creation - logging: encrypted log writer (BBLogger) with rotation, per-module files, stdout suppression for stealth - stealth: process rename via prctl, cmdline spoofing, sysctl helpers, timestomping, core dump disable - resource: hardware tier detection (OPi Zero 3 / Pi Zero / generic) via /proc/device-tree and cpuinfo, resource monitoring - permissions: root/capability checks via capget ctypes, privilege dropping, directory permission enforcement - config_loader: YAML merge hierarchy (hardware_tiers -> bigbrother -> modules -> stealth -> CLI), tier auto-detection, SIGHUP reload - bettercap_api: REST client with per-session random credentials, session/events/command methods
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env python3
|
||||
"""REST client for bettercap API."""
|
||||
|
||||
import secrets
|
||||
import string
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
import requests
|
||||
from requests.auth import HTTPBasicAuth
|
||||
|
||||
|
||||
class BettercapAPI:
|
||||
def __init__(
|
||||
self,
|
||||
host: str = "127.0.0.1",
|
||||
port: int = 8083,
|
||||
user: str = "bb",
|
||||
password: Optional[str] = None,
|
||||
timeout: int = 10,
|
||||
):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.user = user
|
||||
self.password = password or self._generate_password()
|
||||
self.timeout = timeout
|
||||
self._base_url = f"http://{host}:{port}/api"
|
||||
self._auth = HTTPBasicAuth(self.user, self.password)
|
||||
self._session = requests.Session()
|
||||
self._session.auth = self._auth
|
||||
self._session.headers.update({"Content-Type": "application/json"})
|
||||
|
||||
@staticmethod
|
||||
def _generate_password(length: int = 32) -> str:
|
||||
alphabet = string.ascii_letters + string.digits
|
||||
return "".join(secrets.choice(alphabet) for _ in range(length))
|
||||
|
||||
def _request(self, method: str, endpoint: str, **kwargs) -> requests.Response:
|
||||
url = f"{self._base_url}/{endpoint.lstrip('/')}"
|
||||
kwargs.setdefault("timeout", self.timeout)
|
||||
try:
|
||||
resp = self._session.request(method, url, **kwargs)
|
||||
resp.raise_for_status()
|
||||
return resp
|
||||
except requests.exceptions.ConnectionError:
|
||||
raise ConnectionError(f"Cannot connect to bettercap at {self.host}:{self.port}")
|
||||
except requests.exceptions.Timeout:
|
||||
raise TimeoutError(f"Request to bettercap timed out after {self.timeout}s")
|
||||
|
||||
def run(self, command: str) -> Dict[str, Any]:
|
||||
resp = self._request("POST", "session", json={"cmd": command})
|
||||
return resp.json()
|
||||
|
||||
def get_session(self) -> Dict[str, Any]:
|
||||
resp = self._request("GET", "session")
|
||||
return resp.json()
|
||||
|
||||
def get_events(self, since: Optional[int] = None) -> List[Dict[str, Any]]:
|
||||
params = {}
|
||||
if since is not None:
|
||||
params["n"] = since
|
||||
resp = self._request("GET", "events", params=params)
|
||||
return resp.json()
|
||||
|
||||
def is_alive(self) -> bool:
|
||||
try:
|
||||
self.get_session()
|
||||
return True
|
||||
except (ConnectionError, TimeoutError, requests.exceptions.RequestException):
|
||||
return False
|
||||
|
||||
def start_module(self, module: str) -> Dict[str, Any]:
|
||||
return self.run(f"{module} on")
|
||||
|
||||
def stop_module(self, module: str) -> Dict[str, Any]:
|
||||
return self.run(f"{module} off")
|
||||
|
||||
def set_parameter(self, param: str, value: str) -> Dict[str, Any]:
|
||||
return self.run(f"set {param} {value}")
|
||||
|
||||
def get_hosts(self) -> List[Dict[str, Any]]:
|
||||
session = self.get_session()
|
||||
return session.get("lan", {}).get("hosts", [])
|
||||
|
||||
def load_caplet(self, caplet_path: str) -> Dict[str, Any]:
|
||||
return self.run(f"caplet.load {caplet_path}")
|
||||
|
||||
@property
|
||||
def credentials(self) -> Dict[str, str]:
|
||||
return {"user": self.user, "password": self.password}
|
||||
|
||||
@property
|
||||
def api_flags(self) -> List[str]:
|
||||
return [
|
||||
"-api-rest-address", self.host,
|
||||
"-api-rest-port", str(self.port),
|
||||
"-api-rest-username", self.user,
|
||||
"-api-rest-password", self.password,
|
||||
]
|
||||
Reference in New Issue
Block a user