Adding in rule generation from github exploits

This commit is contained in:
Brendan McDevitt 2025-07-08 10:20:54 -05:00
parent cc825fdb86
commit 5a9ae34996
6 changed files with 618 additions and 34 deletions

View file

@ -2,6 +2,11 @@
# Get your free API key at: https://nvd.nist.gov/developers/request-an-api-key # Get your free API key at: https://nvd.nist.gov/developers/request-an-api-key
NVD_API_KEY=your_nvd_api_key_here NVD_API_KEY=your_nvd_api_key_here
# GitHub API Configuration (Optional - for exploit analysis)
# Get your personal access token at: https://github.com/settings/tokens
# Only needs "public_repo" scope for searching public repositories
GITHUB_TOKEN=your_github_token_here
# Database Configuration (Docker Compose will use defaults) # Database Configuration (Docker Compose will use defaults)
# DATABASE_URL=postgresql://cve_user:cve_password@localhost:5432/cve_sigma_db # DATABASE_URL=postgresql://cve_user:cve_password@localhost:5432/cve_sigma_db

View file

@ -5,10 +5,13 @@ An automated platform that fetches CVE data and automatically generates SIGMA ru
## Features ## Features
- **Automated CVE Fetching**: Regularly polls the NVD (National Vulnerability Database) for CVEs from July 2025 - **Automated CVE Fetching**: Regularly polls the NVD (National Vulnerability Database) for CVEs from July 2025
- **Intelligent SIGMA Rule Generation**: Automatically creates SIGMA rules based on CVE characteristics - **GitHub Exploit Analysis**: Automatically searches GitHub for exploit code related to each CVE
- **Intelligent SIGMA Rule Generation**: Creates SIGMA rules based on CVE characteristics AND actual exploit code
- **Exploit-Based Detection**: Enhanced rules using real indicators extracted from GitHub exploits
- **Modern Web Interface**: React-based UI for browsing CVEs and managing SIGMA rules - **Modern Web Interface**: React-based UI for browsing CVEs and managing SIGMA rules
- **Real-time Updates**: Background tasks keep CVE data current with current 2025 vulnerabilities - **Real-time Updates**: Background tasks keep CVE data current with current 2025 vulnerabilities
- **Rule Templates**: Configurable templates for different types of vulnerabilities - **Rule Templates**: Configurable templates for different types of vulnerabilities
- **MITRE ATT&CK Mapping**: Automatic mapping to MITRE ATT&CK techniques
- **API Testing**: Built-in NVD API connectivity testing - **API Testing**: Built-in NVD API connectivity testing
- **Enhanced Error Handling**: Robust fallback mechanisms and detailed logging - **Enhanced Error Handling**: Robust fallback mechanisms and detailed logging
- **Docker Compose**: Easy deployment and orchestration - **Docker Compose**: Easy deployment and orchestration
@ -101,9 +104,25 @@ curl -X POST http://localhost:8000/api/fetch-cves
### Environment Variables ### Environment Variables
- `DATABASE_URL`: PostgreSQL connection string - `DATABASE_URL`: PostgreSQL connection string
- `NVD_API_KEY`: Optional NVD API key for higher rate limits - `NVD_API_KEY`: Optional NVD API key for higher rate limits (5→50 requests/30s)
- `GITHUB_TOKEN`: Optional GitHub personal access token for exploit analysis
- `REACT_APP_API_URL`: Backend API URL for frontend - `REACT_APP_API_URL`: Backend API URL for frontend
### GitHub Integration (Optional)
For enhanced SIGMA rule generation with exploit analysis:
1. **Create GitHub Token**: Visit https://github.com/settings/tokens
2. **Required Permissions**: Only needs "public_repo" scope for searching public repositories
3. **Add to Environment**: `GITHUB_TOKEN=your_token_here` in `.env` file
4. **Benefits**:
- Automatically searches for CVE-related exploit code
- Extracts real indicators (processes, files, network connections)
- Generates more accurate and specific SIGMA rules
- Higher confidence ratings for exploit-based rules
**Rate Limits**: 5000 requests/hour with token, 60/hour without
### Rule Templates ### Rule Templates
The application includes pre-configured rule templates for: The application includes pre-configured rule templates for:
@ -115,19 +134,55 @@ Additional templates can be added to the database via the `rule_templates` table
## SIGMA Rule Generation Logic ## SIGMA Rule Generation Logic
The rule generation process: The enhanced rule generation process:
1. **CVE Analysis**: Analyzes CVE description and affected products 1. **CVE Analysis**: Analyzes CVE description and affected products
2. **Template Selection**: Chooses appropriate SIGMA rule template 2. **GitHub Exploit Search**: Searches GitHub for exploit code using multiple query strategies
3. **Indicator Extraction**: Extracts suspicious processes, ports, or file patterns 3. **Code Analysis**: Extracts specific indicators from exploit code:
4. **Rule Population**: Fills template with CVE-specific data - Process names and command lines
5. **Confidence Scoring**: Assigns confidence level based on CVSS score - File paths and registry keys
- Network connections and ports
- PowerShell commands and scripts
- Command execution patterns
4. **Template Selection**: Chooses appropriate SIGMA rule template based on exploit analysis
5. **Enhanced Rule Population**: Fills template with real exploit indicators
6. **MITRE ATT&CK Mapping**: Maps to specific MITRE ATT&CK techniques
7. **Confidence Scoring**: Higher confidence for exploit-based rules
### Rule Quality Levels
- **Basic Rules**: Generated from CVE description only
- **Exploit-Based Rules**: Enhanced with GitHub exploit analysis (marked with 🔍)
- **Confidence Ratings**:
- **High**: CVSS ≥9.0 + exploit analysis
- **Medium**: CVSS ≥7.0 or exploit analysis
- **Low**: Basic CVE description only
### Template Matching ### Template Matching
- **Process Execution**: Keywords like "process", "execution", "command" - **PowerShell Execution**: Exploit contains PowerShell scripts or cmdlets
- **Network Connection**: Keywords like "network", "remote", "connection" - **Process Execution**: Exploit shows process creation or command execution
- **File Modification**: Keywords like "file", "write", "filesystem" - **Network Connection**: Exploit demonstrates network communications
- **File Modification**: Exploit involves file system operations
### Example Enhanced Rule
```yaml
title: CVE-2025-1234 Exploit-Based Detection
description: Detection for CVE-2025-1234 remote code execution [Enhanced with GitHub exploit analysis]
tags:
- attack.t1059.001
- cve-2025-1234
- exploit.github
detection:
selection:
Image|contains:
- "powershell.exe"
- "malicious_payload.exe"
- "reverse_shell.ps1"
condition: selection
level: high
```
## Development ## Development
@ -217,7 +272,8 @@ docker-compose ps
### API Key Setup ### API Key Setup
For optimal performance, get a free NVD API key: **NVD API (Recommended)**
For optimal CVE fetching performance:
1. Visit: https://nvd.nist.gov/developers/request-an-api-key 1. Visit: https://nvd.nist.gov/developers/request-an-api-key
2. Add to your `.env` file: `NVD_API_KEY=your_key_here` 2. Add to your `.env` file: `NVD_API_KEY=your_key_here`
3. Restart the application 3. Restart the application
@ -225,6 +281,16 @@ For optimal performance, get a free NVD API key:
Without an API key: 5 requests per 30 seconds Without an API key: 5 requests per 30 seconds
With an API key: 50 requests per 30 seconds With an API key: 50 requests per 30 seconds
**GitHub API (Optional)**
For enhanced exploit-based SIGMA rules:
1. Visit: https://github.com/settings/tokens
2. Create token with "public_repo" scope
3. Add to your `.env` file: `GITHUB_TOKEN=your_token_here`
4. Restart the application
Without a GitHub token: Basic rules only
With a GitHub token: Enhanced rules with exploit analysis (🔍 Exploit-Based)
### Rate Limits ### Rate Limits
Without an API key, NVD limits requests to 5 per 30 seconds. With an API key, the limit increases to 50 per 30 seconds. Without an API key, NVD limits requests to 5 per 30 seconds. With an API key, the limit increases to 50 per 30 seconds.

View file

@ -15,6 +15,10 @@ from typing import List, Optional
from pydantic import BaseModel from pydantic import BaseModel
import asyncio import asyncio
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
import base64
from github import Github
from urllib.parse import urlparse
import hashlib
# Database setup # Database setup
DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://cve_user:cve_password@localhost:5432/cve_sigma_db") DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://cve_user:cve_password@localhost:5432/cve_sigma_db")
@ -49,6 +53,9 @@ class SigmaRule(Base):
log_source = Column(String(100)) log_source = Column(String(100))
confidence_level = Column(String(20)) confidence_level = Column(String(20))
auto_generated = Column(Boolean, default=True) auto_generated = Column(Boolean, default=True)
exploit_based = Column(Boolean, default=False)
github_repos = Column(ARRAY(String))
exploit_indicators = Column(Text) # JSON string of extracted indicators
created_at = Column(TIMESTAMP, default=datetime.utcnow) created_at = Column(TIMESTAMP, default=datetime.utcnow)
updated_at = Column(TIMESTAMP, default=datetime.utcnow) updated_at = Column(TIMESTAMP, default=datetime.utcnow)
@ -85,12 +92,271 @@ class SigmaRuleResponse(BaseModel):
log_source: Optional[str] = None log_source: Optional[str] = None
confidence_level: Optional[str] = None confidence_level: Optional[str] = None
auto_generated: bool = True auto_generated: bool = True
exploit_based: bool = False
github_repos: Optional[List[str]] = None
exploit_indicators: Optional[str] = None
created_at: datetime created_at: datetime
class Config: class Config:
from_attributes = True from_attributes = True
# CVE and SIGMA Rule Generator Service # GitHub Exploit Analysis Service
class GitHubExploitAnalyzer:
def __init__(self):
self.github_token = os.getenv("GITHUB_TOKEN")
self.github = Github(self.github_token) if self.github_token else None
async def search_exploits_for_cve(self, cve_id: str) -> List[dict]:
"""Search GitHub for exploit code related to a CVE"""
if not self.github:
print(f"No GitHub token configured, skipping exploit search for {cve_id}")
return []
try:
print(f"Searching GitHub for exploits for {cve_id}")
# Search queries to find exploit code
search_queries = [
f"{cve_id} exploit",
f"{cve_id} poc",
f"{cve_id} vulnerability",
f'"{cve_id}" exploit code',
f"{cve_id.replace('-', '_')} exploit"
]
exploits = []
seen_repos = set()
for query in search_queries[:2]: # Limit to 2 queries to avoid rate limits
try:
# Search repositories
repos = self.github.search_repositories(
query=query,
sort="updated",
order="desc"
)
# Get top 5 results per query
for repo in repos[:5]:
if repo.full_name in seen_repos:
continue
seen_repos.add(repo.full_name)
# Analyze repository
exploit_info = await self._analyze_repository(repo, cve_id)
if exploit_info:
exploits.append(exploit_info)
if len(exploits) >= 10: # Limit total exploits
break
if len(exploits) >= 10:
break
except Exception as e:
print(f"Error searching GitHub with query '{query}': {str(e)}")
continue
print(f"Found {len(exploits)} potential exploits for {cve_id}")
return exploits
except Exception as e:
print(f"Error searching GitHub for {cve_id}: {str(e)}")
return []
async def _analyze_repository(self, repo, cve_id: str) -> Optional[dict]:
"""Analyze a GitHub repository for exploit code"""
try:
# Check if repo name or description mentions the CVE
repo_text = f"{repo.name} {repo.description or ''}".lower()
if cve_id.lower() not in repo_text and cve_id.replace('-', '_').lower() not in repo_text:
return None
# Get repository contents
exploit_files = []
indicators = {
'processes': set(),
'files': set(),
'registry': set(),
'network': set(),
'commands': set(),
'powershell': set(),
'urls': set()
}
try:
contents = repo.get_contents("")
for content in contents[:20]: # Limit files to analyze
if content.type == "file" and self._is_exploit_file(content.name):
file_analysis = await self._analyze_file_content(repo, content, cve_id)
if file_analysis:
exploit_files.append(file_analysis)
# Merge indicators
for key, values in file_analysis.get('indicators', {}).items():
if key in indicators:
indicators[key].update(values)
except Exception as e:
print(f"Error analyzing repo contents for {repo.full_name}: {str(e)}")
if not exploit_files:
return None
return {
'repo_name': repo.full_name,
'repo_url': repo.html_url,
'description': repo.description,
'language': repo.language,
'stars': repo.stargazers_count,
'updated': repo.updated_at.isoformat(),
'files': exploit_files,
'indicators': {k: list(v) for k, v in indicators.items()}
}
except Exception as e:
print(f"Error analyzing repository {repo.full_name}: {str(e)}")
return None
def _is_exploit_file(self, filename: str) -> bool:
"""Check if a file is likely to contain exploit code"""
exploit_extensions = ['.py', '.ps1', '.sh', '.c', '.cpp', '.js', '.rb', '.pl', '.php', '.java']
exploit_names = ['exploit', 'poc', 'payload', 'shell', 'reverse', 'bind', 'attack']
filename_lower = filename.lower()
# Check extension
if not any(filename_lower.endswith(ext) for ext in exploit_extensions):
return False
# Check filename for exploit-related terms
return any(term in filename_lower for term in exploit_names) or 'cve' in filename_lower
async def _analyze_file_content(self, repo, file_content, cve_id: str) -> Optional[dict]:
"""Analyze individual file content for exploit indicators"""
try:
if file_content.size > 100000: # Skip files larger than 100KB
return None
# Decode file content
content = file_content.decoded_content.decode('utf-8', errors='ignore')
# Check if file actually mentions the CVE
if cve_id.lower() not in content.lower() and cve_id.replace('-', '_').lower() not in content.lower():
return None
indicators = self._extract_indicators_from_code(content, file_content.name)
if not any(indicators.values()):
return None
return {
'filename': file_content.name,
'path': file_content.path,
'size': file_content.size,
'indicators': indicators
}
except Exception as e:
print(f"Error analyzing file {file_content.name}: {str(e)}")
return None
def _extract_indicators_from_code(self, content: str, filename: str) -> dict:
"""Extract security indicators from exploit code"""
indicators = {
'processes': set(),
'files': set(),
'registry': set(),
'network': set(),
'commands': set(),
'powershell': set(),
'urls': set()
}
# Process patterns
process_patterns = [
r'CreateProcess[AW]?\s*\(\s*["\']([^"\']+)["\']',
r'ShellExecute[AW]?\s*\([^,]*,\s*["\']([^"\']+)["\']',
r'system\s*\(\s*["\']([^"\']+)["\']',
r'exec\s*\(\s*["\']([^"\']+)["\']',
r'subprocess\.(?:call|run|Popen)\s*\(\s*["\']([^"\']+)["\']'
]
# File patterns
file_patterns = [
r'(?:fopen|CreateFile|WriteFile|ReadFile)\s*\(\s*["\']([^"\']+\.[a-zA-Z0-9]+)["\']',
r'(?:copy|move|del|rm)\s+["\']?([^\s"\']+\.[a-zA-Z0-9]+)["\']?',
r'\\\\[^\\]+\\[^\\]+\\([^\\]+\.[a-zA-Z0-9]+)',
r'[C-Z]:\\\\[^\\]+\\\\([^\\]+\.[a-zA-Z0-9]+)'
]
# Registry patterns
registry_patterns = [
r'(?:RegOpenKey|RegSetValue|RegCreateKey)\s*\([^,]*,\s*["\']([^"\']+)["\']',
r'HKEY_[A-Z_]+\\\\([^"\'\\]+)',
r'reg\s+add\s+["\']?([^"\'\\]+\\\\[^"\']+)["\']?'
]
# Network patterns
network_patterns = [
r'(?:connect|bind|listen)\s*\([^,]*,\s*(\d+)',
r'socket\.connect\s*\(\s*\(["\']?([^"\']+)["\']?,\s*(\d+)\)',
r'(?:http|https|ftp)://([^\s"\'<>]+)',
r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+)'
]
# PowerShell patterns
powershell_patterns = [
r'(?:powershell|pwsh)\s+(?:-[a-zA-Z]+\s+)*["\']?([^"\']+)["\']?',
r'Invoke-(?:Expression|Command|WebRequest|RestMethod)\s+["\']?([^"\']+)["\']?',
r'Start-Process\s+["\']?([^"\']+)["\']?',
r'Get-Process\s+["\']?([^"\']+)["\']?'
]
# Command patterns
command_patterns = [
r'(?:cmd|command)\s+(?:/[a-zA-Z]+\s+)*["\']?([^"\']+)["\']?',
r'(?:ping|nslookup|netstat|tasklist|wmic)\s+([^\s"\']+)',
r'(?:net|sc|schtasks)\s+[a-zA-Z]+\s+([^\s"\']+)'
]
# Extract indicators using regex patterns
patterns = {
'processes': process_patterns,
'files': file_patterns,
'registry': registry_patterns,
'powershell': powershell_patterns,
'commands': command_patterns
}
for category, pattern_list in patterns.items():
for pattern in pattern_list:
matches = re.findall(pattern, content, re.IGNORECASE | re.MULTILINE)
for match in matches:
if isinstance(match, tuple):
indicators[category].add(match[0])
else:
indicators[category].add(match)
# Special handling for network indicators
for pattern in network_patterns:
matches = re.findall(pattern, content, re.IGNORECASE)
for match in matches:
if isinstance(match, tuple):
if len(match) >= 2:
indicators['network'].add(f"{match[0]}:{match[1]}")
else:
indicators['network'].add(match[0])
else:
indicators['network'].add(match)
# Convert sets to lists and filter out empty/invalid indicators
cleaned_indicators = {}
for key, values in indicators.items():
cleaned_values = [v for v in values if v and len(v.strip()) > 2 and len(v) < 200]
if cleaned_values:
cleaned_indicators[key] = cleaned_values[:10] # Limit to 10 per category
return cleaned_indicators
class CVESigmaService: class CVESigmaService:
def __init__(self, db: Session): def __init__(self, db: Session):
self.db = db self.db = db
@ -207,11 +473,33 @@ class CVESigmaService:
self.db.add(sigma_rule) self.db.add(sigma_rule)
return sigma_rule return sigma_rule
def _select_template(self, description: str, affected_products: List[str]): def _select_template(self, description: str, affected_products: List[str], exploit_indicators: dict = None):
"""Select appropriate SIGMA rule template""" """Select appropriate SIGMA rule template based on CVE and exploit analysis"""
templates = self.db.query(RuleTemplate).all() templates = self.db.query(RuleTemplate).all()
# Simple template selection logic # If we have exploit indicators, use them to determine the best template
if exploit_indicators:
if exploit_indicators.get('powershell'):
powershell_template = next((t for t in templates if "PowerShell" in t.template_name), None)
if powershell_template:
return powershell_template
if exploit_indicators.get('network'):
network_template = next((t for t in templates if "Network Connection" in t.template_name), None)
if network_template:
return network_template
if exploit_indicators.get('files'):
file_template = next((t for t in templates if "File Modification" in t.template_name), None)
if file_template:
return file_template
if exploit_indicators.get('processes') or exploit_indicators.get('commands'):
process_template = next((t for t in templates if "Process Execution" in t.template_name), None)
if process_template:
return process_template
# Fallback to original logic
if any("windows" in p or "microsoft" in p for p in affected_products): if any("windows" in p or "microsoft" in p for p in affected_products):
if "process" in description or "execution" in description: if "process" in description or "execution" in description:
return next((t for t in templates if "Process Execution" in t.template_name), None) return next((t for t in templates if "Process Execution" in t.template_name), None)
@ -223,24 +511,50 @@ class CVESigmaService:
# Default to process execution template # Default to process execution template
return next((t for t in templates if "Process Execution" in t.template_name), None) return next((t for t in templates if "Process Execution" in t.template_name), None)
def _populate_template(self, cve: CVE, template: RuleTemplate) -> str: def _populate_template(self, cve: CVE, template: RuleTemplate, exploit_indicators: dict = None) -> str:
"""Populate template with CVE-specific data""" """Populate template with CVE-specific data and exploit indicators"""
try: try:
# Extract suspicious indicators from description # Use exploit indicators if available, otherwise extract from description
suspicious_processes = self._extract_suspicious_indicators(cve.description, "process") if exploit_indicators:
suspicious_ports = self._extract_suspicious_indicators(cve.description, "port") suspicious_processes = exploit_indicators.get('processes', []) + exploit_indicators.get('commands', [])
file_patterns = self._extract_suspicious_indicators(cve.description, "file") suspicious_ports = []
file_patterns = exploit_indicators.get('files', [])
# Extract ports from network indicators
for net_indicator in exploit_indicators.get('network', []):
if ':' in str(net_indicator):
try:
port = int(str(net_indicator).split(':')[-1])
suspicious_ports.append(port)
except ValueError:
pass
else:
# Fallback to original extraction
suspicious_processes = self._extract_suspicious_indicators(cve.description, "process")
suspicious_ports = self._extract_suspicious_indicators(cve.description, "port")
file_patterns = self._extract_suspicious_indicators(cve.description, "file")
# Determine severity level # Determine severity level
level = "high" if cve.cvss_score and cve.cvss_score >= 7.0 else "medium" level = "high" if cve.cvss_score and cve.cvss_score >= 7.0 else "medium"
# Create enhanced description
enhanced_description = cve.description[:200] + "..." if len(cve.description) > 200 else cve.description
if exploit_indicators:
enhanced_description += " [Enhanced with GitHub exploit analysis]"
# Build tags
tags = [f"attack.{self._get_mitre_technique(cve.description, exploit_indicators)}", cve.cve_id.lower()]
if exploit_indicators:
tags.append("exploit.github")
rule_content = template.template_content.format( rule_content = template.template_content.format(
title=f"CVE-{cve.cve_id} Exploitation Attempt", title=f"CVE-{cve.cve_id} {'Exploit-Based ' if exploit_indicators else ''}Detection",
description=cve.description[:200] + "..." if len(cve.description) > 200 else cve.description, description=enhanced_description,
rule_id=str(uuid.uuid4()), rule_id=str(uuid.uuid4()),
date=datetime.utcnow().strftime("%Y/%m/%d"), date=datetime.utcnow().strftime("%Y/%m/%d"),
cve_url=f"https://nvd.nist.gov/vuln/detail/{cve.cve_id}", cve_url=f"https://nvd.nist.gov/vuln/detail/{cve.cve_id}",
cve_id=cve.cve_id.lower(), cve_id=cve.cve_id.lower(),
tags="\n - ".join(tags),
suspicious_processes=suspicious_processes or ["suspicious.exe", "malware.exe"], suspicious_processes=suspicious_processes or ["suspicious.exe", "malware.exe"],
suspicious_ports=suspicious_ports or [4444, 8080, 9999], suspicious_ports=suspicious_ports or [4444, 8080, 9999],
file_patterns=file_patterns or ["temp", "malware", "exploit"], file_patterns=file_patterns or ["temp", "malware", "exploit"],
@ -253,6 +567,37 @@ class CVESigmaService:
print(f"Error populating template: {str(e)}") print(f"Error populating template: {str(e)}")
return None return None
def _get_mitre_technique(self, description: str, exploit_indicators: dict = None) -> str:
"""Map CVE and exploit indicators to MITRE ATT&CK techniques"""
desc_lower = description.lower()
# Check exploit indicators first
if exploit_indicators:
if exploit_indicators.get('powershell'):
return "t1059.001" # PowerShell
elif exploit_indicators.get('commands'):
return "t1059.003" # Windows Command Shell
elif exploit_indicators.get('network'):
return "t1071.001" # Web Protocols
elif exploit_indicators.get('files'):
return "t1105" # Ingress Tool Transfer
elif exploit_indicators.get('processes'):
return "t1106" # Native API
# Fallback to description analysis
if "powershell" in desc_lower:
return "t1059.001"
elif "command" in desc_lower or "cmd" in desc_lower:
return "t1059.003"
elif "network" in desc_lower or "remote" in desc_lower:
return "t1071.001"
elif "file" in desc_lower or "upload" in desc_lower:
return "t1105"
elif "process" in desc_lower or "execution" in desc_lower:
return "t1106"
else:
return "execution" # Generic
def _extract_suspicious_indicators(self, description: str, indicator_type: str) -> List: def _extract_suspicious_indicators(self, description: str, indicator_type: str) -> List:
"""Extract suspicious indicators from CVE description""" """Extract suspicious indicators from CVE description"""
if indicator_type == "process": if indicator_type == "process":
@ -272,8 +617,19 @@ class CVESigmaService:
return None return None
def _determine_detection_type(self, description: str) -> str: def _determine_detection_type(self, description: str, exploit_indicators: dict = None) -> str:
"""Determine detection type based on CVE description""" """Determine detection type based on CVE description and exploit indicators"""
if exploit_indicators:
if exploit_indicators.get('powershell'):
return "powershell"
elif exploit_indicators.get('network'):
return "network"
elif exploit_indicators.get('files'):
return "file"
elif exploit_indicators.get('processes') or exploit_indicators.get('commands'):
return "process"
# Fallback to original logic
if "remote" in description or "network" in description: if "remote" in description or "network" in description:
return "network" return "network"
elif "process" in description or "execution" in description: elif "process" in description or "execution" in description:
@ -283,11 +639,27 @@ class CVESigmaService:
else: else:
return "general" return "general"
def _calculate_confidence(self, cve: CVE) -> str: def _calculate_confidence(self, cve: CVE, exploit_based: bool = False) -> str:
"""Calculate confidence level for the generated rule""" """Calculate confidence level for the generated rule"""
if cve.cvss_score and cve.cvss_score >= 9.0: base_confidence = 0
# CVSS score contributes to confidence
if cve.cvss_score:
if cve.cvss_score >= 9.0:
base_confidence += 3
elif cve.cvss_score >= 7.0:
base_confidence += 2
else:
base_confidence += 1
# Exploit-based rules get higher confidence
if exploit_based:
base_confidence += 2
# Map to confidence levels
if base_confidence >= 4:
return "high" return "high"
elif cve.cvss_score and cve.cvss_score >= 7.0: elif base_confidence >= 2:
return "medium" return "medium"
else: else:
return "low" return "low"
@ -427,6 +799,9 @@ async def get_sigma_rules(skip: int = 0, limit: int = 50, db: Session = Depends(
'log_source': rule.log_source, 'log_source': rule.log_source,
'confidence_level': rule.confidence_level, 'confidence_level': rule.confidence_level,
'auto_generated': rule.auto_generated, 'auto_generated': rule.auto_generated,
'exploit_based': rule.exploit_based or False,
'github_repos': rule.github_repos or [],
'exploit_indicators': rule.exploit_indicators,
'created_at': rule.created_at 'created_at': rule.created_at
} }
result.append(SigmaRuleResponse(**rule_dict)) result.append(SigmaRuleResponse(**rule_dict))
@ -447,6 +822,9 @@ async def get_sigma_rules_by_cve(cve_id: str, db: Session = Depends(get_db)):
'log_source': rule.log_source, 'log_source': rule.log_source,
'confidence_level': rule.confidence_level, 'confidence_level': rule.confidence_level,
'auto_generated': rule.auto_generated, 'auto_generated': rule.auto_generated,
'exploit_based': rule.exploit_based or False,
'github_repos': rule.github_repos or [],
'exploit_indicators': rule.exploit_indicators,
'created_at': rule.created_at 'created_at': rule.created_at
} }
result.append(SigmaRuleResponse(**rule_dict)) result.append(SigmaRuleResponse(**rule_dict))

View file

@ -8,3 +8,7 @@ python-multipart==0.0.6
redis==5.0.1 redis==5.0.1
alembic==1.13.1 alembic==1.13.1
asyncpg==0.29.0 asyncpg==0.29.0
pygithub==2.1.1
gitpython==3.1.40
beautifulsoup4==4.12.2
lxml==4.9.3

View file

@ -275,7 +275,37 @@ function App() {
Auto-generated Auto-generated
</span> </span>
)} )}
{rule.exploit_based && (
<span className="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-red-100 text-red-800">
🔍 Exploit-Based
</span>
)}
</div> </div>
{rule.github_repos && rule.github_repos.length > 0 && (
<div className="mt-2">
<p className="text-xs text-gray-500">
Based on {rule.github_repos.length} GitHub repository{rule.github_repos.length > 1 ? 's' : ''}:
</p>
<div className="flex flex-wrap gap-1 mt-1">
{rule.github_repos.slice(0, 3).map((repo, index) => (
<a
key={index}
href={repo}
target="_blank"
rel="noopener noreferrer"
className="text-xs text-blue-600 hover:text-blue-800 underline"
>
{repo.split('/').slice(-2).join('/')}
</a>
))}
{rule.github_repos.length > 3 && (
<span className="text-xs text-gray-500">
+{rule.github_repos.length - 3} more
</span>
)}
</div>
</div>
)}
</div> </div>
<span className="text-sm text-gray-500"> <span className="text-sm text-gray-500">
{formatDate(rule.created_at)} {formatDate(rule.created_at)}
@ -291,12 +321,52 @@ function App() {
{rule.rule_content} {rule.rule_content}
</SyntaxHighlighter> </SyntaxHighlighter>
</div> </div>
{rule.exploit_indicators && (
<div className="mt-4 p-3 bg-gray-50 rounded-md">
<h4 className="text-sm font-medium text-gray-700 mb-2">Exploit Indicators Found:</h4>
<ExploitIndicators indicators={rule.exploit_indicators} />
</div>
)}
</div> </div>
))} ))}
</div> </div>
</div> </div>
); );
const ExploitIndicators = ({ indicators }) => {
try {
const parsed = JSON.parse(indicators);
return (
<div className="space-y-2">
{Object.entries(parsed).map(([category, items]) => (
items.length > 0 && (
<div key={category} className="flex flex-wrap items-center gap-2">
<span className="text-xs font-medium text-gray-600 capitalize min-w-0">
{category}:
</span>
<div className="flex flex-wrap gap-1">
{items.slice(0, 5).map((item, index) => (
<span
key={index}
className="inline-flex px-2 py-1 text-xs rounded bg-gray-200 text-gray-700 font-mono"
>
{typeof item === 'string' && item.length > 30 ? item.substring(0, 30) + '...' : item}
</span>
))}
{items.length > 5 && (
<span className="text-xs text-gray-500">+{items.length - 5} more</span>
)}
</div>
</div>
)
))}
</div>
);
} catch (e) {
return <p className="text-xs text-gray-500">Invalid indicator data</p>;
}
};
const CVEDetail = ({ cve, onClose }) => { const CVEDetail = ({ cve, onClose }) => {
const [cveRules, setCveRules] = useState([]); const [cveRules, setCveRules] = useState([]);
@ -393,8 +463,38 @@ function App() {
<span className="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-green-100 text-green-800"> <span className="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-green-100 text-green-800">
{rule.confidence_level} {rule.confidence_level}
</span> </span>
{rule.exploit_based && (
<span className="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-red-100 text-red-800">
🔍 Exploit-Based
</span>
)}
</div> </div>
</div> </div>
{rule.github_repos && rule.github_repos.length > 0 && (
<div className="mb-3 p-2 bg-blue-50 rounded">
<p className="text-xs text-blue-700 font-medium mb-1">
Based on GitHub exploit analysis:
</p>
<div className="flex flex-wrap gap-1">
{rule.github_repos.slice(0, 2).map((repo, index) => (
<a
key={index}
href={repo}
target="_blank"
rel="noopener noreferrer"
className="text-xs text-blue-600 hover:text-blue-800 underline"
>
{repo.split('/').slice(-2).join('/')}
</a>
))}
{rule.github_repos.length > 2 && (
<span className="text-xs text-blue-600">
+{rule.github_repos.length - 2} more
</span>
)}
</div>
</div>
)}
<SyntaxHighlighter <SyntaxHighlighter
language="yaml" language="yaml"
style={tomorrow} style={tomorrow}
@ -403,6 +503,12 @@ function App() {
> >
{rule.rule_content} {rule.rule_content}
</SyntaxHighlighter> </SyntaxHighlighter>
{rule.exploit_indicators && (
<div className="mt-3 p-2 bg-gray-50 rounded">
<p className="text-xs font-medium text-gray-700 mb-1">Exploit Indicators:</p>
<ExploitIndicators indicators={rule.exploit_indicators} />
</div>
)}
</div> </div>
))} ))}
</div> </div>

View file

@ -27,6 +27,9 @@ CREATE TABLE sigma_rules (
log_source VARCHAR(100), log_source VARCHAR(100),
confidence_level VARCHAR(20), confidence_level VARCHAR(20),
auto_generated BOOLEAN DEFAULT TRUE, auto_generated BOOLEAN DEFAULT TRUE,
exploit_based BOOLEAN DEFAULT FALSE,
github_repos TEXT[],
exploit_indicators TEXT,
created_at TIMESTAMP DEFAULT NOW(), created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW() updated_at TIMESTAMP DEFAULT NOW()
); );
@ -54,8 +57,7 @@ date: {date}
references: references:
- {cve_url} - {cve_url}
tags: tags:
- attack.execution - {tags}
- {cve_id}
logsource: logsource:
category: process_creation category: process_creation
product: windows product: windows
@ -80,8 +82,7 @@ date: {date}
references: references:
- {cve_url} - {cve_url}
tags: tags:
- attack.command_and_control - {tags}
- {cve_id}
logsource: logsource:
category: network_connection category: network_connection
product: windows product: windows
@ -107,8 +108,7 @@ date: {date}
references: references:
- {cve_url} - {cve_url}
tags: tags:
- attack.defense_evasion - {tags}
- {cve_id}
logsource: logsource:
category: file_event category: file_event
product: windows product: windows
@ -122,6 +122,31 @@ falsepositives:
level: {level}', level: {level}',
ARRAY['file', 'filesystem', 'modification'], ARRAY['file', 'filesystem', 'modification'],
'Template for file modification detection' 'Template for file modification detection'
),
(
'PowerShell Execution',
'title: {title}
description: {description}
id: {rule_id}
status: experimental
author: CVE-SIGMA Auto Generator
date: {date}
references:
- {cve_url}
tags:
- {tags}
logsource:
product: windows
category: ps_script
detection:
selection:
ScriptBlockText|contains: {suspicious_processes}
condition: selection
falsepositives:
- Legitimate PowerShell scripts
level: {level}',
ARRAY['powershell', 'script', 'ps1'],
'Template for PowerShell script execution detection'
); );
-- Create indexes -- Create indexes