@iocium/ioc-diff
Version:
A full-featured, ESM-compatible IOC diffing and normalization library + CLI for InfoSec tooling.
98 lines (85 loc) • 2.24 kB
text/typescript
import { diffIOCs } from '../src/diffIOCs';
import type { IOC } from '../src/types';
// Sample YARA rule content
const yaraOld = `
rule MaliciousExample {
strings:
$a = "evil.com"
$b = "bad.com"
condition:
any of them
}
`;
const yaraNew = `
rule MaliciousExample {
strings:
$a = "evil.com"
$b = "worse.com"
condition:
any of them
}
`;
// Simulate basic YARA parser logic from CLI
function parseYara(raw: string): IOC[] {
const iocs: IOC[] = [];
const lines = raw.split(/\r?\n/);
for (const line of lines) {
const match = line.match(/\$[\w_]+\s*=\s*"([^"]+)"/);
if (match) {
iocs.push({ value: match[1], type: 'string', source: 'yara' });
}
}
return iocs;
}
// Sample Sigma rule content
const sigmaOld = `
title: Suspicious Domain Access
detection:
selection:
domain: evil.com
condition: selection
`;
const sigmaNew = `
title: Suspicious Domain Access
detection:
selection:
domain: evil.com
alt: worse.com
condition: selection
`;
import yaml from 'js-yaml';
function parseSigma(raw: string): IOC[] {
const doc = yaml.load(raw);
const detection = (doc as any)?.detection ?? {};
const iocs: IOC[] = [];
for (const val of Object.values(detection)) {
if (typeof val === 'object' && !Array.isArray(val)) {
for (const sub of Object.values(val)) {
if (typeof sub === 'string') {
iocs.push({ value: sub, type: 'string', source: 'sigma' });
}
}
}
}
return iocs;
}
describe('Sigma and YARA IOC diffing', () => {
it('detects changes in YARA rules', () => {
const oldIOCs = parseYara(yaraOld);
const newIOCs = parseYara(yaraNew);
const diff = diffIOCs(oldIOCs, newIOCs, {
matchBy: 'value',
});
expect(diff.added.map(i => i.value)).toContain('worse.com');
expect(diff.removed.map(i => i.value)).toContain('bad.com');
});
it('detects added IOCs in Sigma rules', () => {
const oldIOCs = parseSigma(sigmaOld);
const newIOCs = parseSigma(sigmaNew);
const diff = diffIOCs(oldIOCs, newIOCs, {
matchBy: 'value',
});
expect(diff.added.map(i => i.value)).toContain('worse.com');
expect(diff.removed).toEqual([]); // 'evil.com' remains
});
});