Files
FunguyBot/plugins/exploitdb.py
T

255 lines
8.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
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"""<strong>💣 Exploit {index}/{total}</strong><br>
<strong>Title:</strong> {title}<br>
<strong>EDB-ID:</strong> {edb_id}<br>
<strong>Type:</strong> {exploit_type} | <strong>Platform:</strong> {platform}<br>
<strong>Author:</strong> {author} | <strong>Date:</strong> {date}<br>
<strong>URL:</strong> <a href="{url}">{url}</a>"""
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"""<strong>💣 Exploit-DB Search for: {query}</strong><br><br>
<strong>Direct Search:</strong><br>
<a href="{exploitdb_search_url}">{exploitdb_search_url}</a><br><br>
<strong>Google Site Search:</strong><br>
<a href="{google_search_url}">{google_search_url}</a><br><br>
<em>💡 Tip: You can also use <code>searchsploit</code> command-line tool for offline searches.</em><br>
<em>⚠️ Use responsibly and only on systems you have permission to test.</em>"""
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 <search term> [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: <strong>{query}</strong><br><br>"
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"<strong>💣 Exploit-DB Search Results for: {query}</strong><br><br>"
for idx, exploit in enumerate(exploits, 1):
output += format_exploit(exploit, idx, total)
output += "<br><br>"
output += f"<em>⚠️ Use responsibly and only on systems you have permission to test.</em>"
# Wrap in collapsible details if more than 2 results
if total > 2:
summary = f"<strong>💣 Exploit-DB: {query}</strong> ({total} results)"
output = f"<details><summary>{summary}</summary>{output}</details>"
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)
# ---------------------------------------------------------------------------
# Plugin Metadata
# ---------------------------------------------------------------------------
__version__ = "1.0.0"
__author__ = "Funguy Bot"
__description__ = "Exploit-DB search"
__help__ = """
<details>
<summary><strong>!exploitdb</strong> Search Exploit Database</summary>
<p><code>!exploitdb &lt;search term&gt; [max_results]</code> Search for exploits (title, EDB-ID, type, platform, author, link).<br>
Example: <code>!exploitdb wordpress 5</code></p>
<p>Fetches from the official Exploit-DB CSV. Falls back to search links if unavailable.</p>
</details>
"""