Standardize import ordering and code formatting

This commit is contained in:
pandaadir05
2025-11-20 14:25:44 +02:00
parent 34007d11c1
commit e44f58e308
14 changed files with 823 additions and 546 deletions

View File

@@ -1,10 +1,11 @@
use crate::{DetectionResult, ProcessInfo, ThreatLevel};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::{SystemTime, Duration};
use serde::{Serialize, Deserialize};
use crate::{DetectionResult, ThreatLevel, ProcessInfo};
use std::time::{Duration, SystemTime};
/// Threat Intelligence Integration Module
/// Provides real-time threat context and IOC matching
#[derive(Debug)]
pub struct ThreatIntelligence {
ioc_database: IocDatabase,
threat_feeds: Vec<ThreatFeed>,
@@ -81,6 +82,7 @@ pub struct Campaign {
pub iocs: Vec<String>,
}
#[derive(Debug)]
pub struct IocDatabase {
indicators: HashMap<String, IndicatorOfCompromise>,
hash_index: HashMap<String, Vec<String>>,
@@ -127,6 +129,7 @@ pub struct FrequencyRequirement {
pub time_window: Duration,
}
#[derive(Debug)]
pub struct ThreatFeed {
pub name: String,
pub url: String,
@@ -153,6 +156,7 @@ pub struct FeedCredential {
pub password: Option<String>,
}
#[derive(Debug)]
pub struct AttributionEngine {
threat_actors: HashMap<String, ThreatActor>,
campaigns: HashMap<String, Campaign>,
@@ -171,18 +175,32 @@ pub struct AttributionRule {
#[derive(Debug, Clone)]
pub enum AttributionCondition {
IocMatch { ioc_types: Vec<IocType>, min_matches: u32 },
TechniquePattern { techniques: Vec<String>, correlation: f32 },
TemporalPattern { time_windows: Vec<Duration>, frequency: u32 },
GeographicalIndicator { regions: Vec<String>, confidence: f32 },
IocMatch {
ioc_types: Vec<IocType>,
min_matches: u32,
},
TechniquePattern {
techniques: Vec<String>,
correlation: f32,
},
TemporalPattern {
time_windows: Vec<Duration>,
frequency: u32,
},
GeographicalIndicator {
regions: Vec<String>,
confidence: f32,
},
}
#[derive(Debug)]
pub struct SimilarityCalculator {
technique_weights: HashMap<String, f32>,
temporal_weights: HashMap<String, f32>,
behavioral_weights: HashMap<String, f32>,
}
#[derive(Debug)]
pub struct ReputationCache {
process_reputations: HashMap<String, ProcessReputation>,
ip_reputations: HashMap<String, IpReputation>,
@@ -311,7 +329,7 @@ impl ThreatIntelligence {
// Initialize with basic IOCs
self.load_default_iocs().await?;
Ok(())
}
@@ -321,7 +339,10 @@ impl ThreatIntelligence {
let mut risk_score = 0.0f32;
// Check process name against IOCs
if let Some(iocs) = self.ioc_database.lookup_process_name(&detection.process.name) {
if let Some(iocs) = self
.ioc_database
.lookup_process_name(&detection.process.name)
{
matched_iocs.extend(iocs);
}
@@ -349,8 +370,9 @@ impl ThreatIntelligence {
}
// Perform attribution analysis
let (threat_actor, campaign, attribution_confidence) =
self.attribution_engine.analyze_attribution(&matched_iocs, &detection.indicators);
let (threat_actor, campaign, attribution_confidence) = self
.attribution_engine
.analyze_attribution(&matched_iocs, &detection.indicators);
// Generate recommended actions
let recommended_actions = self.generate_recommendations(&matched_iocs, risk_score);
@@ -373,16 +395,19 @@ impl ThreatIntelligence {
/// Update all threat feeds
pub async fn update_threat_feeds(&mut self) -> Result<(), Box<dyn std::error::Error>> {
let mut updates = Vec::new();
for (idx, feed) in self.threat_feeds.iter().enumerate() {
if SystemTime::now().duration_since(feed.last_update).unwrap_or_default()
>= feed.update_interval {
if SystemTime::now()
.duration_since(feed.last_update)
.unwrap_or_default()
>= feed.update_interval
{
// Fetch data inline to avoid borrow issues
let iocs = Vec::new(); // Stub implementation
updates.push((idx, iocs));
}
}
for (idx, iocs) in updates {
self.ioc_database.update_indicators(iocs);
self.threat_feeds[idx].last_update = SystemTime::now();
@@ -391,7 +416,10 @@ impl ThreatIntelligence {
}
/// Fetch data from a threat feed
async fn fetch_feed_data(&self, feed: &ThreatFeed) -> Result<Vec<IndicatorOfCompromise>, Box<dyn std::error::Error>> {
async fn fetch_feed_data(
&self,
feed: &ThreatFeed,
) -> Result<Vec<IndicatorOfCompromise>, Box<dyn std::error::Error>> {
// Implementation would depend on feed type
match feed.feed_type {
FeedType::JSON => self.fetch_json_feed(feed).await,
@@ -401,19 +429,28 @@ impl ThreatIntelligence {
}
}
async fn fetch_json_feed(&self, feed: &ThreatFeed) -> Result<Vec<IndicatorOfCompromise>, Box<dyn std::error::Error>> {
async fn fetch_json_feed(
&self,
feed: &ThreatFeed,
) -> Result<Vec<IndicatorOfCompromise>, Box<dyn std::error::Error>> {
// Placeholder implementation
// In a real implementation, this would fetch from the feed URL
Ok(Vec::new())
}
async fn fetch_stix_feed(&self, feed: &ThreatFeed) -> Result<Vec<IndicatorOfCompromise>, Box<dyn std::error::Error>> {
async fn fetch_stix_feed(
&self,
feed: &ThreatFeed,
) -> Result<Vec<IndicatorOfCompromise>, Box<dyn std::error::Error>> {
// Placeholder implementation
// In a real implementation, this would parse STIX/TAXII data
Ok(Vec::new())
}
async fn fetch_csv_feed(&self, feed: &ThreatFeed) -> Result<Vec<IndicatorOfCompromise>, Box<dyn std::error::Error>> {
async fn fetch_csv_feed(
&self,
feed: &ThreatFeed,
) -> Result<Vec<IndicatorOfCompromise>, Box<dyn std::error::Error>> {
// Placeholder implementation
// In a real implementation, this would parse CSV threat data
Ok(Vec::new())
@@ -431,7 +468,10 @@ impl ThreatIntelligence {
confidence: 0.6,
created_date: SystemTime::now(),
expiry_date: None,
tags: vec!["process-injection".to_string(), "living-off-the-land".to_string()],
tags: vec![
"process-injection".to_string(),
"living-off-the-land".to_string(),
],
mitre_techniques: vec!["T1055".to_string()],
},
IndicatorOfCompromise {
@@ -467,7 +507,11 @@ impl ThreatIntelligence {
Ok(())
}
fn generate_recommendations(&self, iocs: &[IndicatorOfCompromise], risk_score: f32) -> Vec<String> {
fn generate_recommendations(
&self,
iocs: &[IndicatorOfCompromise],
risk_score: f32,
) -> Vec<String> {
let mut recommendations = Vec::new();
if risk_score > 0.8 {
@@ -487,9 +531,15 @@ impl ThreatIntelligence {
for ioc in iocs {
for technique in &ioc.mitre_techniques {
match technique.as_str() {
"T1055" => recommendations.push("Deploy process injection countermeasures".to_string()),
"T1055.001" => recommendations.push("Monitor DLL loading activities".to_string()),
"T1055.002" => recommendations.push("Implement PE injection detection".to_string()),
"T1055" => {
recommendations.push("Deploy process injection countermeasures".to_string())
}
"T1055.001" => {
recommendations.push("Monitor DLL loading activities".to_string())
}
"T1055.002" => {
recommendations.push("Implement PE injection detection".to_string())
}
_ => {}
}
}
@@ -518,12 +568,14 @@ impl IocDatabase {
// Update indexes for fast lookup
match ioc.ioc_type {
IocType::FileHash => {
self.hash_index.entry(ioc.value.clone())
self.hash_index
.entry(ioc.value.clone())
.or_insert_with(Vec::new)
.push(ioc.id.clone());
}
IocType::MemorySignature | IocType::BehaviorPattern => {
self.pattern_index.entry(ioc.value.clone())
self.pattern_index
.entry(ioc.value.clone())
.or_insert_with(Vec::new)
.push(ioc.id.clone());
}
@@ -532,23 +584,33 @@ impl IocDatabase {
}
pub fn lookup_process_name(&self, name: &str) -> Option<Vec<IndicatorOfCompromise>> {
let matches: Vec<_> = self.indicators
let matches: Vec<_> = self
.indicators
.values()
.filter(|ioc| ioc.ioc_type == IocType::ProcessName && ioc.value == name)
.cloned()
.collect();
if matches.is_empty() { None } else { Some(matches) }
if matches.is_empty() {
None
} else {
Some(matches)
}
}
pub fn lookup_process_path(&self, path: &str) -> Option<Vec<IndicatorOfCompromise>> {
let matches: Vec<_> = self.indicators
let matches: Vec<_> = self
.indicators
.values()
.filter(|ioc| ioc.ioc_type == IocType::ProcessPath && path.contains(&ioc.value))
.cloned()
.collect();
if matches.is_empty() { None } else { Some(matches) }
if matches.is_empty() {
None
} else {
Some(matches)
}
}
pub fn lookup_memory_signature(&self, signature: &str) -> Option<Vec<IndicatorOfCompromise>> {
@@ -558,7 +620,11 @@ impl IocDatabase {
.filter_map(|id| self.indicators.get(id))
.cloned()
.collect();
if matches.is_empty() { None } else { Some(matches) }
if matches.is_empty() {
None
} else {
Some(matches)
}
} else {
None
}
@@ -581,9 +647,11 @@ impl AttributionEngine {
}
}
pub fn analyze_attribution(&self, iocs: &[IndicatorOfCompromise], indicators: &[String])
-> (Option<ThreatActor>, Option<Campaign>, f32) {
pub fn analyze_attribution(
&self,
iocs: &[IndicatorOfCompromise],
indicators: &[String],
) -> (Option<ThreatActor>, Option<Campaign>, f32) {
let mut best_actor: Option<ThreatActor> = None;
let mut best_campaign: Option<Campaign> = None;
let mut best_confidence = 0.0f32;
@@ -591,7 +659,7 @@ impl AttributionEngine {
// Analyze each attribution rule
for rule in &self.attribution_rules {
let confidence = self.evaluate_attribution_rule(rule, iocs, indicators);
if confidence > best_confidence {
best_confidence = confidence;
if let Some(actor) = self.threat_actors.get(&rule.threat_actor) {
@@ -608,29 +676,40 @@ impl AttributionEngine {
(best_actor, best_campaign, best_confidence)
}
fn evaluate_attribution_rule(&self, rule: &AttributionRule,
iocs: &[IndicatorOfCompromise],
indicators: &[String]) -> f32 {
fn evaluate_attribution_rule(
&self,
rule: &AttributionRule,
iocs: &[IndicatorOfCompromise],
indicators: &[String],
) -> f32 {
let mut total_confidence = 0.0f32;
let mut condition_count = 0;
for condition in &rule.conditions {
match condition {
AttributionCondition::IocMatch { ioc_types, min_matches } => {
let matches = iocs.iter()
AttributionCondition::IocMatch {
ioc_types,
min_matches,
} => {
let matches = iocs
.iter()
.filter(|ioc| ioc_types.contains(&ioc.ioc_type))
.count() as u32;
if matches >= *min_matches {
total_confidence += rule.confidence_weight;
}
}
AttributionCondition::TechniquePattern { techniques, correlation } => {
let technique_matches = iocs.iter()
AttributionCondition::TechniquePattern {
techniques,
correlation,
} => {
let technique_matches = iocs
.iter()
.flat_map(|ioc| &ioc.mitre_techniques)
.filter(|tech| techniques.contains(tech))
.count();
if technique_matches as f32 / techniques.len() as f32 >= *correlation {
total_confidence += rule.confidence_weight;
}
@@ -667,4 +746,4 @@ impl ReputationCache {
cache_ttl: Duration::from_secs(3600), // 1 hour
}
}
}
}