Unlink scripts submodule and commit contents as normal directory
This commit is contained in:
1 parent
4f7dea111f
commit
6488b3ea85
48 files changed
+2876
-1
No files matched your search
@@ -0,0 +1,271 @@
|
||||
const { FLAGS, createFlagCollection } = require('../flags.js');
|
||||
const logIpToFile = require('../logIpToFile.js');
|
||||
const tailFile = require('../services/tailFile.js');
|
||||
const logger = require('../logger.js');
|
||||
const resolvePath = require('../pathResolver.js');
|
||||
const { COWRIE_LOG_FILE, SERVER_ID } = require('../../config.js').MAIN;
|
||||
|
||||
const LOG_FILE = resolvePath(COWRIE_LOG_FILE);
|
||||
const REPORT_DELAY = SERVER_ID === 'development' ? 30 * 1000 : 10 * 60 * 1000;
|
||||
|
||||
const CREDS_LIMIT = 885;
|
||||
const ipBuffers = new Map();
|
||||
|
||||
const extractSessionData = sessions => {
|
||||
const commands = [];
|
||||
const flags = createFlagCollection();
|
||||
|
||||
const credsSet = new Set();
|
||||
const fingerprints = new Set();
|
||||
const uploads = new Set();
|
||||
const tunnels = new Set();
|
||||
|
||||
let dpt = null, proto = null, sshVersion = null, timestamp = null;
|
||||
const downloadUrls = new Set();
|
||||
|
||||
for (const s of sessions) {
|
||||
dpt ??= s.dpt;
|
||||
proto ??= s.proto;
|
||||
sshVersion ??= s.sshVersion;
|
||||
timestamp ??= s.timestamp;
|
||||
|
||||
s.credentials?.forEach((_, cred) => credsSet.add(cred));
|
||||
commands.push(...s.commands);
|
||||
|
||||
if (s.fingerprint) fingerprints.add(s.fingerprint);
|
||||
if (s.uploads) s.uploads.forEach(f => uploads.add(f));
|
||||
if (s.tunnels) s.tunnels.forEach(t => tunnels.add(t));
|
||||
if (s.download?.url) {
|
||||
flags.add(FLAGS.WEB_APP_ATTACK);
|
||||
downloadUrls.add(s.download.url);
|
||||
}
|
||||
}
|
||||
|
||||
const creds = [...credsSet];
|
||||
const loginAttempts = creds.length;
|
||||
const cmdCount = commands.length;
|
||||
|
||||
if (loginAttempts >= 2) flags.add(FLAGS.BRUTE_FORCE);
|
||||
if (proto === 'ssh') flags.add(FLAGS.SSH);
|
||||
if (proto === 'telnet') flags.add(FLAGS.TELNET);
|
||||
if (cmdCount) flags.add(FLAGS.EMAIL);
|
||||
if (!loginAttempts && !cmdCount) flags.add(FLAGS.PORT_SCAN);
|
||||
|
||||
return {
|
||||
dpt, proto, sshVersion, timestamp, creds, commands,
|
||||
categories: flags.toString(),
|
||||
downloadUrls: [...downloadUrls],
|
||||
fingerprints: [...fingerprints],
|
||||
uploads: [...uploads],
|
||||
tunnels: [...tunnels],
|
||||
};
|
||||
};
|
||||
|
||||
const buildComment = ({ serverId, dpt, proto, creds, commands, sshVersion, downloadUrls, fingerprints, uploads, tunnels }, full = false) => {
|
||||
const loginAttempts = creds.length;
|
||||
const cmdCount = commands.length;
|
||||
const lines = [];
|
||||
|
||||
lines.push(`Honeypot ${serverId ? `[${serverId}]` : 'hit'}: ${loginAttempts ? 'Brute-force attack' : 'Unauthorized connection attempt'} detected on ${dpt}/${proto.toUpperCase()}`);
|
||||
|
||||
if (loginAttempts === 1) {
|
||||
lines.push(`• Credential used: ${creds[0]}`);
|
||||
} else if (loginAttempts > 1) {
|
||||
let joined = creds.join(', ');
|
||||
if (!full && joined.length > CREDS_LIMIT) joined = joined.slice(0, CREDS_LIMIT).replace(/,[^,]*$/, '') + '...';
|
||||
lines.push(`• Credentials: ${joined}`);
|
||||
}
|
||||
|
||||
if (loginAttempts) lines.push(`• Number of login attempts: ${loginAttempts}`);
|
||||
if (cmdCount) lines.push(`• ${cmdCount} command(s) were executed during the session`);
|
||||
if (sshVersion) lines.push(`• Client: ${sshVersion}`);
|
||||
if (downloadUrls.length) lines.push(`• Suspicious file URLs: ${downloadUrls.join(', ')}`);
|
||||
if (fingerprints.length) lines.push(`• SSH key fingerprints: ${fingerprints.join(', ')}`);
|
||||
if (uploads.length) lines.push(`• Uploaded files: ${uploads.join(', ')}`);
|
||||
if (tunnels.length) lines.push(`• TCP tunnels: ${tunnels.join(', ')}`);
|
||||
|
||||
return lines.join('\n');
|
||||
};
|
||||
|
||||
const flushBuffer = async (srcIp, reportIp) => {
|
||||
const buffer = ipBuffers.get(srcIp);
|
||||
if (!buffer) return;
|
||||
|
||||
clearTimeout(buffer.timer);
|
||||
ipBuffers.delete(srcIp);
|
||||
|
||||
const sessions = buffer.sessions || [];
|
||||
if (!sessions.length) return;
|
||||
|
||||
const {
|
||||
dpt, proto, sshVersion, timestamp, creds, commands,
|
||||
categories, downloadUrls, fingerprints, uploads, tunnels,
|
||||
} = extractSessionData(sessions);
|
||||
|
||||
if (!srcIp || !dpt || !proto) {
|
||||
return logger.warn(`COWRIE -> Incomplete data for ${srcIp}, discarded`);
|
||||
}
|
||||
|
||||
const shortComment = buildComment({ serverId: SERVER_ID, dpt, proto, creds, commands, sshVersion, downloadUrls, fingerprints, uploads, tunnels }, false);
|
||||
const [, ...restLines] = shortComment.split('\n');
|
||||
const rest = restLines.length ? `\n${restLines.join('\n')}` : '';
|
||||
|
||||
await reportIp('COWRIE', { srcIp, dpt, proto, timestamp }, categories, shortComment);
|
||||
if (restLines.length) await logger.info(rest);
|
||||
await logger.webhook(`### Cowrie: ${srcIp} on ${dpt}/${proto}${rest}`);
|
||||
|
||||
logIpToFile(srcIp, { honeypot: 'COWRIE', comment: buildComment({ serverId: SERVER_ID, dpt, proto, creds, commands, sshVersion, downloadUrls, fingerprints, uploads, tunnels }, true) });
|
||||
};
|
||||
|
||||
const processCowrieLogLine = async (entry, reportIp) => {
|
||||
const ip = entry?.src_ip;
|
||||
const sessionId = entry?.session;
|
||||
const { eventid } = entry;
|
||||
if (!ip || !eventid || !sessionId) return logger.warn('COWRIE -> Skipped: missing src_ip, eventid or sessionId');
|
||||
|
||||
let buffer = ipBuffers.get(ip);
|
||||
if (!buffer) {
|
||||
buffer = {
|
||||
sessions: [],
|
||||
timer: setTimeout(() => flushBuffer(ip, reportIp), REPORT_DELAY),
|
||||
lastSeen: Date.now(),
|
||||
};
|
||||
ipBuffers.set(ip, buffer);
|
||||
} else {
|
||||
buffer.lastSeen = Date.now();
|
||||
}
|
||||
|
||||
let session = buffer.sessions.find(s => s.sessionId === sessionId);
|
||||
if (!session && eventid !== 'cowrie.session.closed') {
|
||||
session = {
|
||||
sessionId,
|
||||
srcIp: ip,
|
||||
dpt: null,
|
||||
proto: null,
|
||||
timestamp: null,
|
||||
credentials: new Map(),
|
||||
commands: [],
|
||||
sshVersion: null,
|
||||
download: null,
|
||||
fingerprint: null,
|
||||
uploads: [],
|
||||
tunnels: [],
|
||||
};
|
||||
buffer.sessions.push(session);
|
||||
}
|
||||
|
||||
switch (eventid) {
|
||||
case 'cowrie.session.connect':
|
||||
if (session) {
|
||||
session.dpt = entry.dst_port;
|
||||
session.proto = entry.protocol;
|
||||
session.timestamp = entry.timestamp;
|
||||
logger.info(`COWRIE -> ${ip}/${session.proto}/${session.dpt}: Connect`);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'cowrie.login.success':
|
||||
case 'cowrie.login.failed':
|
||||
if (session && (entry.username || entry.password)) {
|
||||
session.credentials.set(`${entry.username}:${entry.password}`, true);
|
||||
const status = eventid === 'cowrie.login.success' ? 'Connected' : 'Failed login';
|
||||
logger.info(`COWRIE -> ${ip}/${session.proto}/${session.dpt}: ${status} » ${entry.username}:${entry.password}`);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'cowrie.client.version':
|
||||
if (session) {
|
||||
session.sshVersion = entry.version;
|
||||
logger.info(`COWRIE -> ${ip}/${session.proto}/${session.dpt}: SSH version » ${entry.version}`);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'cowrie.command.input':
|
||||
if (session && entry.input) {
|
||||
session.commands.push(entry.input);
|
||||
logger.info(`COWRIE -> ${ip}/${session.proto}/${session.dpt}: $ ${entry.input}`);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'cowrie.session.file_download':
|
||||
if (session && entry.url) {
|
||||
session.commands.push(`[download] ${entry.url}`);
|
||||
session.download = { url: entry.url, outfile: entry.outfile };
|
||||
logger.info(`COWRIE -> ${ip}/${session.proto}/${session.dpt}: File download » ${entry.url}`);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'cowrie.client.fingerprint':
|
||||
if (session && entry.fingerprint) {
|
||||
session.fingerprint = entry.fingerprint;
|
||||
logger.info(`COWRIE -> ${ip}/${session.proto}/${session.dpt}: SSH key fingerprint » ${entry.fingerprint}`);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'cowrie.session.file_upload':
|
||||
if (session && entry.filename) {
|
||||
session.uploads.push(entry.filename);
|
||||
logger.info(`COWRIE -> ${ip}/${session.proto}/${session.dpt}: File upload » ${entry.filename}`);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'cowrie.direct-tcpip.request':
|
||||
if (session && entry.dst_ip && entry.dst_port) {
|
||||
const tunnel = `${entry.dst_ip}:${entry.dst_port}`;
|
||||
session.tunnels.push(tunnel);
|
||||
logger.info(`COWRIE -> ${ip}/${session.proto}/${session.dpt}: TCP tunnel request » ${tunnel}`);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'cowrie.session.closed':
|
||||
logger.info(`COWRIE -> ${ip}/${session?.proto ?? 'unknown'}/${session?.dpt ?? '-'}: Session ${sessionId} closed`);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = reportIp => {
|
||||
tailFile(LOG_FILE, async line => {
|
||||
if (!line.length) return;
|
||||
|
||||
let entry;
|
||||
try {
|
||||
entry = JSON.parse(line);
|
||||
} catch (err) {
|
||||
return logger.error(`COWRIE -> JSON parse error: ${err.message}\nFaulty line: ${JSON.stringify(line)}`);
|
||||
}
|
||||
|
||||
try {
|
||||
await processCowrieLogLine(entry, reportIp);
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
}
|
||||
}, { label: 'COWRIE' }).catch(err => logger.error(err));
|
||||
|
||||
// Clean buffer
|
||||
const cleanupInterval = setInterval(() => {
|
||||
const now = Date.now();
|
||||
for (const [ip, buffer] of ipBuffers.entries()) {
|
||||
if (now - buffer.lastSeen > 30 * 60 * 1000) {
|
||||
clearTimeout(buffer.timer);
|
||||
ipBuffers.delete(ip);
|
||||
logger.warn(`COWRIE -> Cleaned up stale session buffer for ${ip}`);
|
||||
}
|
||||
}
|
||||
}, 15 * 60 * 1000);
|
||||
|
||||
logger.success('🛡️ COWRIE » Watcher initialized');
|
||||
return {
|
||||
flush: async () => {
|
||||
for (const ip of ipBuffers.keys()) {
|
||||
await flushBuffer(ip, reportIp);
|
||||
}
|
||||
},
|
||||
cleanup: () => {
|
||||
clearInterval(cleanupInterval);
|
||||
for (const buffer of ipBuffers.values()) {
|
||||
clearTimeout(buffer.timer);
|
||||
}
|
||||
ipBuffers.clear();
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,97 @@
|
||||
const { FLAGS, createFlagCollection } = require('../flags.js');
|
||||
const logIpToFile = require('../logIpToFile.js');
|
||||
const tailFile = require('../services/tailFile.js');
|
||||
const logger = require('../logger.js');
|
||||
const resolvePath = require('../pathResolver.js');
|
||||
const { DIONAEA_LOG_FILE, SERVER_ID } = require('../../config.js').MAIN;
|
||||
|
||||
const LOG_FILE = resolvePath(DIONAEA_LOG_FILE);
|
||||
|
||||
const getReportDetails = (entry, dpt) => {
|
||||
const proto = entry?.connection?.protocol || 'unknown';
|
||||
const timestamp = entry?.timestamp || new Date().toISOString();
|
||||
|
||||
const flags = createFlagCollection();
|
||||
let comment;
|
||||
|
||||
switch (proto) {
|
||||
case 'mssqld': {
|
||||
const username = entry?.credentials?.username?.[0];
|
||||
const password = entry?.credentials?.password?.[0];
|
||||
if (username && !password) {
|
||||
flags.add(FLAGS.BRUTE_FORCE);
|
||||
comment = `MSSQL traffic (on ${dpt}) with username ${username} and empty password`;
|
||||
} else if (username && password) {
|
||||
flags.add(FLAGS.BRUTE_FORCE);
|
||||
comment = `MSSQL traffic (on ${dpt}) with credentials ${username}:${password}`;
|
||||
} else {
|
||||
flags.add(FLAGS.PORT_SCAN);
|
||||
comment = `MSSQL traffic (on ${dpt}) without login credentials`;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'httpd':
|
||||
flags.add(FLAGS.HTTP, FLAGS.BAD_WEB_BOT);
|
||||
comment = `Incoming HTTP traffic on port ${dpt}`;
|
||||
break;
|
||||
case 'ftp':
|
||||
flags.add(FLAGS.FTP, FLAGS.BRUTE_FORCE);
|
||||
comment = `FTP brute-force or probing on port ${dpt}`;
|
||||
break;
|
||||
case 'smbd':
|
||||
flags.add(FLAGS.SMB);
|
||||
comment = `SMB traffic on port ${dpt}`;
|
||||
break;
|
||||
case 'mysql':
|
||||
flags.add(FLAGS.BRUTE_FORCE);
|
||||
comment = `MySQL brute-force or probing on port ${dpt}`;
|
||||
break;
|
||||
case 'tftp':
|
||||
flags.add(FLAGS.EXPLOITED_HOST);
|
||||
comment = `TFTP protocol traffic on ${dpt}`;
|
||||
break;
|
||||
case 'upnp':
|
||||
case 'mqtt':
|
||||
flags.add(FLAGS.IOT_TARGETED);
|
||||
comment = `Unauthorized ${proto.toUpperCase()} traffic on ${dpt}`;
|
||||
break;
|
||||
default:
|
||||
flags.add(FLAGS.PORT_SCAN);
|
||||
comment = `Unauthorized traffic on ${dpt}/${proto}`;
|
||||
}
|
||||
|
||||
return {
|
||||
proto: proto.toUpperCase(),
|
||||
comment: `Honeypot ${SERVER_ID ? `[${SERVER_ID}]` : 'hit'}: ${comment}`,
|
||||
categories: flags.toString(),
|
||||
timestamp,
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = reportIp => {
|
||||
tailFile(LOG_FILE, async line => {
|
||||
if (!line.length) return;
|
||||
|
||||
let entry;
|
||||
try {
|
||||
entry = JSON.parse(line);
|
||||
} catch (err) {
|
||||
return logger.error(`DIONAEA -> JSON parse error: ${err.message}\nFaulty line: ${JSON.stringify(line)}`);
|
||||
}
|
||||
|
||||
try {
|
||||
const srcIp = entry?.src_ip;
|
||||
const dpt = entry?.dst_port;
|
||||
if (!srcIp || !dpt) return;
|
||||
|
||||
const { proto, timestamp, categories, comment } = getReportDetails(entry, dpt);
|
||||
await reportIp('DIONAEA', { srcIp, dpt, proto, timestamp }, categories, comment);
|
||||
|
||||
await logIpToFile(srcIp, { honeypot: 'DIONAEA', comment });
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
}
|
||||
}, { label: 'DIONAEA' }).catch(err => logger.error(err));
|
||||
|
||||
logger.success('🛡️ DIONAEA » Watcher initialized');
|
||||
};
|
||||
@@ -0,0 +1,179 @@
|
||||
const logIpToFile = require('../logIpToFile.js');
|
||||
const tailFile = require('../services/tailFile.js');
|
||||
const logger = require('../logger.js');
|
||||
const resolvePath = require('../pathResolver.js');
|
||||
const { HONEYTRAP_LOG_FILE, SERVER_ID } = require('../../config.js').MAIN;
|
||||
const { FLAGS, createFlagCollection } = require('../flags.js');
|
||||
|
||||
const LOG_FILE = resolvePath(HONEYTRAP_LOG_FILE);
|
||||
const HEADER_PRIORITY = ['user-agent', 'accept', 'accept-language', 'accept-encoding'];
|
||||
|
||||
let lastFlushTime = Date.now();
|
||||
const attackBuffer = new Map();
|
||||
|
||||
const capitalizeHeader = header => header.split('-').map(w => w[0].toUpperCase() + w.slice(1)).join('-');
|
||||
|
||||
const parseHttpRequest = (ascii, dpt) => {
|
||||
const lines = ascii.replace(/\r\n|\r/g, '\n').trim().split('\n');
|
||||
|
||||
const requestLineRaw = lines.shift()?.trim() || '';
|
||||
const protocol = requestLineRaw.match(/HTTP\/[0-9.]+/i)?.[0]?.toUpperCase() || 'HTTP';
|
||||
const requestLine = requestLineRaw.replace(/\s*HTTP\/[0-9.]+$/i, '');
|
||||
|
||||
const headers = {};
|
||||
const body = [];
|
||||
let parsingBody = false;
|
||||
|
||||
for (const line of lines) {
|
||||
if (parsingBody) {
|
||||
body.push(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!line.trim()) {
|
||||
parsingBody = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const [key, ...value] = line.split(':');
|
||||
if (value.length && key.toLowerCase() !== 'host') headers[key.trim().toLowerCase()] = value.join(':').trim();
|
||||
}
|
||||
|
||||
const formattedHeaders = HEADER_PRIORITY
|
||||
.filter(h => headers[h])
|
||||
.map(h => `${capitalizeHeader(h)}: ${headers[h]}`)
|
||||
.join('\n');
|
||||
|
||||
let output = `${protocol} request on ${dpt}\n\n${requestLine}`;
|
||||
if (formattedHeaders) output += `\n${formattedHeaders}`;
|
||||
|
||||
if (requestLineRaw.startsWith('POST')) {
|
||||
const bodyContent = body.join('\n').trim();
|
||||
if (bodyContent) output += `\nPOST Data: ${bodyContent}`;
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
const getReportDetails = (entry, dpt) => {
|
||||
const proto = entry?.attack_connection?.protocol || 'unknown';
|
||||
const hex = entry?.attack_connection?.payload?.data_hex || '';
|
||||
const ascii = Buffer.from(hex, 'hex').toString('utf8');
|
||||
const simplifiedAscii = ascii.replace(/\s+/g, ' ').toLowerCase();
|
||||
const payloadLen = entry?.attack_connection?.payload?.length || 0;
|
||||
|
||||
const flags = createFlagCollection();
|
||||
let comment;
|
||||
|
||||
switch (true) {
|
||||
case payloadLen === 0:
|
||||
flags.add(FLAGS.PORT_SCAN);
|
||||
comment = `Empty payload on ${dpt}/${proto} (likely service probe)`;
|
||||
break;
|
||||
case payloadLen > 1000:
|
||||
flags.add(FLAGS.BAD_WEB_BOT);
|
||||
comment = `Large payload (${payloadLen} bytes) on ${dpt}/${proto}`;
|
||||
break;
|
||||
case (/HTTP\/(0\.9|1\.0|1\.1|2|3)/i).test(simplifiedAscii):
|
||||
flags.add(FLAGS.HTTP, FLAGS.BAD_WEB_BOT);
|
||||
comment = parseHttpRequest(ascii, dpt);
|
||||
break;
|
||||
case (/\bssh\b/).test(simplifiedAscii):
|
||||
flags.add(FLAGS.SSH);
|
||||
comment = `SSH handshake/banner on ${dpt}/${proto} (${payloadLen} bytes of payload)`;
|
||||
break;
|
||||
case simplifiedAscii.includes('cookie:'):
|
||||
flags.add(FLAGS.HTTP, FLAGS.BAD_WEB_BOT);
|
||||
comment = `HTTP header with cookie on ${dpt}/${proto}`;
|
||||
break;
|
||||
case (/(admin|root|wget|curl|bash|eval|php|bin)/).test(simplifiedAscii):
|
||||
flags.add(FLAGS.COMMAND_INJECTION);
|
||||
comment = `Suspicious payload on ${dpt}/${proto} (possible command injection)`;
|
||||
break;
|
||||
default:
|
||||
flags.add(FLAGS.PORT_SCAN);
|
||||
comment = `Unauthorized traffic on ${dpt}/${proto} (${payloadLen} bytes of payload)`;
|
||||
break;
|
||||
}
|
||||
|
||||
return { proto, baseComment: comment, categories: flags.toString(), timestamp: entry?.['@timestamp'] };
|
||||
};
|
||||
|
||||
const flushBuffer = async reportIp => {
|
||||
if (!attackBuffer.size) return;
|
||||
|
||||
for (const [srcIp, ports] of attackBuffer.entries()) {
|
||||
const sortedPorts = Array.from(ports.entries())
|
||||
.sort(([, a], [, b]) => b.count - a.count)
|
||||
.slice(0, 6);
|
||||
|
||||
const proto = sortedPorts[0][1].proto || 'tcp';
|
||||
const timestamp = sortedPorts[0][1].timestamp;
|
||||
const baseComment = sortedPorts[0][1].baseComment;
|
||||
const categories = sortedPorts[0][1].categories;
|
||||
|
||||
const portSummary = sortedPorts.map(([port, data]) => `${port} [${data.count}]`).join(', ');
|
||||
const comment = `Honeypot ${SERVER_ID ? `[${SERVER_ID}]` : 'hit'}: ${baseComment.replace(/ on \d+\/\w+/, '')}; ${portSummary} ${proto.toUpperCase()}`;
|
||||
|
||||
await reportIp('HONEYTRAP', { srcIp, dpt: sortedPorts[0][0], proto, timestamp }, categories, comment);
|
||||
await logIpToFile(srcIp, { honeypot: 'HONEYTRAP', comment });
|
||||
}
|
||||
|
||||
logger.success(`HONEYTRAP -> Flushed ${attackBuffer.size} IPs`);
|
||||
attackBuffer.clear();
|
||||
};
|
||||
|
||||
module.exports = reportIp => {
|
||||
tailFile(LOG_FILE, async line => {
|
||||
if (!line.length) return;
|
||||
|
||||
let entry;
|
||||
try {
|
||||
entry = JSON.parse(line);
|
||||
} catch (err) {
|
||||
return logger.error(`HONEYTRAP -> JSON parse error: ${err.message}\nFaulty line: ${JSON.stringify(line)}`);
|
||||
}
|
||||
|
||||
try {
|
||||
const srcIp = entry?.attack_connection?.remote_ip;
|
||||
const dpt = entry?.attack_connection?.local_port;
|
||||
if (!srcIp || !dpt) return;
|
||||
|
||||
let ipData = attackBuffer.get(srcIp);
|
||||
if (!ipData) {
|
||||
ipData = new Map();
|
||||
attackBuffer.set(srcIp, ipData);
|
||||
}
|
||||
|
||||
const { proto, timestamp, categories, baseComment } = getReportDetails(entry, dpt);
|
||||
let portData = ipData.get(dpt);
|
||||
if (portData) {
|
||||
portData.count++;
|
||||
} else {
|
||||
portData = { count: 1, proto, timestamp, categories, baseComment };
|
||||
ipData.set(dpt, portData);
|
||||
}
|
||||
|
||||
logger.info(`HONEYTRAP -> ${srcIp} hit ${dpt} | x${portData.count}`);
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
}
|
||||
}, { label: 'HONEYTRAP' }).catch(err => logger.error(err));
|
||||
|
||||
// Clean buffer
|
||||
const cleanupInterval = setInterval(async () => {
|
||||
if (Date.now() >= lastFlushTime + 5 * 60 * 1000) {
|
||||
await flushBuffer(reportIp);
|
||||
lastFlushTime = Date.now();
|
||||
}
|
||||
}, 60 * 1000);
|
||||
|
||||
logger.success('🛡️ HONEYTRAP » Watcher initialized');
|
||||
return {
|
||||
flush: () => flushBuffer(reportIp),
|
||||
cleanup: () => {
|
||||
clearInterval(cleanupInterval);
|
||||
attackBuffer.clear();
|
||||
},
|
||||
};
|
||||
};
|
||||
Reference in new issue
Block a user