# Data collection and organization tool to aggregate findings from other modules. # Saves settings in `/home/bjorn/.settings_bjorn/freya_harvest_settings.json`. # Automatically loads saved settings if arguments are not provided. # -i, --input Input directory to monitor (default: /home/bjorn/Bjorn/data/output/). # -o, --output Output directory for reports (default: /home/bjorn/Bjorn/data/reports). # -f, --format Output format (json, html, md, default: all). # -w, --watch Watch for new findings in real-time. # -c, --clean Clean old data before processing. import os import json import argparse from datetime import datetime import logging import time import shutil import glob import watchdog.observers import watchdog.events import markdown import jinja2 from collections import defaultdict b_class = "FreyaHarvest" b_module = "freya_harvest" b_enabled = 0 # Configure logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') # Default settings DEFAULT_INPUT_DIR = "/home/bjorn/Bjorn/data/output" DEFAULT_OUTPUT_DIR = "/home/bjorn/Bjorn/data/reports" DEFAULT_SETTINGS_DIR = "/home/bjorn/.settings_bjorn" SETTINGS_FILE = os.path.join(DEFAULT_SETTINGS_DIR, "freya_harvest_settings.json") # HTML template for reports HTML_TEMPLATE = """ Bjorn Reconnaissance Report

Bjorn Reconnaissance Report

Generated: {{ timestamp }}

{% for section in sections %}

{{ section.title }}

{{ section.content }}
{% endfor %} """ class FreyaHarvest: def __init__(self, input_dir=DEFAULT_INPUT_DIR, output_dir=DEFAULT_OUTPUT_DIR, formats=None, watch_mode=False, clean=False): self.input_dir = input_dir self.output_dir = output_dir self.formats = formats or ['json', 'html', 'md'] self.watch_mode = watch_mode self.clean = clean self.data = defaultdict(list) self.observer = None def clean_directories(self): """Clean output directory if requested.""" if self.clean and os.path.exists(self.output_dir): shutil.rmtree(self.output_dir) os.makedirs(self.output_dir) logging.info(f"Cleaned output directory: {self.output_dir}") def collect_wifi_data(self): """Collect WiFi-related findings.""" try: wifi_dir = os.path.join(self.input_dir, "wifi") if os.path.exists(wifi_dir): for file in glob.glob(os.path.join(wifi_dir, "*.json")): with open(file, 'r') as f: data = json.load(f) self.data['wifi'].append(data) except Exception as e: logging.error(f"Error collecting WiFi data: {e}") def collect_network_data(self): """Collect network topology and host findings.""" try: network_dir = os.path.join(self.input_dir, "topology") if os.path.exists(network_dir): for file in glob.glob(os.path.join(network_dir, "*.json")): with open(file, 'r') as f: data = json.load(f) self.data['network'].append(data) except Exception as e: logging.error(f"Error collecting network data: {e}") def collect_vulnerability_data(self): """Collect vulnerability findings.""" try: vuln_dir = os.path.join(self.input_dir, "webscan") if os.path.exists(vuln_dir): for file in glob.glob(os.path.join(vuln_dir, "*.json")): with open(file, 'r') as f: data = json.load(f) self.data['vulnerabilities'].append(data) except Exception as e: logging.error(f"Error collecting vulnerability data: {e}") def collect_credential_data(self): """Collect credential findings.""" try: cred_dir = os.path.join(self.input_dir, "packets") if os.path.exists(cred_dir): for file in glob.glob(os.path.join(cred_dir, "*.json")): with open(file, 'r') as f: data = json.load(f) self.data['credentials'].append(data) except Exception as e: logging.error(f"Error collecting credential data: {e}") def collect_data(self): """Collect all data from various sources.""" self.data.clear() # Reset data before collecting self.collect_wifi_data() self.collect_network_data() self.collect_vulnerability_data() self.collect_credential_data() logging.info("Data collection completed") def generate_json_report(self): """Generate JSON format report.""" try: report = { 'timestamp': datetime.now().isoformat(), 'findings': dict(self.data) } os.makedirs(self.output_dir, exist_ok=True) output_file = os.path.join(self.output_dir, f"report_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.json") with open(output_file, 'w') as f: json.dump(report, f, indent=4) logging.info(f"JSON report saved to {output_file}") except Exception as e: logging.error(f"Error generating JSON report: {e}") def generate_html_report(self): """Generate HTML format report.""" try: template = jinja2.Template(HTML_TEMPLATE) sections = [] # Network Section if self.data['network']: content = "

Network Topology

" for topology in self.data['network']: content += f"

Hosts discovered: {len(topology.get('hosts', []))}

" content += "" for ip, data in topology.get('hosts', {}).items(): ports = data.get('ports', []) mac = data.get('mac', 'Unknown') status = data.get('status', 'Unknown') content += f"" content += "
IPMACOpen PortsStatus
{ip}{mac}{', '.join(map(str, ports))}{status}
" sections.append({"title": "Network Information", "content": content}) # WiFi Section if self.data['wifi']: content = "

WiFi Findings

" for wifi_data in self.data['wifi']: content += "" for network in wifi_data.get('networks', []): content += f"" content += f"" content += f"" content += f"" content += f"" content += "
SSIDBSSIDSecuritySignalChannel
{network.get('ssid', 'Unknown')}{network.get('bssid', 'Unknown')}{network.get('security', 'Unknown')}{network.get('signal_strength', 'Unknown')}{network.get('channel', 'Unknown')}
" sections.append({"title": "WiFi Networks", "content": content}) # Vulnerabilities Section if self.data['vulnerabilities']: content = "

Discovered Vulnerabilities

" for vuln_data in self.data['vulnerabilities']: content += "" for vuln in vuln_data.get('findings', []): severity_class = f"vuln-{vuln.get('severity', 'low').lower()}" content += f"" content += f"" content += f"" content += f"" content += f"" content += f"" content += "
TypeSeverityTargetDescriptionRecommendation
{vuln.get('type', 'Unknown')}{vuln.get('severity', 'Unknown')}{vuln.get('target', 'Unknown')}{vuln.get('description', 'No description')}{vuln.get('recommendation', 'No recommendation')}
" sections.append({"title": "Vulnerabilities", "content": content}) # Credentials Section if self.data['credentials']: content = "

Discovered Credentials

" content += "" for cred_data in self.data['credentials']: for cred in cred_data.get('credentials', []): content += f"" content += f"" content += f"" content += f"" content += f"" content += "
TypeSourceServiceUsernameTimestamp
{cred.get('type', 'Unknown')}{cred.get('source', 'Unknown')}{cred.get('service', 'Unknown')}{cred.get('username', 'Unknown')}{cred.get('timestamp', 'Unknown')}
" sections.append({"title": "Credentials", "content": content}) # Generate HTML os.makedirs(self.output_dir, exist_ok=True) html = template.render( timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S"), sections=sections ) output_file = os.path.join(self.output_dir, f"report_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.html") with open(output_file, 'w') as f: f.write(html) logging.info(f"HTML report saved to {output_file}") except Exception as e: logging.error(f"Error generating HTML report: {e}") def generate_markdown_report(self): """Generate Markdown format report.""" try: md_content = [ "# Bjorn Reconnaissance Report", f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n" ] # Network Section if self.data['network']: md_content.append("## Network Information") for topology in self.data['network']: md_content.append(f"\nHosts discovered: {len(topology.get('hosts', []))}") md_content.append("\n| IP | MAC | Open Ports | Status |") md_content.append("|-------|-------|------------|---------|") for ip, data in topology.get('hosts', {}).items(): ports = data.get('ports', []) mac = data.get('mac', 'Unknown') status = data.get('status', 'Unknown') md_content.append(f"| {ip} | {mac} | {', '.join(map(str, ports))} | {status} |") # WiFi Section if self.data['wifi']: md_content.append("\n## WiFi Networks") md_content.append("\n| SSID | BSSID | Security | Signal | Channel |") md_content.append("|------|--------|-----------|---------|----------|") for wifi_data in self.data['wifi']: for network in wifi_data.get('networks', []): md_content.append( f"| {network.get('ssid', 'Unknown')} | " f"{network.get('bssid', 'Unknown')} | " f"{network.get('security', 'Unknown')} | " f"{network.get('signal_strength', 'Unknown')} | " f"{network.get('channel', 'Unknown')} |" ) # Vulnerabilities Section if self.data['vulnerabilities']: md_content.append("\n## Vulnerabilities") md_content.append("\n| Type | Severity | Target | Description | Recommendation |") md_content.append("|------|-----------|--------|-------------|----------------|") for vuln_data in self.data['vulnerabilities']: for vuln in vuln_data.get('findings', []): md_content.append( f"| {vuln.get('type', 'Unknown')} | " f"{vuln.get('severity', 'Unknown')} | " f"{vuln.get('target', 'Unknown')} | " f"{vuln.get('description', 'No description')} | " f"{vuln.get('recommendation', 'No recommendation')} |" ) # Credentials Section if self.data['credentials']: md_content.append("\n## Discovered Credentials") md_content.append("\n| Type | Source | Service | Username | Timestamp |") md_content.append("|------|---------|----------|-----------|------------|") for cred_data in self.data['credentials']: for cred in cred_data.get('credentials', []): md_content.append( f"| {cred.get('type', 'Unknown')} | " f"{cred.get('source', 'Unknown')} | " f"{cred.get('service', 'Unknown')} | " f"{cred.get('username', 'Unknown')} | " f"{cred.get('timestamp', 'Unknown')} |" ) os.makedirs(self.output_dir, exist_ok=True) output_file = os.path.join(self.output_dir, f"report_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.md") with open(output_file, 'w') as f: f.write('\n'.join(md_content)) logging.info(f"Markdown report saved to {output_file}") except Exception as e: logging.error(f"Error generating Markdown report: {e}") def generate_reports(self): """Generate reports in all specified formats.""" os.makedirs(self.output_dir, exist_ok=True) if 'json' in self.formats: self.generate_json_report() if 'html' in self.formats: self.generate_html_report() if 'md' in self.formats: self.generate_markdown_report() def start_watching(self): """Start watching for new data files.""" class FileHandler(watchdog.events.FileSystemEventHandler): def __init__(self, harvester): self.harvester = harvester def on_created(self, event): if event.is_directory: return if event.src_path.endswith('.json'): logging.info(f"New data file detected: {event.src_path}") self.harvester.collect_data() self.harvester.generate_reports() self.observer = watchdog.observers.Observer() self.observer.schedule(FileHandler(self), self.input_dir, recursive=True) self.observer.start() try: while True: time.sleep(1) except KeyboardInterrupt: self.observer.stop() self.observer.join() def execute(self): """Execute the data collection and reporting process.""" try: logging.info("Starting data collection") if self.clean: self.clean_directories() # Initial data collection and report generation self.collect_data() self.generate_reports() # Start watch mode if enabled if self.watch_mode: logging.info("Starting watch mode for new data") try: self.start_watching() except KeyboardInterrupt: logging.info("Watch mode stopped by user") finally: if self.observer: self.observer.stop() self.observer.join() logging.info("Data collection and reporting completed") except Exception as e: logging.error(f"Error during execution: {e}") raise finally: # Ensure observer is stopped if watch mode was active if self.observer and self.observer.is_alive(): self.observer.stop() self.observer.join() def save_settings(input_dir, output_dir, formats, watch_mode, clean): """Save settings to JSON file.""" try: os.makedirs(DEFAULT_SETTINGS_DIR, exist_ok=True) settings = { "input_dir": input_dir, "output_dir": output_dir, "formats": formats, "watch_mode": watch_mode, "clean": clean } with open(SETTINGS_FILE, 'w') as f: json.dump(settings, f) logging.info(f"Settings saved to {SETTINGS_FILE}") except Exception as e: logging.error(f"Failed to save settings: {e}") def load_settings(): """Load settings from JSON file.""" if os.path.exists(SETTINGS_FILE): try: with open(SETTINGS_FILE, 'r') as f: return json.load(f) except Exception as e: logging.error(f"Failed to load settings: {e}") return {} def main(): parser = argparse.ArgumentParser(description="Data collection and organization tool") parser.add_argument("-i", "--input", default=DEFAULT_INPUT_DIR, help="Input directory to monitor") parser.add_argument("-o", "--output", default=DEFAULT_OUTPUT_DIR, help="Output directory for reports") parser.add_argument("-f", "--format", choices=['json', 'html', 'md', 'all'], default='all', help="Output format") parser.add_argument("-w", "--watch", action="store_true", help="Watch for new findings") parser.add_argument("-c", "--clean", action="store_true", help="Clean old data before processing") args = parser.parse_args() settings = load_settings() input_dir = args.input or settings.get("input_dir") output_dir = args.output or settings.get("output_dir") formats = ['json', 'html', 'md'] if args.format == 'all' else [args.format] watch_mode = args.watch or settings.get("watch_mode", False) clean = args.clean or settings.get("clean", False) save_settings(input_dir, output_dir, formats, watch_mode, clean) harvester = FreyaHarvest( input_dir=input_dir, output_dir=output_dir, formats=formats, watch_mode=watch_mode, clean=clean ) harvester.execute() if __name__ == "__main__": main()