""" This plugin provides a command to search Exploit-DB for security exploits and vulnerabilities. Uses the searchsploit-style approach with the files.csv database. """ import logging import requests import csv import io import simplematrixbotlib as botlib from datetime import datetime # Exploit-DB CSV database URL EXPLOITDB_CSV_URL = "https://gitlab.com/exploit-database/exploitdb/-/raw/main/files_exploits.csv" def format_exploit(exploit, index, total): """ Format an exploit entry for display. Args: exploit (dict): The exploit data. index (int): Current result index. total (int): Total number of results. Returns: str: Formatted HTML string. """ edb_id = exploit.get('id', 'N/A') title = exploit.get('description', 'No title') date = exploit.get('date', 'Unknown') author = exploit.get('author', 'Unknown') exploit_type = exploit.get('type', 'Unknown') platform = exploit.get('platform', 'Unknown') # Build the URL url = f"https://www.exploit-db.com/exploits/{edb_id}" output = f"""💣 Exploit {index}/{total}
Title: {title}
EDB-ID: {edb_id}
Type: {exploit_type} | Platform: {platform}
Author: {author} | Date: {date}
URL: {url}""" return output async def search_exploitdb_csv(query, max_results=5): """ Search Exploit-DB CSV database for exploits matching the query. Args: query (str): Search term. max_results (int): Maximum number of results to return. Returns: list: List of exploit dictionaries, or None on error. """ try: logging.info(f"Downloading Exploit-DB CSV database...") headers = { 'User-Agent': 'FunguyBot/1.0', } # Download the CSV file response = requests.get(EXPLOITDB_CSV_URL, headers=headers, timeout=30) response.raise_for_status() # Parse CSV csv_data = response.text csv_file = io.StringIO(csv_data) reader = csv.DictReader(csv_file) # Search through CSV results = [] query_lower = query.lower() logging.info(f"Searching CSV for: {query}") for row in reader: # Search in description (title) and other fields description = row.get('description', '').lower() file_path = row.get('file', '').lower() if query_lower in description or query_lower in file_path: exploit = { 'id': row.get('id', 'N/A'), 'description': row.get('description', 'No title'), 'date': row.get('date_published', row.get('date', 'Unknown')), 'author': row.get('author', 'Unknown'), 'type': row.get('type', 'Unknown'), 'platform': row.get('platform', 'Unknown') } results.append(exploit) if len(results) >= max_results: break return results except requests.exceptions.Timeout: logging.error("Timeout downloading Exploit-DB database") return None except requests.exceptions.RequestException as e: logging.error(f"Error downloading Exploit-DB database: {e}") return None except Exception as e: logging.error(f"Unexpected error searching Exploit-DB: {e}", exc_info=True) return None async def search_exploitdb_google(query, max_results=5): """ Alternative: Search Exploit-DB using site-specific search. Returns formatted search URLs instead of parsing. Args: query (str): Search term. max_results (int): Maximum number of results to return. Returns: str: Formatted search information. """ # Create search URLs exploitdb_search_url = f"https://www.exploit-db.com/search?q={query}" google_search_url = f"https://www.google.com/search?q=site:exploit-db.com+{query}" output = f"""💣 Exploit-DB Search for: {query}

Direct Search:
{exploitdb_search_url}

Google Site Search:
{google_search_url}

💡 Tip: You can also use searchsploit command-line tool for offline searches.
⚠️ Use responsibly and only on systems you have permission to test.""" return output async def handle_command(room, message, bot, prefix, config): """ Function to handle the !exploitdb command. Args: room (Room): The Matrix room where the command was invoked. message (RoomMessage): The message object containing the command. bot (Bot): The bot object. prefix (str): The command prefix. config (dict): Configuration parameters. Returns: None """ match = botlib.MessageMatch(room, message, bot, prefix) if match.is_not_from_this_bot() and match.prefix() and match.command("exploitdb"): logging.info("Received !exploitdb command") args = match.args() if len(args) < 1: await bot.api.send_text_message( room.room_id, "Usage: !exploitdb [max_results]\n" "Examples:\n" " !exploitdb wordpress\n" " !exploitdb apache 3\n" " !exploitdb windows privilege escalation\n" "Searches Exploit-DB for security vulnerabilities and exploits." ) logging.info("Sent usage message for !exploitdb") return # Check if last argument is a number (max results) max_results = 5 search_terms = args if args[-1].isdigit(): max_results = int(args[-1]) if max_results < 1: max_results = 1 elif max_results > 10: max_results = 10 search_terms = args[:-1] query = ' '.join(search_terms) try: # Send "searching" message await bot.api.send_text_message( room.room_id, f"🔍 Searching Exploit-DB for: {query}... (this may take a moment)" ) # Try CSV search first exploits = await search_exploitdb_csv(query, max_results) if exploits is None: # Fallback to providing search links logging.warning("CSV search failed, providing search links instead") output = await search_exploitdb_google(query, max_results) await bot.api.send_markdown_message(room.room_id, output) return if not exploits: # Also provide search links when no results output = f"No exploits found in local search for: {query}

" output += await search_exploitdb_google(query, max_results) await bot.api.send_markdown_message(room.room_id, output) logging.info(f"No exploits found for: {query}") return total = len(exploits) logging.info(f"Found {total} exploit(s) for: {query}") # Format all results output = f"💣 Exploit-DB Search Results for: {query}

" for idx, exploit in enumerate(exploits, 1): output += format_exploit(exploit, idx, total) output += "

" output += f"⚠️ Use responsibly and only on systems you have permission to test." # Wrap in collapsible details if more than 2 results if total > 2: summary = f"💣 Exploit-DB: {query} ({total} results)" output = f"
{summary}{output}
" await bot.api.send_markdown_message(room.room_id, output) logging.info(f"Sent {total} exploit(s) for: {query}") except Exception as e: await bot.api.send_text_message( room.room_id, f"An error occurred while searching Exploit-DB: {str(e)}" ) logging.error(f"Error in exploitdb plugin: {e}", exc_info=True)