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', 'apt1', 'apt28', 'apt29', 'apt32', 'apt33', 'apt34', 'apt35', 'apt37', 'apt38', 'apt39', 'apt40', 'apt41',
'lazarus', 'kimsuky', 'andariel', 'fancy bear', 'cozy bear', 'sandworm', 'lazarus', 'kimsuky', 'andariel', 'fancy bear', 'cozy bear', 'sandworm',
'turla', 'equation group', 'carbanak', 'fin7', 'fin6', 'fin8', 'turla', 'equation group', 'carbanak', 'fin7', 'fin6', 'fin8',
'conti', 'lockbit', 'blackcat', 'alphv', 'cl0p', 'clop', 'revil', 'darkside',
'nobelium', 'hafnium', 'phosphorus', 'holmium', 'strontium', '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 # MITRE ATT&CK technique pattern
@@ -125,6 +147,15 @@ class ContentClassifier:
found_actors.append(actor.upper()) found_actors.append(actor.upper())
return list(set(found_actors)) 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]]: def extract_iocs(self, text: str) -> Dict[str, List[str]]:
"""Extract Indicators of Compromise from text""" """Extract Indicators of Compromise from text"""
iocs = { iocs = {
@@ -285,6 +316,7 @@ class ContentClassifier:
cves = self.extract_cves(combined_text) cves = self.extract_cves(combined_text)
mitre_techniques = self.extract_mitre_techniques(combined_text) mitre_techniques = self.extract_mitre_techniques(combined_text)
threat_actors = self.extract_threat_actors(combined_text) threat_actors = self.extract_threat_actors(combined_text)
malware_families = self.extract_malware_families(combined_text)
iocs = self.extract_iocs(combined_text) iocs = self.extract_iocs(combined_text)
# Classify content type # Classify content type
@@ -306,13 +338,14 @@ class ContentClassifier:
article['cves'] = cves article['cves'] = cves
article['mitre_techniques'] = mitre_techniques article['mitre_techniques'] = mitre_techniques
article['threat_actors'] = threat_actors article['threat_actors'] = threat_actors
article['malware_families'] = malware_families
article['iocs'] = iocs article['iocs'] = iocs
# Log classification # Log classification
logger.info( logger.info(
f"Classified: {article['title'][:50]}... | " f"Classified: {article['title'][:50]}... | "
f"Score: {quality_score} | Severity: {severity} | " 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 return article
+15 -32
View File
@@ -449,7 +449,6 @@ class RSSFeedManager:
@staticmethod @staticmethod
def format_telegram_message(article: Dict) -> Tuple[str, Optional[str]]: def format_telegram_message(article: Dict) -> Tuple[str, Optional[str]]:
"""Format article for Telegram message""" """Format article for Telegram message"""
# Category emoji mapping
category_emojis = { category_emojis = {
'news': '📰', 'news': '📰',
'malware': '🦠', 'malware': '🦠',
@@ -459,48 +458,32 @@ class RSSFeedManager:
} }
emoji = category_emojis.get(article.get('category', ''), '📰') emoji = category_emojis.get(article.get('category', ''), '📰')
category_display = article.get('category', '').replace('_', ' ').title()
title = escape(article.get('title', 'No Title')) title = escape(article.get('title', 'No Title'))
description = escape(article.get('description', '')) description = escape(article.get('description', ''))
source = escape(article.get('source', 'Unknown Source')) source = escape(article.get('source', 'Unknown Source'))
published_human = escape(article.get('published_human', 'Unknown')) published_human = escape(article.get('published_human', 'Unknown'))
category_safe = escape(category_display)
url = escape(article.get('url', ''), quote=True) url = escape(article.get('url', ''), quote=True)
severity = article.get('severity', 'unknown').lower() cves = article.get('cves', [])[:5]
quality_score = article.get('quality_score') threat_actors = article.get('threat_actors', [])[:3]
cves = article.get('cves', [])[:3] malware_families = article.get('malware_families', [])[:3]
classifications = article.get('classifications', [])[:3]
severity_emoji = {
'critical': '🚨',
'high': '🔴',
'medium': '🟠',
'low': '🟡',
}.get(severity, '')
severity_safe = escape(severity.upper())
message = f"{emoji} <b>{title}</b>\n\n" message = f"{emoji} <b>{title}</b>\n\n"
if description: 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: if cves:
cve_text = ", ".join(escape(cve) for cve in cves) message += f"🆔 {', '.join(escape(c) for c in cves)}\n"
message += f"🆔 <b>CVEs:</b> {cve_text}\n"
why_this_matters = RSSFeedManager.build_why_this_matters(article) if threat_actors:
if why_this_matters: message += f"👤 {', '.join(escape(a.title()) for a in threat_actors)}\n"
message += f"🎯 <b>Why This Matters:</b> {escape(why_this_matters)}\n"
message += f"⏰ <b>Published:</b> {published_human}\n" if malware_families:
message += f"🔗 <b><a href=\"{url}\">Read Full Article</a></b>" 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') return message, article.get('thumbnail')