File size: 3,275 Bytes
34367da
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import 'dotenv/config';
import neo4j from 'neo4j-driver';
import * as path from 'path';
import { fileURLToPath } from 'url';

// SHIM: Define __dirname for ES Modules
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const RANSOMWATCH_FEED = 'https://raw.githubusercontent.com/joshhighet/ransomwatch/main/posts.json';

async function harvestDarkWeb() {
    console.log('🌑 Operation Dark Sentry: Initializing...');
    const uri = process.env.NEO4J_URI;
    const user = process.env.NEO4J_USER;
    const password = process.env.NEO4J_PASSWORD;

    if (!uri || !user || !password) {
        console.error('❌ ERROR: Missing Neo4j credentials');
        process.exit(1);
    }

    const driver = neo4j.driver(uri, neo4j.auth.basic(user, password));
    const session = driver.session();

    try {
        console.log('📡 Intercepting Ransomwatch feed...');
        const response = await fetch(RANSOMWATCH_FEED);
        if (!response.ok) throw new Error(`Failed to fetch feed: ${response.statusText}`);
        
        const allPosts = await response.json() as any[];
        console.log(`📦 Intercepted ${allPosts.length} leak posts.`);

        // Sort by date descending and take top 50
        const recentPosts = allPosts
            .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
            .slice(0, 50);

        console.log(`⚡ Processing ${recentPosts.length} most recent threats...`);

        let nodesCreated = 0;
        const groupCounts: Record<string, number> = {};

        for (const post of recentPosts) {
            // Data normalization
            const actorName = post.group_name || 'Unknown Actor';
            const victimTitle = post.post_title || 'Unknown Victim';
            const date = post.discovered || new Date().toISOString();
            
            groupCounts[actorName] = (groupCounts[actorName] || 0) + 1;

            await session.run(`

                MERGE (actor:ThreatActor {name: $actorName})

                ON CREATE SET actor.firstSeen = $date

                ON MATCH SET actor.lastSeen = $date

                

                MERGE (victim:Victim {name: $victimTitle})

                ON CREATE SET victim.discovered = $date

                

                MERGE (actor)-[r:TARGETED]->(victim)

                SET r.date = $date, r.source = 'ransomwatch'

            `, { actorName, victimTitle, date });
            
            nodesCreated++;
            if (nodesCreated % 10 === 0) process.stdout.write('.');
        }

        console.log(`\n✅ Intelligence Injection Complete. Processed ${nodesCreated} attacks.`);
        
        // Sort groups by activity
        const topGroups = Object.entries(groupCounts)
            .sort(([,a], [,b]) => b - a)
            .slice(0, 3);
            
        console.log('\n📊 Top Active Threat Actors (Recent Sample):');
        topGroups.forEach(([group, count]) => console.log(`- ${group}: ${count} victims`));

    } catch (error) {
        console.error('💥 Sentry Failure:', error);
    } finally {
        await session.close();
        await driver.close();
    }
}

harvestDarkWeb();