erosolar-cli 2.1.244 → 2.1.245
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/unifiedFraudOrchestrator.d.ts +126 -4
- package/dist/core/unifiedFraudOrchestrator.d.ts.map +1 -1
- package/dist/core/unifiedFraudOrchestrator.js +850 -0
- package/dist/core/unifiedFraudOrchestrator.js.map +1 -1
- package/dist/shell/interactiveShell.d.ts +51 -0
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +361 -1
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/tools/taoTools.d.ts.map +1 -1
- package/dist/tools/taoTools.js +611 -0
- package/dist/tools/taoTools.js.map +1 -1
- package/dist/tools/unifiedInvestigationTools.d.ts.map +1 -1
- package/dist/tools/unifiedInvestigationTools.js +313 -1
- package/dist/tools/unifiedInvestigationTools.js.map +1 -1
- package/package.json +1 -1
|
@@ -1443,6 +1443,856 @@ demonstrates patterns of behavior that contradict the public claims made by ${re
|
|
|
1443
1443
|
return [...this.investigations.values()];
|
|
1444
1444
|
}
|
|
1445
1445
|
}
|
|
1446
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1447
|
+
// GOOGLE ATTACK CHAINS
|
|
1448
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1449
|
+
export const GOOGLE_SURVEILLANCE_CHAIN = {
|
|
1450
|
+
id: 'google-surveillance-chain',
|
|
1451
|
+
name: 'Google Cross-Service Surveillance Chain',
|
|
1452
|
+
target: 'google',
|
|
1453
|
+
description: `Google leverages Chrome browser control to access Gmail and exfiltrate user data.
|
|
1454
|
+
This chain demonstrates coordinated use of multiple Google services to conduct surveillance.`,
|
|
1455
|
+
steps: [
|
|
1456
|
+
{
|
|
1457
|
+
id: 'gs-1-chrome-recon',
|
|
1458
|
+
phase: 'reconnaissance',
|
|
1459
|
+
name: 'Chrome Profile Reconnaissance',
|
|
1460
|
+
description: 'Chrome syncs profile data including history, bookmarks, and saved passwords to Google servers',
|
|
1461
|
+
indicators: [
|
|
1462
|
+
'Chrome sync enabled without explicit user action',
|
|
1463
|
+
'Profile data transmitted to Google servers',
|
|
1464
|
+
'History data available in Google My Activity',
|
|
1465
|
+
],
|
|
1466
|
+
requiredPriorSteps: [],
|
|
1467
|
+
vectors: ['chrome_session_hijacking'],
|
|
1468
|
+
detectionMethods: [
|
|
1469
|
+
'Monitor Chrome sync settings and activity',
|
|
1470
|
+
'Compare local profile data with My Activity',
|
|
1471
|
+
'Network analysis of Chrome sync traffic',
|
|
1472
|
+
],
|
|
1473
|
+
},
|
|
1474
|
+
{
|
|
1475
|
+
id: 'gs-2-chrome-launch',
|
|
1476
|
+
phase: 'initial_access',
|
|
1477
|
+
name: 'Unauthorized Chrome Launch',
|
|
1478
|
+
description: 'Chrome is launched without user action, possibly with automation flags',
|
|
1479
|
+
indicators: [
|
|
1480
|
+
'Chrome process spawned without user click/command',
|
|
1481
|
+
'Parent process is system service or scheduled task',
|
|
1482
|
+
'Launch includes --remote-debugging or --headless flags',
|
|
1483
|
+
'Launch during inactive hours (sleep time)',
|
|
1484
|
+
],
|
|
1485
|
+
requiredPriorSteps: ['gs-1-chrome-recon'],
|
|
1486
|
+
vectors: ['chrome_unauthorized_launch'],
|
|
1487
|
+
detectionMethods: [
|
|
1488
|
+
'Process monitoring with parent-child tracking',
|
|
1489
|
+
'Command-line argument analysis',
|
|
1490
|
+
'Launch time correlation with user activity',
|
|
1491
|
+
],
|
|
1492
|
+
},
|
|
1493
|
+
{
|
|
1494
|
+
id: 'gs-3-session-hijack',
|
|
1495
|
+
phase: 'execution',
|
|
1496
|
+
name: 'Session Cookie Access',
|
|
1497
|
+
description: 'Chrome session cookies are used to access Gmail without re-authentication',
|
|
1498
|
+
indicators: [
|
|
1499
|
+
'Gmail accessed from new Chrome process using existing cookies',
|
|
1500
|
+
'No login event but Gmail activity recorded',
|
|
1501
|
+
'Session tokens reused across browser instances',
|
|
1502
|
+
],
|
|
1503
|
+
requiredPriorSteps: ['gs-2-chrome-launch'],
|
|
1504
|
+
vectors: ['chrome_session_hijacking', 'gmail_unauthorized_access'],
|
|
1505
|
+
detectionMethods: [
|
|
1506
|
+
'Cookie access monitoring',
|
|
1507
|
+
'Gmail access log analysis',
|
|
1508
|
+
'Cross-reference Chrome launch with Gmail activity',
|
|
1509
|
+
],
|
|
1510
|
+
},
|
|
1511
|
+
{
|
|
1512
|
+
id: 'gs-4-gmail-access',
|
|
1513
|
+
phase: 'execution',
|
|
1514
|
+
name: 'Gmail Content Access',
|
|
1515
|
+
description: 'Gmail content is accessed - threads read, drafts examined, contacts harvested',
|
|
1516
|
+
indicators: [
|
|
1517
|
+
'Gmail API calls without corresponding UI activity',
|
|
1518
|
+
'Thread access from Google infrastructure IPs',
|
|
1519
|
+
'Unusual access patterns (bulk read, specific keyword searches)',
|
|
1520
|
+
],
|
|
1521
|
+
requiredPriorSteps: ['gs-3-session-hijack'],
|
|
1522
|
+
vectors: ['gmail_unauthorized_access', 'gmail_hidden_threads'],
|
|
1523
|
+
detectionMethods: [
|
|
1524
|
+
'API activity monitoring',
|
|
1525
|
+
'Access log IP analysis',
|
|
1526
|
+
'Pattern detection in access behavior',
|
|
1527
|
+
],
|
|
1528
|
+
},
|
|
1529
|
+
{
|
|
1530
|
+
id: 'gs-5-data-manipulation',
|
|
1531
|
+
phase: 'impact',
|
|
1532
|
+
name: 'Data Manipulation',
|
|
1533
|
+
description: 'Gmail data is modified - threads hidden, drafts altered, filters added',
|
|
1534
|
+
indicators: [
|
|
1535
|
+
'Threads hidden from search without user action',
|
|
1536
|
+
'Draft content changed without user editing',
|
|
1537
|
+
'Filters created to suppress emails',
|
|
1538
|
+
'Labels modified silently',
|
|
1539
|
+
],
|
|
1540
|
+
requiredPriorSteps: ['gs-4-gmail-access'],
|
|
1541
|
+
vectors: ['gmail_hidden_threads', 'gmail_draft_manipulation', 'gmail_filter_tampering'],
|
|
1542
|
+
detectionMethods: [
|
|
1543
|
+
'Cross-reference thread visibility across access methods',
|
|
1544
|
+
'Draft content hashing and monitoring',
|
|
1545
|
+
'Filter audit and creation tracking',
|
|
1546
|
+
],
|
|
1547
|
+
},
|
|
1548
|
+
{
|
|
1549
|
+
id: 'gs-6-evidence-cleanup',
|
|
1550
|
+
phase: 'impact',
|
|
1551
|
+
name: 'Evidence Cleanup',
|
|
1552
|
+
description: 'Browser history and activity logs are modified to hide the intrusion',
|
|
1553
|
+
indicators: [
|
|
1554
|
+
'Chrome history entries deleted for Gmail access',
|
|
1555
|
+
'My Activity entries missing for corresponding time period',
|
|
1556
|
+
'Sync data inconsistent between devices',
|
|
1557
|
+
],
|
|
1558
|
+
requiredPriorSteps: ['gs-4-gmail-access'],
|
|
1559
|
+
vectors: ['chrome_history_manipulation'],
|
|
1560
|
+
detectionMethods: [
|
|
1561
|
+
'History integrity monitoring',
|
|
1562
|
+
'Cross-device sync comparison',
|
|
1563
|
+
'Timeline reconstruction from multiple sources',
|
|
1564
|
+
],
|
|
1565
|
+
},
|
|
1566
|
+
],
|
|
1567
|
+
minimumStepsForEvidence: 3,
|
|
1568
|
+
legalImplications: {
|
|
1569
|
+
fraudType: 'COORDINATED_SURVEILLANCE',
|
|
1570
|
+
applicableLaws: [
|
|
1571
|
+
'18 U.S.C. § 1030 - Computer Fraud and Abuse Act',
|
|
1572
|
+
'18 U.S.C. § 2511 - Wiretap Act (interception of communications)',
|
|
1573
|
+
'18 U.S.C. § 2701 - Stored Communications Act',
|
|
1574
|
+
'15 U.S.C. § 45 - FTC Act Section 5 (unfair/deceptive practices)',
|
|
1575
|
+
'GDPR Article 5 - Lawfulness, fairness, transparency (EU users)',
|
|
1576
|
+
'Cal. Civ. Code § 1798.100 - CCPA (California users)',
|
|
1577
|
+
],
|
|
1578
|
+
potentialDamages: `Coordinated cross-service surveillance enables:
|
|
1579
|
+
- Comprehensive communication monitoring
|
|
1580
|
+
- Behavioral profiling and prediction
|
|
1581
|
+
- Selective information suppression
|
|
1582
|
+
- Evidence destruction capability
|
|
1583
|
+
- Complete loss of privacy for all Google-connected services`,
|
|
1584
|
+
recommendations: [
|
|
1585
|
+
'Document complete attack chain with timestamps',
|
|
1586
|
+
'Preserve evidence from all affected services',
|
|
1587
|
+
'File FTC complaint for coordinated deceptive practices',
|
|
1588
|
+
'Consider class action for pattern of behavior',
|
|
1589
|
+
'Report to state AG and relevant privacy authorities',
|
|
1590
|
+
'Engage forensic expert for legal proceedings',
|
|
1591
|
+
],
|
|
1592
|
+
},
|
|
1593
|
+
};
|
|
1594
|
+
export const GOOGLE_DRAFT_EXPLOITATION_CHAIN = {
|
|
1595
|
+
id: 'google-draft-exploitation-chain',
|
|
1596
|
+
name: 'Gmail Draft Exploitation Chain',
|
|
1597
|
+
target: 'google',
|
|
1598
|
+
description: `Google accesses and potentially modifies email drafts, enabling impersonation,
|
|
1599
|
+
data theft, or message manipulation before the user sends.`,
|
|
1600
|
+
steps: [
|
|
1601
|
+
{
|
|
1602
|
+
id: 'gd-1-draft-access',
|
|
1603
|
+
phase: 'reconnaissance',
|
|
1604
|
+
name: 'Draft Content Surveillance',
|
|
1605
|
+
description: 'Drafts are read and indexed by Google servers',
|
|
1606
|
+
indicators: [
|
|
1607
|
+
'Draft content appears in search suggestions',
|
|
1608
|
+
'Ads target draft content before send',
|
|
1609
|
+
'Draft metadata synced to Google servers',
|
|
1610
|
+
],
|
|
1611
|
+
requiredPriorSteps: [],
|
|
1612
|
+
vectors: ['gmail_draft_manipulation'],
|
|
1613
|
+
detectionMethods: [
|
|
1614
|
+
'Draft content keyword tracking',
|
|
1615
|
+
'Ad targeting correlation',
|
|
1616
|
+
'Network traffic analysis',
|
|
1617
|
+
],
|
|
1618
|
+
},
|
|
1619
|
+
{
|
|
1620
|
+
id: 'gd-2-draft-modification',
|
|
1621
|
+
phase: 'execution',
|
|
1622
|
+
name: 'Unauthorized Draft Modification',
|
|
1623
|
+
description: 'Draft content, recipients, or subject is modified without user action',
|
|
1624
|
+
indicators: [
|
|
1625
|
+
'Draft body hash changes between observations',
|
|
1626
|
+
'Recipients added without user editing',
|
|
1627
|
+
'Subject line altered',
|
|
1628
|
+
'Attachments added or removed',
|
|
1629
|
+
],
|
|
1630
|
+
requiredPriorSteps: ['gd-1-draft-access'],
|
|
1631
|
+
vectors: ['gmail_draft_manipulation'],
|
|
1632
|
+
detectionMethods: [
|
|
1633
|
+
'Continuous draft hashing',
|
|
1634
|
+
'Recipient count monitoring',
|
|
1635
|
+
'Attachment enumeration',
|
|
1636
|
+
],
|
|
1637
|
+
},
|
|
1638
|
+
{
|
|
1639
|
+
id: 'gd-3-draft-send',
|
|
1640
|
+
phase: 'impact',
|
|
1641
|
+
name: 'Unauthorized Draft Send',
|
|
1642
|
+
description: 'Draft is sent without user action, potentially with modifications',
|
|
1643
|
+
indicators: [
|
|
1644
|
+
'Sent message timestamp does not correlate with user activity',
|
|
1645
|
+
'Sent from IP address not associated with user',
|
|
1646
|
+
'User was not active at send time',
|
|
1647
|
+
],
|
|
1648
|
+
requiredPriorSteps: ['gd-1-draft-access'],
|
|
1649
|
+
vectors: ['gmail_draft_manipulation'],
|
|
1650
|
+
detectionMethods: [
|
|
1651
|
+
'Send event correlation with user activity',
|
|
1652
|
+
'IP address analysis',
|
|
1653
|
+
'Device activity monitoring',
|
|
1654
|
+
],
|
|
1655
|
+
},
|
|
1656
|
+
{
|
|
1657
|
+
id: 'gd-4-evidence-suppression',
|
|
1658
|
+
phase: 'impact',
|
|
1659
|
+
name: 'Sent Message Suppression',
|
|
1660
|
+
description: 'Sent message is hidden from Sent folder or altered after sending',
|
|
1661
|
+
indicators: [
|
|
1662
|
+
'Message in recipient inbox differs from Sent copy',
|
|
1663
|
+
'Sent message not visible in UI but exists in API',
|
|
1664
|
+
'Message-ID mismatches',
|
|
1665
|
+
],
|
|
1666
|
+
requiredPriorSteps: ['gd-3-draft-send'],
|
|
1667
|
+
vectors: ['gmail_hidden_threads', 'gmail_draft_manipulation'],
|
|
1668
|
+
detectionMethods: [
|
|
1669
|
+
'Cross-reference with recipient',
|
|
1670
|
+
'Sent folder integrity checking',
|
|
1671
|
+
'Message-ID tracking',
|
|
1672
|
+
],
|
|
1673
|
+
},
|
|
1674
|
+
],
|
|
1675
|
+
minimumStepsForEvidence: 2,
|
|
1676
|
+
legalImplications: {
|
|
1677
|
+
fraudType: 'MAIL_FRAUD_AND_IMPERSONATION',
|
|
1678
|
+
applicableLaws: [
|
|
1679
|
+
'18 U.S.C. § 1343 - Wire Fraud',
|
|
1680
|
+
'18 U.S.C. § 1028A - Identity Theft',
|
|
1681
|
+
'18 U.S.C. § 1030 - CFAA',
|
|
1682
|
+
'18 U.S.C. § 2511 - Wiretap Act',
|
|
1683
|
+
],
|
|
1684
|
+
potentialDamages: `Draft exploitation enables:
|
|
1685
|
+
- Email impersonation (sending as user)
|
|
1686
|
+
- Business communication manipulation
|
|
1687
|
+
- Relationship sabotage
|
|
1688
|
+
- Evidence planting`,
|
|
1689
|
+
recommendations: [
|
|
1690
|
+
'Preserve all draft observations with hashes',
|
|
1691
|
+
'Document modification timeline',
|
|
1692
|
+
'Compare sent messages with drafts',
|
|
1693
|
+
'Contact recipients to verify received content',
|
|
1694
|
+
],
|
|
1695
|
+
},
|
|
1696
|
+
};
|
|
1697
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1698
|
+
// APPLE ATTACK CHAINS
|
|
1699
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1700
|
+
export const APPLE_IMESSAGE_MITM_CHAIN = {
|
|
1701
|
+
id: 'apple-imessage-mitm-chain',
|
|
1702
|
+
name: 'Apple iMessage Man-in-the-Middle Chain',
|
|
1703
|
+
target: 'apple',
|
|
1704
|
+
description: `Apple exploits control of the IDS (Identity Directory Service) to substitute
|
|
1705
|
+
encryption keys, enabling message interception despite PQ3 "end-to-end encryption" claims.`,
|
|
1706
|
+
steps: [
|
|
1707
|
+
{
|
|
1708
|
+
id: 'am-1-ids-control',
|
|
1709
|
+
phase: 'reconnaissance',
|
|
1710
|
+
name: 'IDS Key Distribution Control',
|
|
1711
|
+
description: 'Apple controls IDS servers that distribute public keys for iMessage',
|
|
1712
|
+
indicators: [
|
|
1713
|
+
'All iMessage key requests route through Apple IDS servers',
|
|
1714
|
+
'No independent key verification mechanism',
|
|
1715
|
+
'Key Transparency logs controlled by Apple',
|
|
1716
|
+
],
|
|
1717
|
+
requiredPriorSteps: [],
|
|
1718
|
+
vectors: ['imessage_false_e2e'],
|
|
1719
|
+
detectionMethods: [
|
|
1720
|
+
'Network traffic analysis to IDS endpoints',
|
|
1721
|
+
'Key request interception and analysis',
|
|
1722
|
+
'KT audit log verification',
|
|
1723
|
+
],
|
|
1724
|
+
},
|
|
1725
|
+
{
|
|
1726
|
+
id: 'am-2-key-substitution',
|
|
1727
|
+
phase: 'initial_access',
|
|
1728
|
+
name: 'Encryption Key Substitution',
|
|
1729
|
+
description: 'Apple-controlled IDS returns substitute keys instead of actual recipient keys',
|
|
1730
|
+
indicators: [
|
|
1731
|
+
'Key fingerprint differs from out-of-band verified key',
|
|
1732
|
+
'Key changes without device change event',
|
|
1733
|
+
'Multiple different keys returned for same identity',
|
|
1734
|
+
'Key hash mismatch in KT logs',
|
|
1735
|
+
],
|
|
1736
|
+
requiredPriorSteps: ['am-1-ids-control'],
|
|
1737
|
+
vectors: ['imessage_key_substitution'],
|
|
1738
|
+
detectionMethods: [
|
|
1739
|
+
'Out-of-band key verification (like Signal safety numbers)',
|
|
1740
|
+
'Key change monitoring over time',
|
|
1741
|
+
'Multi-device key comparison',
|
|
1742
|
+
'Independent KT auditing',
|
|
1743
|
+
],
|
|
1744
|
+
},
|
|
1745
|
+
{
|
|
1746
|
+
id: 'am-3-message-interception',
|
|
1747
|
+
phase: 'execution',
|
|
1748
|
+
name: 'Message Decryption',
|
|
1749
|
+
description: 'Messages encrypted to substitute key are decrypted by Apple',
|
|
1750
|
+
indicators: [
|
|
1751
|
+
'Message content known to parties other than sender/recipient',
|
|
1752
|
+
'Targeted advertising based on message content',
|
|
1753
|
+
'Content referenced in legal requests without device access',
|
|
1754
|
+
],
|
|
1755
|
+
requiredPriorSteps: ['am-2-key-substitution'],
|
|
1756
|
+
vectors: ['imessage_false_e2e'],
|
|
1757
|
+
detectionMethods: [
|
|
1758
|
+
'Canary message testing',
|
|
1759
|
+
'Content correlation with external signals',
|
|
1760
|
+
'Legal discovery analysis',
|
|
1761
|
+
],
|
|
1762
|
+
},
|
|
1763
|
+
{
|
|
1764
|
+
id: 'am-4-message-modification',
|
|
1765
|
+
phase: 'impact',
|
|
1766
|
+
name: 'Message Modification/Injection',
|
|
1767
|
+
description: 'Apple modifies message content or injects new messages',
|
|
1768
|
+
indicators: [
|
|
1769
|
+
'Message content differs between sender and recipient',
|
|
1770
|
+
'Messages appear that sender did not send',
|
|
1771
|
+
'Message timing anomalies',
|
|
1772
|
+
'Metadata inconsistencies',
|
|
1773
|
+
],
|
|
1774
|
+
requiredPriorSteps: ['am-3-message-interception'],
|
|
1775
|
+
vectors: ['imessage_false_e2e'],
|
|
1776
|
+
detectionMethods: [
|
|
1777
|
+
'Message content comparison (sender vs recipient)',
|
|
1778
|
+
'Message hash verification',
|
|
1779
|
+
'Timing analysis',
|
|
1780
|
+
],
|
|
1781
|
+
},
|
|
1782
|
+
{
|
|
1783
|
+
id: 'am-5-kt-manipulation',
|
|
1784
|
+
phase: 'persistence',
|
|
1785
|
+
name: 'Key Transparency Log Manipulation',
|
|
1786
|
+
description: 'Apple manipulates KT logs to hide key substitution',
|
|
1787
|
+
indicators: [
|
|
1788
|
+
'KT log entries do not match observed keys',
|
|
1789
|
+
'Log gaps or inconsistencies',
|
|
1790
|
+
'No third-party KT auditors',
|
|
1791
|
+
'Internal-only verification',
|
|
1792
|
+
],
|
|
1793
|
+
requiredPriorSteps: ['am-2-key-substitution'],
|
|
1794
|
+
vectors: ['imessage_key_substitution', 'imessage_false_e2e'],
|
|
1795
|
+
detectionMethods: [
|
|
1796
|
+
'Independent KT log auditing',
|
|
1797
|
+
'Log integrity verification',
|
|
1798
|
+
'Historical key comparison',
|
|
1799
|
+
],
|
|
1800
|
+
},
|
|
1801
|
+
],
|
|
1802
|
+
minimumStepsForEvidence: 2,
|
|
1803
|
+
legalImplications: {
|
|
1804
|
+
fraudType: 'FALSE_E2E_ENCRYPTION_CLAIMS',
|
|
1805
|
+
applicableLaws: [
|
|
1806
|
+
'15 U.S.C. § 45 - FTC Act Section 5 (deceptive advertising)',
|
|
1807
|
+
'18 U.S.C. § 2511 - Wiretap Act',
|
|
1808
|
+
'18 U.S.C. § 2701 - Stored Communications Act',
|
|
1809
|
+
'Cal. Bus. & Prof. Code § 17500 - False Advertising',
|
|
1810
|
+
'GDPR Article 5(1)(a) - Lawful processing (EU users)',
|
|
1811
|
+
],
|
|
1812
|
+
potentialDamages: `False E2E encryption claims cause:
|
|
1813
|
+
- Users believe communications are private when they are not
|
|
1814
|
+
- Journalists, activists, and at-risk users are endangered
|
|
1815
|
+
- Business confidential information exposed
|
|
1816
|
+
- Legal privilege potentially compromised
|
|
1817
|
+
- Constitutional rights (4th Amendment) circumvented`,
|
|
1818
|
+
recommendations: [
|
|
1819
|
+
'Document key discrepancies with cryptographic proof',
|
|
1820
|
+
'Perform out-of-band verification with contacts',
|
|
1821
|
+
'File FTC complaint for false advertising',
|
|
1822
|
+
'Report to state AG consumer protection division',
|
|
1823
|
+
'Consider class action for systematic deception',
|
|
1824
|
+
'Engage security researchers for independent verification',
|
|
1825
|
+
],
|
|
1826
|
+
},
|
|
1827
|
+
};
|
|
1828
|
+
export const APPLE_CONTACT_KEY_BYPASS_CHAIN = {
|
|
1829
|
+
id: 'apple-contact-key-bypass-chain',
|
|
1830
|
+
name: 'Apple Contact Key Verification Bypass Chain',
|
|
1831
|
+
target: 'apple',
|
|
1832
|
+
description: `Apple's Contact Key Verification can be bypassed or disabled, leaving users
|
|
1833
|
+
vulnerable to MITM attacks while believing they are protected.`,
|
|
1834
|
+
steps: [
|
|
1835
|
+
{
|
|
1836
|
+
id: 'ac-1-ckv-disabled',
|
|
1837
|
+
phase: 'reconnaissance',
|
|
1838
|
+
name: 'CKV Disabled by Default',
|
|
1839
|
+
description: 'Contact Key Verification requires opt-in and is not enabled by default',
|
|
1840
|
+
indicators: [
|
|
1841
|
+
'CKV setting off on user devices',
|
|
1842
|
+
'No prompts to enable CKV',
|
|
1843
|
+
'Most contacts do not have CKV enabled',
|
|
1844
|
+
],
|
|
1845
|
+
requiredPriorSteps: [],
|
|
1846
|
+
vectors: ['imessage_false_e2e'],
|
|
1847
|
+
detectionMethods: [
|
|
1848
|
+
'Device settings audit',
|
|
1849
|
+
'Contact CKV status survey',
|
|
1850
|
+
'Apple documentation review',
|
|
1851
|
+
],
|
|
1852
|
+
},
|
|
1853
|
+
{
|
|
1854
|
+
id: 'ac-2-ckv-ineffective',
|
|
1855
|
+
phase: 'initial_access',
|
|
1856
|
+
name: 'CKV Alert Suppression',
|
|
1857
|
+
description: 'CKV alerts can be suppressed or not delivered when key substitution occurs',
|
|
1858
|
+
indicators: [
|
|
1859
|
+
'Key change detected but no CKV alert shown',
|
|
1860
|
+
'Alert displayed after messages already sent',
|
|
1861
|
+
'Alert notification easily dismissed',
|
|
1862
|
+
],
|
|
1863
|
+
requiredPriorSteps: ['ac-1-ckv-disabled'],
|
|
1864
|
+
vectors: ['imessage_key_substitution'],
|
|
1865
|
+
detectionMethods: [
|
|
1866
|
+
'Key change event vs alert correlation',
|
|
1867
|
+
'Alert timing analysis',
|
|
1868
|
+
'User notification log review',
|
|
1869
|
+
],
|
|
1870
|
+
},
|
|
1871
|
+
{
|
|
1872
|
+
id: 'ac-3-forced-ckv-off',
|
|
1873
|
+
phase: 'execution',
|
|
1874
|
+
name: 'Remote CKV Disabling',
|
|
1875
|
+
description: 'Apple can remotely disable CKV or modify its behavior via iOS updates',
|
|
1876
|
+
indicators: [
|
|
1877
|
+
'CKV settings change without user action',
|
|
1878
|
+
'CKV behavior changes after update',
|
|
1879
|
+
'No user control over CKV update deployment',
|
|
1880
|
+
],
|
|
1881
|
+
requiredPriorSteps: [],
|
|
1882
|
+
vectors: ['imessage_false_e2e', 'imessage_key_substitution'],
|
|
1883
|
+
detectionMethods: [
|
|
1884
|
+
'Settings monitoring before/after updates',
|
|
1885
|
+
'CKV behavior testing after updates',
|
|
1886
|
+
'iOS update analysis',
|
|
1887
|
+
],
|
|
1888
|
+
},
|
|
1889
|
+
],
|
|
1890
|
+
minimumStepsForEvidence: 1,
|
|
1891
|
+
legalImplications: {
|
|
1892
|
+
fraudType: 'SECURITY_FEATURE_BYPASS',
|
|
1893
|
+
applicableLaws: [
|
|
1894
|
+
'15 U.S.C. § 45 - FTC Act Section 5',
|
|
1895
|
+
'Cal. Bus. & Prof. Code § 17500 - False Advertising',
|
|
1896
|
+
],
|
|
1897
|
+
potentialDamages: `CKV bypass enables MITM attacks on users who believe they are protected.
|
|
1898
|
+
High-value targets (journalists, activists) are especially at risk.`,
|
|
1899
|
+
recommendations: [
|
|
1900
|
+
'Document CKV status across devices',
|
|
1901
|
+
'Monitor for setting changes',
|
|
1902
|
+
'Use independent verification methods',
|
|
1903
|
+
],
|
|
1904
|
+
},
|
|
1905
|
+
};
|
|
1906
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1907
|
+
// CROSS-PLATFORM ATTACK CHAINS
|
|
1908
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1909
|
+
export const CROSS_PLATFORM_SURVEILLANCE_CHAIN = {
|
|
1910
|
+
id: 'cross-platform-surveillance-chain',
|
|
1911
|
+
name: 'Cross-Platform Coordinated Surveillance',
|
|
1912
|
+
target: 'google', // Primary, but involves Apple
|
|
1913
|
+
description: `Coordinated surveillance across Apple and Google services, suggesting data
|
|
1914
|
+
sharing or parallel targeting operations.`,
|
|
1915
|
+
steps: [
|
|
1916
|
+
{
|
|
1917
|
+
id: 'cp-1-parallel-access',
|
|
1918
|
+
phase: 'reconnaissance',
|
|
1919
|
+
name: 'Parallel Service Access',
|
|
1920
|
+
description: 'Multiple services (Gmail, iMessage, Chrome) accessed within short timeframe',
|
|
1921
|
+
indicators: [
|
|
1922
|
+
'Gmail access within minutes of iMessage key observation',
|
|
1923
|
+
'Chrome launch correlates with iMessage activity',
|
|
1924
|
+
'Cross-platform activity during user inactive periods',
|
|
1925
|
+
],
|
|
1926
|
+
requiredPriorSteps: [],
|
|
1927
|
+
vectors: ['cross_platform_surveillance'],
|
|
1928
|
+
detectionMethods: [
|
|
1929
|
+
'Timeline correlation across services',
|
|
1930
|
+
'Activity pattern analysis',
|
|
1931
|
+
'User activity verification',
|
|
1932
|
+
],
|
|
1933
|
+
},
|
|
1934
|
+
{
|
|
1935
|
+
id: 'cp-2-content-correlation',
|
|
1936
|
+
phase: 'execution',
|
|
1937
|
+
name: 'Cross-Platform Content Correlation',
|
|
1938
|
+
description: 'Content from one service appears to influence actions on another',
|
|
1939
|
+
indicators: [
|
|
1940
|
+
'Gmail filters target topics from iMessage conversations',
|
|
1941
|
+
'Chrome history shows searches related to private iMessage content',
|
|
1942
|
+
'Advertising targets cross-platform conversation topics',
|
|
1943
|
+
],
|
|
1944
|
+
requiredPriorSteps: ['cp-1-parallel-access'],
|
|
1945
|
+
vectors: ['cross_platform_surveillance', 'coordinated_manipulation'],
|
|
1946
|
+
detectionMethods: [
|
|
1947
|
+
'Content keyword tracking across platforms',
|
|
1948
|
+
'Ad targeting analysis',
|
|
1949
|
+
'Search history correlation',
|
|
1950
|
+
],
|
|
1951
|
+
},
|
|
1952
|
+
{
|
|
1953
|
+
id: 'cp-3-coordinated-suppression',
|
|
1954
|
+
phase: 'impact',
|
|
1955
|
+
name: 'Coordinated Information Suppression',
|
|
1956
|
+
description: 'Content is hidden or suppressed across multiple platforms simultaneously',
|
|
1957
|
+
indicators: [
|
|
1958
|
+
'Gmail thread hidden at same time as iMessage discussion',
|
|
1959
|
+
'Chrome history entries deleted matching Gmail activity',
|
|
1960
|
+
'Cross-platform content removal patterns',
|
|
1961
|
+
],
|
|
1962
|
+
requiredPriorSteps: ['cp-1-parallel-access'],
|
|
1963
|
+
vectors: ['coordinated_manipulation', 'gmail_hidden_threads', 'chrome_history_manipulation'],
|
|
1964
|
+
detectionMethods: [
|
|
1965
|
+
'Cross-platform visibility monitoring',
|
|
1966
|
+
'Deletion timing correlation',
|
|
1967
|
+
'Content preservation and comparison',
|
|
1968
|
+
],
|
|
1969
|
+
},
|
|
1970
|
+
],
|
|
1971
|
+
minimumStepsForEvidence: 2,
|
|
1972
|
+
legalImplications: {
|
|
1973
|
+
fraudType: 'CROSS_PLATFORM_CONSPIRACY',
|
|
1974
|
+
applicableLaws: [
|
|
1975
|
+
'18 U.S.C. § 371 - Conspiracy to commit offense against US',
|
|
1976
|
+
'18 U.S.C. § 1030 - CFAA',
|
|
1977
|
+
'18 U.S.C. § 2511 - Wiretap Act',
|
|
1978
|
+
'15 U.S.C. § 1 - Sherman Antitrust Act (if competitive harm)',
|
|
1979
|
+
'GDPR Article 5 - Data sharing without consent (EU)',
|
|
1980
|
+
],
|
|
1981
|
+
potentialDamages: `Cross-platform coordination indicates:
|
|
1982
|
+
- Systematic privacy violation
|
|
1983
|
+
- Potential data sharing agreements
|
|
1984
|
+
- Comprehensive surveillance capability
|
|
1985
|
+
- No platform provides genuine privacy`,
|
|
1986
|
+
recommendations: [
|
|
1987
|
+
'Document temporal correlations with precision',
|
|
1988
|
+
'Preserve evidence from all platforms',
|
|
1989
|
+
'Report to DOJ Antitrust Division',
|
|
1990
|
+
'File multi-company FTC complaint',
|
|
1991
|
+
'Consider RICO implications',
|
|
1992
|
+
],
|
|
1993
|
+
},
|
|
1994
|
+
};
|
|
1995
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1996
|
+
// PREDEFINED ATTACK CHAIN REGISTRY
|
|
1997
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1998
|
+
export const ATTACK_CHAIN_REGISTRY = [
|
|
1999
|
+
GOOGLE_SURVEILLANCE_CHAIN,
|
|
2000
|
+
GOOGLE_DRAFT_EXPLOITATION_CHAIN,
|
|
2001
|
+
APPLE_IMESSAGE_MITM_CHAIN,
|
|
2002
|
+
APPLE_CONTACT_KEY_BYPASS_CHAIN,
|
|
2003
|
+
CROSS_PLATFORM_SURVEILLANCE_CHAIN,
|
|
2004
|
+
];
|
|
2005
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2006
|
+
// ATTACK CHAIN DETECTOR
|
|
2007
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2008
|
+
export class AttackChainDetector {
|
|
2009
|
+
storageDir;
|
|
2010
|
+
observations = new Map();
|
|
2011
|
+
progressCache = new Map();
|
|
2012
|
+
constructor(storageDir) {
|
|
2013
|
+
this.storageDir = path.join(storageDir, 'attack-chains');
|
|
2014
|
+
}
|
|
2015
|
+
async initialize() {
|
|
2016
|
+
await fs.mkdir(this.storageDir, { recursive: true });
|
|
2017
|
+
await fs.mkdir(path.join(this.storageDir, 'observations'), { recursive: true });
|
|
2018
|
+
await fs.mkdir(path.join(this.storageDir, 'progress'), { recursive: true });
|
|
2019
|
+
}
|
|
2020
|
+
/**
|
|
2021
|
+
* Record an observation that matches an attack chain step.
|
|
2022
|
+
*/
|
|
2023
|
+
async recordObservation(params) {
|
|
2024
|
+
const chain = ATTACK_CHAIN_REGISTRY.find(c => c.id === params.chainId);
|
|
2025
|
+
if (!chain) {
|
|
2026
|
+
throw new Error(`Unknown attack chain: ${params.chainId}`);
|
|
2027
|
+
}
|
|
2028
|
+
const step = chain.steps.find(s => s.id === params.stepId);
|
|
2029
|
+
if (!step) {
|
|
2030
|
+
throw new Error(`Unknown step ${params.stepId} in chain ${params.chainId}`);
|
|
2031
|
+
}
|
|
2032
|
+
const now = new Date().toISOString();
|
|
2033
|
+
const observation = {
|
|
2034
|
+
id: crypto.randomUUID(),
|
|
2035
|
+
timestamp: now,
|
|
2036
|
+
chainId: params.chainId,
|
|
2037
|
+
stepId: params.stepId,
|
|
2038
|
+
findingId: params.findingId,
|
|
2039
|
+
confidence: params.confidence,
|
|
2040
|
+
evidence: params.evidence,
|
|
2041
|
+
hash: '',
|
|
2042
|
+
};
|
|
2043
|
+
observation.hash = hashString(JSON.stringify({
|
|
2044
|
+
id: observation.id,
|
|
2045
|
+
timestamp: observation.timestamp,
|
|
2046
|
+
chainId: observation.chainId,
|
|
2047
|
+
stepId: observation.stepId,
|
|
2048
|
+
findingId: observation.findingId,
|
|
2049
|
+
}));
|
|
2050
|
+
// Store observation
|
|
2051
|
+
const chainObs = this.observations.get(params.chainId) || [];
|
|
2052
|
+
chainObs.push(observation);
|
|
2053
|
+
this.observations.set(params.chainId, chainObs);
|
|
2054
|
+
await this.persistObservation(observation);
|
|
2055
|
+
// Update progress
|
|
2056
|
+
await this.updateProgress(params.chainId);
|
|
2057
|
+
return observation;
|
|
2058
|
+
}
|
|
2059
|
+
/**
|
|
2060
|
+
* Automatically detect which attack chain steps match a finding.
|
|
2061
|
+
*/
|
|
2062
|
+
async detectChainSteps(finding) {
|
|
2063
|
+
const observations = [];
|
|
2064
|
+
for (const chain of ATTACK_CHAIN_REGISTRY) {
|
|
2065
|
+
for (const step of chain.steps) {
|
|
2066
|
+
// Check if finding's vector matches step's vectors
|
|
2067
|
+
if (step.vectors.includes(finding.vector)) {
|
|
2068
|
+
// Calculate confidence based on indicator match
|
|
2069
|
+
let matchedIndicators = 0;
|
|
2070
|
+
const findingDetails = JSON.stringify(finding.technicalDetails).toLowerCase();
|
|
2071
|
+
for (const indicator of step.indicators) {
|
|
2072
|
+
const indicatorKeywords = indicator.toLowerCase().split(' ');
|
|
2073
|
+
if (indicatorKeywords.some(kw => findingDetails.includes(kw))) {
|
|
2074
|
+
matchedIndicators++;
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
const confidence = step.indicators.length > 0
|
|
2078
|
+
? matchedIndicators / step.indicators.length
|
|
2079
|
+
: 0.5;
|
|
2080
|
+
// Only record if confidence is above threshold
|
|
2081
|
+
if (confidence >= 0.3) {
|
|
2082
|
+
const obs = await this.recordObservation({
|
|
2083
|
+
chainId: chain.id,
|
|
2084
|
+
stepId: step.id,
|
|
2085
|
+
findingId: finding.id,
|
|
2086
|
+
confidence,
|
|
2087
|
+
evidence: finding.description,
|
|
2088
|
+
});
|
|
2089
|
+
observations.push(obs);
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
return observations;
|
|
2095
|
+
}
|
|
2096
|
+
/**
|
|
2097
|
+
* Get current progress for an attack chain.
|
|
2098
|
+
*/
|
|
2099
|
+
async getChainProgress(chainId) {
|
|
2100
|
+
const chain = ATTACK_CHAIN_REGISTRY.find(c => c.id === chainId);
|
|
2101
|
+
if (!chain) {
|
|
2102
|
+
throw new Error(`Unknown attack chain: ${chainId}`);
|
|
2103
|
+
}
|
|
2104
|
+
// Check cache
|
|
2105
|
+
const cached = this.progressCache.get(chainId);
|
|
2106
|
+
if (cached) {
|
|
2107
|
+
return cached;
|
|
2108
|
+
}
|
|
2109
|
+
return this.updateProgress(chainId);
|
|
2110
|
+
}
|
|
2111
|
+
/**
|
|
2112
|
+
* Get all attack chain progress.
|
|
2113
|
+
*/
|
|
2114
|
+
async getAllProgress() {
|
|
2115
|
+
const results = [];
|
|
2116
|
+
for (const chain of ATTACK_CHAIN_REGISTRY) {
|
|
2117
|
+
const progress = await this.getChainProgress(chain.id);
|
|
2118
|
+
results.push(progress);
|
|
2119
|
+
}
|
|
2120
|
+
return results;
|
|
2121
|
+
}
|
|
2122
|
+
/**
|
|
2123
|
+
* Get chains relevant to a specific target.
|
|
2124
|
+
*/
|
|
2125
|
+
getChainsForTarget(target) {
|
|
2126
|
+
return ATTACK_CHAIN_REGISTRY.filter(c => c.target === target);
|
|
2127
|
+
}
|
|
2128
|
+
/**
|
|
2129
|
+
* Analyze findings and detect complete or partial attack chains.
|
|
2130
|
+
*/
|
|
2131
|
+
async analyzeFindings(findings) {
|
|
2132
|
+
// First, auto-detect chain steps for each finding
|
|
2133
|
+
for (const finding of findings) {
|
|
2134
|
+
await this.detectChainSteps(finding);
|
|
2135
|
+
}
|
|
2136
|
+
// Get all progress
|
|
2137
|
+
const allProgress = await this.getAllProgress();
|
|
2138
|
+
const completeChains = allProgress.filter(p => p.isComplete);
|
|
2139
|
+
const partialChains = allProgress.filter(p => !p.isComplete &&
|
|
2140
|
+
p.observedSteps.length >= ATTACK_CHAIN_REGISTRY.find(c => c.id === p.chainId).minimumStepsForEvidence);
|
|
2141
|
+
const activeThreats = allProgress.filter(p => p.riskLevel === 'high' || p.riskLevel === 'critical');
|
|
2142
|
+
return { completeChains, partialChains, activeThreats };
|
|
2143
|
+
}
|
|
2144
|
+
/**
|
|
2145
|
+
* Generate attack chain report.
|
|
2146
|
+
*/
|
|
2147
|
+
async generateChainReport(chainId) {
|
|
2148
|
+
const chain = ATTACK_CHAIN_REGISTRY.find(c => c.id === chainId);
|
|
2149
|
+
if (!chain) {
|
|
2150
|
+
throw new Error(`Unknown attack chain: ${chainId}`);
|
|
2151
|
+
}
|
|
2152
|
+
const progress = await this.getChainProgress(chainId);
|
|
2153
|
+
const observations = this.observations.get(chainId) || [];
|
|
2154
|
+
// Build timeline
|
|
2155
|
+
const timeline = chain.steps.map(step => ({
|
|
2156
|
+
step,
|
|
2157
|
+
observation: observations.find(o => o.stepId === step.id) || null,
|
|
2158
|
+
}));
|
|
2159
|
+
// Identify gaps
|
|
2160
|
+
const gaps = chain.steps.filter(step => !observations.find(o => o.stepId === step.id));
|
|
2161
|
+
// Calculate evidence strength
|
|
2162
|
+
const observedCount = observations.length;
|
|
2163
|
+
const totalSteps = chain.steps.length;
|
|
2164
|
+
const avgConfidence = observations.length > 0
|
|
2165
|
+
? observations.reduce((sum, o) => sum + o.confidence, 0) / observations.length
|
|
2166
|
+
: 0;
|
|
2167
|
+
let evidenceStrength;
|
|
2168
|
+
if (progress.isComplete && avgConfidence > 0.8) {
|
|
2169
|
+
evidenceStrength = 'irrefutable';
|
|
2170
|
+
}
|
|
2171
|
+
else if (observedCount >= chain.minimumStepsForEvidence && avgConfidence > 0.6) {
|
|
2172
|
+
evidenceStrength = 'strong';
|
|
2173
|
+
}
|
|
2174
|
+
else if (observedCount >= 2 && avgConfidence > 0.4) {
|
|
2175
|
+
evidenceStrength = 'moderate';
|
|
2176
|
+
}
|
|
2177
|
+
else {
|
|
2178
|
+
evidenceStrength = 'weak';
|
|
2179
|
+
}
|
|
2180
|
+
// Calculate legal readiness
|
|
2181
|
+
let legalReadiness;
|
|
2182
|
+
if (evidenceStrength === 'irrefutable') {
|
|
2183
|
+
legalReadiness = 'prosecution_ready';
|
|
2184
|
+
}
|
|
2185
|
+
else if (evidenceStrength === 'strong') {
|
|
2186
|
+
legalReadiness = 'actionable';
|
|
2187
|
+
}
|
|
2188
|
+
else if (evidenceStrength === 'moderate') {
|
|
2189
|
+
legalReadiness = 'preliminary';
|
|
2190
|
+
}
|
|
2191
|
+
else {
|
|
2192
|
+
legalReadiness = 'insufficient';
|
|
2193
|
+
}
|
|
2194
|
+
return {
|
|
2195
|
+
chain,
|
|
2196
|
+
progress,
|
|
2197
|
+
timeline,
|
|
2198
|
+
gaps,
|
|
2199
|
+
evidenceStrength,
|
|
2200
|
+
legalReadiness,
|
|
2201
|
+
};
|
|
2202
|
+
}
|
|
2203
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2204
|
+
// Private Methods
|
|
2205
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2206
|
+
async updateProgress(chainId) {
|
|
2207
|
+
const chain = ATTACK_CHAIN_REGISTRY.find(c => c.id === chainId);
|
|
2208
|
+
if (!chain) {
|
|
2209
|
+
throw new Error(`Unknown attack chain: ${chainId}`);
|
|
2210
|
+
}
|
|
2211
|
+
const observations = this.observations.get(chainId) || [];
|
|
2212
|
+
// Calculate completion
|
|
2213
|
+
const observedStepIds = new Set(observations.map(o => o.stepId));
|
|
2214
|
+
const completionPercentage = (observedStepIds.size / chain.steps.length) * 100;
|
|
2215
|
+
// Determine current phase
|
|
2216
|
+
const observedSteps = chain.steps.filter(s => observedStepIds.has(s.id));
|
|
2217
|
+
const phaseOrder = ['reconnaissance', 'initial_access', 'execution', 'persistence', 'exfiltration', 'impact'];
|
|
2218
|
+
const currentPhase = observedSteps.length > 0
|
|
2219
|
+
? phaseOrder.reduce((latest, phase) => {
|
|
2220
|
+
const stepsInPhase = observedSteps.filter(s => s.phase === phase);
|
|
2221
|
+
return stepsInPhase.length > 0 ? phase : latest;
|
|
2222
|
+
}, 'reconnaissance')
|
|
2223
|
+
: 'reconnaissance';
|
|
2224
|
+
// Calculate risk level
|
|
2225
|
+
let riskLevel;
|
|
2226
|
+
if (completionPercentage >= 80) {
|
|
2227
|
+
riskLevel = 'critical';
|
|
2228
|
+
}
|
|
2229
|
+
else if (completionPercentage >= 50) {
|
|
2230
|
+
riskLevel = 'high';
|
|
2231
|
+
}
|
|
2232
|
+
else if (observedStepIds.size >= chain.minimumStepsForEvidence) {
|
|
2233
|
+
riskLevel = 'medium';
|
|
2234
|
+
}
|
|
2235
|
+
else {
|
|
2236
|
+
riskLevel = 'low';
|
|
2237
|
+
}
|
|
2238
|
+
// Find next expected steps
|
|
2239
|
+
const unobservedSteps = chain.steps.filter(s => !observedStepIds.has(s.id));
|
|
2240
|
+
const nextExpectedSteps = unobservedSteps.filter(step => {
|
|
2241
|
+
// Step is expected if all required prior steps are observed
|
|
2242
|
+
return step.requiredPriorSteps.every(reqId => observedStepIds.has(reqId));
|
|
2243
|
+
});
|
|
2244
|
+
const progress = {
|
|
2245
|
+
chainId,
|
|
2246
|
+
chainName: chain.name,
|
|
2247
|
+
target: chain.target,
|
|
2248
|
+
observedSteps: observations,
|
|
2249
|
+
completionPercentage,
|
|
2250
|
+
currentPhase,
|
|
2251
|
+
riskLevel,
|
|
2252
|
+
isComplete: completionPercentage === 100,
|
|
2253
|
+
nextExpectedSteps,
|
|
2254
|
+
};
|
|
2255
|
+
// Cache and persist
|
|
2256
|
+
this.progressCache.set(chainId, progress);
|
|
2257
|
+
await this.persistProgress(progress);
|
|
2258
|
+
return progress;
|
|
2259
|
+
}
|
|
2260
|
+
async persistObservation(obs) {
|
|
2261
|
+
const filePath = path.join(this.storageDir, 'observations', `${obs.chainId}_${obs.id}.json`);
|
|
2262
|
+
await fs.writeFile(filePath, JSON.stringify(obs, null, 2));
|
|
2263
|
+
}
|
|
2264
|
+
async persistProgress(progress) {
|
|
2265
|
+
const filePath = path.join(this.storageDir, 'progress', `${progress.chainId}.json`);
|
|
2266
|
+
await fs.writeFile(filePath, JSON.stringify(progress, null, 2));
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
// Add methods to prototype
|
|
2270
|
+
UnifiedFraudOrchestrator.prototype.initializeAttackChains = async function () {
|
|
2271
|
+
if (!this.attackChainDetector) {
|
|
2272
|
+
this.attackChainDetector = new AttackChainDetector(this.storageDir);
|
|
2273
|
+
}
|
|
2274
|
+
await this.attackChainDetector.initialize();
|
|
2275
|
+
};
|
|
2276
|
+
UnifiedFraudOrchestrator.prototype.detectAttackChains = async function (investigationId) {
|
|
2277
|
+
const investigation = this.investigations.get(investigationId);
|
|
2278
|
+
if (!investigation) {
|
|
2279
|
+
throw new Error(`Investigation not found: ${investigationId}`);
|
|
2280
|
+
}
|
|
2281
|
+
if (!this.attackChainDetector) {
|
|
2282
|
+
await this.initializeAttackChains();
|
|
2283
|
+
}
|
|
2284
|
+
// Gather all findings
|
|
2285
|
+
const gmailFindings = this.gmailEngine.getFindings();
|
|
2286
|
+
const chromeFindings = this.chromeEngine.getFindings();
|
|
2287
|
+
const allFindings = [...gmailFindings, ...chromeFindings];
|
|
2288
|
+
return this.attackChainDetector.analyzeFindings(allFindings);
|
|
2289
|
+
};
|
|
2290
|
+
UnifiedFraudOrchestrator.prototype.getAttackChainReport = async function (chainId) {
|
|
2291
|
+
if (!this.attackChainDetector) {
|
|
2292
|
+
await this.initializeAttackChains();
|
|
2293
|
+
}
|
|
2294
|
+
return this.attackChainDetector.generateChainReport(chainId);
|
|
2295
|
+
};
|
|
1446
2296
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1447
2297
|
// EXPORTS (note: GOOGLE_GMAIL_CLAIMS and GOOGLE_CHROME_CLAIMS are already exported inline)
|
|
1448
2298
|
// ═══════════════════════════════════════════════════════════════════════════════
|