Cleaner message format, add malware family extraction

This commit is contained in:
bot
2026-04-23 22:34:58 +03:00
parent e3307391c7
commit a9460cec07
2 changed files with 51 additions and 35 deletions
+36 -3
View File
@@ -84,9 +84,31 @@ class ContentClassifier:
'apt1', 'apt28', 'apt29', 'apt32', 'apt33', 'apt34', 'apt35', 'apt37', 'apt38', 'apt39', 'apt40', 'apt41',
'lazarus', 'kimsuky', 'andariel', 'fancy bear', 'cozy bear', 'sandworm',
'turla', 'equation group', 'carbanak', 'fin7', 'fin6', 'fin8',
'conti', 'lockbit', 'blackcat', 'alphv', 'cl0p', 'clop', 'revil', 'darkside',
'nobelium', 'hafnium', 'phosphorus', 'holmium', 'strontium',
'volt typhoon', 'flax typhoon', 'mustang panda', 'winnti'
'volt typhoon', 'flax typhoon', 'mustang panda', 'winnti',
'scattered spider', 'lapsus', 'lapsus$', 'unc2452', 'unc3944',
'ta505', 'ta577', 'ta558', 'gold southfield', 'gold dupont',
}
# Stored as display names; matched case-insensitively
MALWARE_FAMILIES = {
# Ransomware
'LockBit', 'REvil', 'BlackCat', 'ALPHV', 'Cl0p', 'Conti', 'DarkSide',
'Ryuk', 'BlackMatter', 'Akira', 'Black Basta', 'RansomHub', 'Rhysida',
'Medusa', 'Cactus', 'Play', 'Royal', 'Hive', 'Maze', '8Base',
'Hunters International', 'Inc Ransom', 'Monti', 'Nokoyawa',
# C2 frameworks / RATs
'Cobalt Strike', 'Mimikatz', 'Sliver', 'Brute Ratel', 'Havoc',
'AsyncRAT', 'Remcos', 'njRAT', 'NanoCore', 'XWorm', 'QuasarRAT',
'DarkComet', 'NetWire', 'Metasploit',
# Loaders / droppers
'Emotet', 'TrickBot', 'QakBot', 'IcedID', 'BazarLoader', 'Dridex',
'GootLoader', 'BumbleBee', 'PikaBot', 'DarkGate',
# Stealers
'AgentTesla', 'FormBook', 'RedLine', 'Vidar', 'Raccoon', 'Lumma',
'Rhadamanthys', 'StealC', 'Meduza', 'Aurora',
# APT tooling
'PlugX', 'ShadowPad', 'Gh0stRAT', 'PoisonIvy',
}
# MITRE ATT&CK technique pattern
@@ -125,6 +147,15 @@ class ContentClassifier:
found_actors.append(actor.upper())
return list(set(found_actors))
def extract_malware_families(self, text: str) -> List[str]:
"""Extract known malware family / tool names from text"""
text_lower = text.lower()
found = []
for family in self.MALWARE_FAMILIES:
if family.lower() in text_lower:
found.append(family)
return list(set(found))
def extract_iocs(self, text: str) -> Dict[str, List[str]]:
"""Extract Indicators of Compromise from text"""
iocs = {
@@ -285,6 +316,7 @@ class ContentClassifier:
cves = self.extract_cves(combined_text)
mitre_techniques = self.extract_mitre_techniques(combined_text)
threat_actors = self.extract_threat_actors(combined_text)
malware_families = self.extract_malware_families(combined_text)
iocs = self.extract_iocs(combined_text)
# Classify content type
@@ -306,13 +338,14 @@ class ContentClassifier:
article['cves'] = cves
article['mitre_techniques'] = mitre_techniques
article['threat_actors'] = threat_actors
article['malware_families'] = malware_families
article['iocs'] = iocs
# Log classification
logger.info(
f"Classified: {article['title'][:50]}... | "
f"Score: {quality_score} | Severity: {severity} | "
f"Types: {', '.join(classifications)} | CVEs: {len(cves)}"
f"CVEs: {len(cves)} | Actors: {len(threat_actors)} | Malware: {len(malware_families)}"
)
return article
+15 -32
View File
@@ -449,7 +449,6 @@ class RSSFeedManager:
@staticmethod
def format_telegram_message(article: Dict) -> Tuple[str, Optional[str]]:
"""Format article for Telegram message"""
# Category emoji mapping
category_emojis = {
'news': '📰',
'malware': '🦠',
@@ -459,48 +458,32 @@ class RSSFeedManager:
}
emoji = category_emojis.get(article.get('category', ''), '📰')
category_display = article.get('category', '').replace('_', ' ').title()
title = escape(article.get('title', 'No Title'))
description = escape(article.get('description', ''))
source = escape(article.get('source', 'Unknown Source'))
published_human = escape(article.get('published_human', 'Unknown'))
category_safe = escape(category_display)
url = escape(article.get('url', ''), quote=True)
severity = article.get('severity', 'unknown').lower()
quality_score = article.get('quality_score')
cves = article.get('cves', [])[:3]
classifications = article.get('classifications', [])[:3]
severity_emoji = {
'critical': '🚨',
'high': '🔴',
'medium': '🟠',
'low': '🟡',
}.get(severity, '')
severity_safe = escape(severity.upper())
cves = article.get('cves', [])[:5]
threat_actors = article.get('threat_actors', [])[:3]
malware_families = article.get('malware_families', [])[:3]
message = f"{emoji} <b>{title}</b>\n\n"
if description:
message += f"📋 {description}\n\n"
message += f"{description}\n\n"
message += f"📡 {source} · {published_human}\n"
message += f"🏷️ <b>Category:</b> {category_safe}\n"
message += f"📡 <b>Source:</b> {source}\n"
message += f"{severity_emoji} <b>Severity:</b> {severity_safe}\n"
if quality_score is not None:
message += f"⭐ <b>Quality:</b> {int(quality_score)}/100\n"
if classifications:
class_text = ", ".join(escape(c) for c in classifications)
message += f"🧠 <b>Type:</b> {class_text}\n"
if cves:
cve_text = ", ".join(escape(cve) for cve in cves)
message += f"🆔 <b>CVEs:</b> {cve_text}\n"
why_this_matters = RSSFeedManager.build_why_this_matters(article)
if why_this_matters:
message += f"🎯 <b>Why This Matters:</b> {escape(why_this_matters)}\n"
message += f"⏰ <b>Published:</b> {published_human}\n"
message += f"🔗 <b><a href=\"{url}\">Read Full Article</a></b>"
message += f"🆔 {', '.join(escape(c) for c in cves)}\n"
if threat_actors:
message += f"👤 {', '.join(escape(a.title()) for a in threat_actors)}\n"
if malware_families:
message += f"🦠 {', '.join(escape(f) for f in malware_families)}\n"
message += f"\n🔗 <a href=\"{url}\">Read Full Article</a>"
return message, article.get('thumbnail')