dtp-tripwire-agent
Version:
A service for protecting your node against malicious attacks and scans.
135 lines (118 loc) • 3.31 kB
text/typescript
import env from "./config/env.js";
import path from "node:path";
import fs from "node:fs";
import readline from "readline";
import dayjs from "dayjs";
import customParseFormat from "dayjs/plugin/customParseFormat.js";
import { MethodMap, TripwireConfigFile, UriSet } from "service.js";
dayjs.extend(customParseFormat);
const blockedUriStrings = [
".env",
".git",
".php",
".zip",
".htaccess",
"wordpress",
"wp-admin",
"wp-config",
"wp-content",
"wp-includes",
"wp-mail",
];
const blockedUriPrefixes = [
"/.well-known",
"/cgi-bin",
"/file.php",
"/modules",
"/wp",
"/wp1",
"/wp2",
"/xmlrpc.php",
];
const logFile = fs.createReadStream("./data/access.log");
const rl = readline.createInterface({
input: logFile,
crlfDelay: Infinity,
});
const methods: MethodMap = new Map<string, UriSet>();
let recordCount = 0;
let prefixMatchCount = 0;
let stringMatchCount = 0;
rl.on("line", (line) => {
++recordCount;
const re = /([^ ]*) ([^ ]*) ([^ ]*) \[([^\]]*)\] "([^"]*)" ([^ ]*) ([^ ]*)/;
const matches = line.match(re);
if (!matches || !matches[4] || !matches[5]) {
return;
}
if (matches) {
// const timestamp = matches[4];
// const date = dayjs(timestamp, "DD/MMM/YYYY:HH:mm:ss ZZ").toDate();
const requestTokens = matches[5].split(" ");
if (!requestTokens[0] || !requestTokens[1] || !requestTokens[2]) {
// console.error(matches[1], "malformed request", matches[5]);
return;
}
const request = {
method: requestTokens[0].trim(),
uri: requestTokens[1].trim(),
version: requestTokens[2].trim(),
};
if (
request.method[0] === "\\" ||
request.uri[0] === "\\" ||
request.version[0] === "\\"
) {
// console.error(matches[1], "malformed request", matches[5]);
return;
}
for (const text of blockedUriStrings) {
if (request.uri.includes(text)) {
++stringMatchCount;
return;
}
}
for (const prefix of blockedUriPrefixes) {
if (request.uri.startsWith(prefix)) {
++prefixMatchCount;
return;
}
}
const method = methods.get(request.method);
if (method) {
method.add(request.uri);
} else {
methods.set(request.method, new Set<string>([request.uri]));
}
// const obj = {
// remoteHost: matches[1],
// remoteLogName: matches[2],
// authUser: matches[3],
// date,
// request,
// status: Number(matches[6]),
// bytes: Number(matches[7]) || 0,
// };
// console.log(JSON.stringify(obj));
}
});
rl.on("close", async () => {
console.log(`${recordCount} records read`);
console.log(`${prefixMatchCount} prefix matches`);
console.log(`${stringMatchCount} string matches`);
const configPath = path.join(env.cache.path, "tripwire");
await fs.promises.mkdir(configPath, { recursive: true });
const configuration: TripwireConfigFile = {
prefixes: blockedUriPrefixes,
strings: blockedUriStrings,
methods: [],
};
for (const [method, uris] of methods) {
configuration.methods.push({ name: method, uris: Array.from(uris) });
}
const configFile = path.join(configPath, "config.json");
await fs.promises.writeFile(
configFile,
JSON.stringify(configuration, null, 2)
);
});