// Lets use some libs to help us out. const fs = require('fs') Tail = require('tail').Tail; sshTail = new Tail("/var/log/auth.log"); const cmd = require('cmd-promise') // Setting up our main storage logic - for now this program does not use a database system. let serverStatusCount = 0; let attackData = [] let blockedIPs = [] let ipToBlock console.log("Welcome to the security notification system secuNotify by Discord-Linux!"); console.log("We currently will notify you about login events, such as failed logins and successful logins."); // Setting up our notification function - This allows us to direct message our user. function notify(message) { const { spawn } = require('child_process'); const notif = spawn('notif', [message]); notif.stdout.on('data', (data) => { console.log(`stdout: ${data}`); }); notif.stderr.on('data', (data) => { console.error(`stderr: ${data}`); }); notif.on('close', (code) => { console.log(`Code: ${code} - Continuing to monitor`); }); } function listenAuthLog(logLocation) { sshTail.on("line", function (info) { let infoString = info.toString(); if (infoString.includes("Failed password for root")) { console.log(info); notify("secuNotify Service Alert: \n" + info); } if (infoString.includes("Accepted password for")) { console.log(info); notify("secuNotify Service Alert: \n" + info + "This does mean that someone (Maybe you) has logged in successfully!"); } if (infoString.includes("Invalid user")) { console.log(info); notify("secuNotify Service Alert: \n" + info + "This means that someone (Maybe you) has tried to login with an invalid username!"); } }) ; } function listenWPLog(logLocation) { // Check to see if we are a wordpress user, if so, activate the wordpress notification service try { if (fs.existsSync("/var/www/html/wp-config.php")) { console.log("We are a wordpress user, activating wordpress notification service"); // Tail Logs section, if we have a lot, it will have a listeniner below. wpTail.on("line", function (info) { // Convert Data to String let requestInfo = info.toString() // FIND IP Address from this request var ipRegEx = /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/; // RegEx IPAddress Format var ipRegExMatched = requestInfo.match(ipRegEx); // Set up our match let remoteIP = ipRegExMatched[0] // Set our var // // Grab the whitelist // let whitelistData = process.env.WHITELIST // let whitelist = whitelistData.split(",") // // If an IP is found to be in the whitelist, return as to do nothing. // for (const [key, value] of Object.entries(whitelist)) { // if (value === remoteIP) return // } // Filtering out any server-status requests - These are annoying. if (requestInfo.includes("server-status")) { // Add to the server status count so we may keep track of these requests. serverStatusCount++ // Lets return the data as no not proceed with any further code, as it is not needed. // We return to stdout here to update the cli without adding a new line line a clock return process.stdout.write("Server Status Count: " + serverStatusCount + "\r"); } // If request contans wp-login lets process its request if (requestInfo.includes("wp-login.php") && requestInfo.includes("POST")) { // Lets start the process of logging attack attempts to determine request intent. // Over the threshhold here will automatically CSF D the IP Address. // In this simple version, we will just log each IP Address as they come in within an array // We will then roll and count this array after each detection to determine the IPs intent. console.log("---------\nWP LOGIN REQUEST DETECTED!\n---------") console.log(info + "\n----------"); attackData.push(remoteIP) // Lets count the attack data per IP Address to ensure its logged properly. var counts = {}; // For each IP Address recorded into the main attackData array, count them and see outmany bad requests they have made. attackData.forEach(function (x) { // Add a point for each entry counts[x] = (counts[x] || 0) + 1; // for ([key, value] of Object.entries(counts)) { // If the count has hit the blockON Count we start the blocking process if (counts[x] == 5) { // Preserve the key for later blocklist addition ipToBlock = key // Check the already blocked IPs - If the remoteIP is in the list do nothing if (blockedIPs.includes(key)) { return } else { // The remoteIP is not listed, lets add it. blockedIPs.push(ipToBlock) // Let the log know we are blocking the IP console.log("Starting to block bad IP") // Run the block, wait for the promise - Requests are still going on cmd(`/var/tools/firewallctl ` + key + " WP-Login Brute Force Blocked Via secuNotify").then(out => { notify("secuNotify Service Alert:\n " + key + " has been blocked for 5 bad wordpress login attempts!"); // The block has finished - remoteIP no longer has access }).catch(err => { // IF we see an error, give its output console.log('CSF Error: ', err) }).then(out2 => { // Set IPBLOCK to null for a reset and start scanning for new attacks ipToBlock = null; console.log("Attack Stopped, Looking for new attacks....") }) } } } }); // Live view of the counts console.log(counts) } }) } } catch (err) { console.log(err) } } listenAuthLog("/var/log/auth.log") fs.exists("/var/log/apache2/access.log", function (isExist) { if (isExist) { wpTail = new Tail("/var/log/apache2/access.log"); listenWPLog("/var/log/apache2/access.log") } else { console.log("ApacheHTTP Server is not installed, not enabling WP protection."); } });