@feardread/fear 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.
- package/FEAR.js +459 -0
- package/FEARServer.js +280 -0
- package/controllers/agent.js +438 -0
- package/controllers/auth/index.js +345 -0
- package/controllers/auth/token.js +50 -0
- package/controllers/blog.js +105 -0
- package/controllers/brand.js +10 -0
- package/controllers/cart.js +425 -0
- package/controllers/category.js +9 -0
- package/controllers/coupon.js +63 -0
- package/controllers/crud/crud.js +508 -0
- package/controllers/crud/index.js +36 -0
- package/controllers/email.js +34 -0
- package/controllers/enquiry.js +65 -0
- package/controllers/events.js +9 -0
- package/controllers/order.js +125 -0
- package/controllers/payment.js +31 -0
- package/controllers/product.js +147 -0
- package/controllers/review.js +247 -0
- package/controllers/tag.js +10 -0
- package/controllers/task.js +10 -0
- package/controllers/upload.js +41 -0
- package/controllers/user.js +401 -0
- package/index.js +7 -0
- package/libs/agent/index.js +561 -0
- package/libs/agent/modules/ai/ai.js +285 -0
- package/libs/agent/modules/ai/chat.js +518 -0
- package/libs/agent/modules/ai/config.js +688 -0
- package/libs/agent/modules/ai/operations.js +787 -0
- package/libs/agent/modules/analyze/api.js +546 -0
- package/libs/agent/modules/analyze/dorks.js +395 -0
- package/libs/agent/modules/ccard/README.md +454 -0
- package/libs/agent/modules/ccard/audit.js +479 -0
- package/libs/agent/modules/ccard/checker.js +674 -0
- package/libs/agent/modules/ccard/payment-processors.json +16 -0
- package/libs/agent/modules/ccard/validator.js +629 -0
- package/libs/agent/modules/code/analyzer.js +303 -0
- package/libs/agent/modules/code/jquery.js +1093 -0
- package/libs/agent/modules/code/react.js +1536 -0
- package/libs/agent/modules/code/refactor.js +499 -0
- package/libs/agent/modules/crypto/exchange.js +564 -0
- package/libs/agent/modules/net/proxy.js +409 -0
- package/libs/agent/modules/security/cve.js +442 -0
- package/libs/agent/modules/security/monitor.js +360 -0
- package/libs/agent/modules/security/scanner.js +300 -0
- package/libs/agent/modules/security/vulnerability.js +506 -0
- package/libs/agent/modules/security/web.js +465 -0
- package/libs/agent/modules/utils/browser.js +492 -0
- package/libs/agent/modules/utils/colorizer.js +285 -0
- package/libs/agent/modules/utils/manager.js +478 -0
- package/libs/cloud/index.js +228 -0
- package/libs/config/db.js +21 -0
- package/libs/config/validator.js +82 -0
- package/libs/db/index.js +318 -0
- package/libs/emailer/imap.js +126 -0
- package/libs/emailer/info.js +41 -0
- package/libs/emailer/smtp.js +77 -0
- package/libs/handler/async.js +3 -0
- package/libs/handler/error.js +66 -0
- package/libs/handler/index.js +161 -0
- package/libs/logger/index.js +49 -0
- package/libs/logger/morgan.js +24 -0
- package/libs/passport/passport.js +109 -0
- package/libs/search/api.js +384 -0
- package/libs/search/features.js +219 -0
- package/libs/search/service.js +64 -0
- package/libs/swagger/config.js +18 -0
- package/libs/swagger/index.js +35 -0
- package/libs/validator/index.js +254 -0
- package/models/blog.js +31 -0
- package/models/brand.js +12 -0
- package/models/cart.js +14 -0
- package/models/category.js +11 -0
- package/models/coupon.js +9 -0
- package/models/customer.js +0 -0
- package/models/enquiry.js +29 -0
- package/models/events.js +13 -0
- package/models/order.js +94 -0
- package/models/product.js +32 -0
- package/models/review.js +14 -0
- package/models/tag.js +10 -0
- package/models/task.js +11 -0
- package/models/user.js +68 -0
- package/package.json +12 -0
- package/routes/agent.js +615 -0
- package/routes/auth.js +13 -0
- package/routes/blog.js +19 -0
- package/routes/brand.js +15 -0
- package/routes/cart.js +105 -0
- package/routes/category.js +16 -0
- package/routes/coupon.js +15 -0
- package/routes/enquiry.js +14 -0
- package/routes/events.js +16 -0
- package/routes/mail.js +170 -0
- package/routes/order.js +19 -0
- package/routes/product.js +22 -0
- package/routes/review.js +11 -0
- package/routes/task.js +12 -0
- package/routes/user.js +17 -0
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
// modules/api-tester.js - API Endpoint Security Testing
|
|
2
|
+
const https = require('https');
|
|
3
|
+
const http = require('http');
|
|
4
|
+
const { URL } = require('url');
|
|
5
|
+
const fs = require('fs').promises;
|
|
6
|
+
const colorizer = require("../utils/colorizer");
|
|
7
|
+
|
|
8
|
+
const ApiAnalyzer = function () {
|
|
9
|
+
|
|
10
|
+
this.testResults = [];
|
|
11
|
+
this.vulnerabilities = [];
|
|
12
|
+
this.payloads = {
|
|
13
|
+
xss: [
|
|
14
|
+
'<script>alert("XSS")</script>',
|
|
15
|
+
'"><script>alert(1)</script>',
|
|
16
|
+
'javascript:alert(1)',
|
|
17
|
+
'<img src=x onerror=alert(1)>',
|
|
18
|
+
'<svg onload=alert(1)>'
|
|
19
|
+
],
|
|
20
|
+
sql: [
|
|
21
|
+
"' OR '1'='1",
|
|
22
|
+
"1' OR '1'='1' --",
|
|
23
|
+
"admin'--",
|
|
24
|
+
"' UNION SELECT NULL--",
|
|
25
|
+
"1; DROP TABLE users--"
|
|
26
|
+
],
|
|
27
|
+
nosql: [
|
|
28
|
+
'{"$gt":""}',
|
|
29
|
+
'{"$ne":null}',
|
|
30
|
+
'{"$regex":".*"}',
|
|
31
|
+
'[$ne]=1'
|
|
32
|
+
],
|
|
33
|
+
cmdInjection: [
|
|
34
|
+
'; ls -la',
|
|
35
|
+
'| cat /etc/passwd',
|
|
36
|
+
'`whoami`',
|
|
37
|
+
'$(whoami)',
|
|
38
|
+
'& dir'
|
|
39
|
+
],
|
|
40
|
+
pathTraversal: [
|
|
41
|
+
'../../../etc/passwd',
|
|
42
|
+
'..\\..\\..\\windows\\system.ini',
|
|
43
|
+
'....//....//....//etc/passwd',
|
|
44
|
+
'%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd'
|
|
45
|
+
],
|
|
46
|
+
xxe: [
|
|
47
|
+
'<?xml version="1.0"?><!DOCTYPE root [<!ENTITY test SYSTEM "file:///etc/passwd">]><root>&test;</root>'
|
|
48
|
+
]
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
this.commonHeaders = {
|
|
52
|
+
'User-Agent': 'Security-AI-Agent/2.0',
|
|
53
|
+
'Accept': 'application/json, text/plain, */*',
|
|
54
|
+
'Content-Type': 'application/json'
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
ApiAnalyzer.prototype = {
|
|
60
|
+
|
|
61
|
+
async testEndpoint(args) {
|
|
62
|
+
const url = (args) ? args[0] : null;
|
|
63
|
+
const method = (args && args.length > 0) ? (args[1]).toUpperCase() : 'GET';
|
|
64
|
+
|
|
65
|
+
if (!url || url === null) {
|
|
66
|
+
console.log(colorizer.red('Usage: test-endpoint <url> [method] [body]\n'));
|
|
67
|
+
console.log(colorizer.header('Examples:'));
|
|
68
|
+
console.log(' test-endpoint https://api.example.com/users');
|
|
69
|
+
console.log(' test-endpoint https://api.example.com/login POST');
|
|
70
|
+
console.log(' test-endpoint https://api.example.com/user/123 GET\n');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
console.log(colorizer.box(`\nAPI Endpoint Security Test`));
|
|
75
|
+
console.log(`URL: ${url}`);
|
|
76
|
+
console.log(`Method: ${method}`);
|
|
77
|
+
console.log(colorizer.grey(`Started: ${new Date().toLocaleString()}\n`));
|
|
78
|
+
|
|
79
|
+
this.testResults = [];
|
|
80
|
+
this.vulnerabilities = [];
|
|
81
|
+
// Run security tests
|
|
82
|
+
this.test.entries.forEach(async (func) => {
|
|
83
|
+
await this.test[func](url, method);
|
|
84
|
+
})
|
|
85
|
+
.then(() => this.displayResults())
|
|
86
|
+
.catch((err) => {
|
|
87
|
+
console.log("error running tests", err);
|
|
88
|
+
})
|
|
89
|
+
/*
|
|
90
|
+
await this.testBasicSecurity(url, method);
|
|
91
|
+
await this.testHeaders(url);
|
|
92
|
+
await this.testAuthentication(url, method);
|
|
93
|
+
await this.testRateLimiting(url, method);
|
|
94
|
+
await this.testInputValidation(url, method);
|
|
95
|
+
await this.testHTTPMethods(url);
|
|
96
|
+
*/
|
|
97
|
+
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
async testCollection(args) {
|
|
101
|
+
const filePath = args[0];
|
|
102
|
+
|
|
103
|
+
if (!filePath) {
|
|
104
|
+
console.log('Usage: test-collection <json-file>\n');
|
|
105
|
+
console.log('Example JSON format:');
|
|
106
|
+
console.log(JSON.stringify({
|
|
107
|
+
name: "API Test Collection",
|
|
108
|
+
endpoints: [
|
|
109
|
+
{ url: "https://api.example.com/users", method: "GET" },
|
|
110
|
+
{ url: "https://api.example.com/login", method: "POST" }
|
|
111
|
+
]
|
|
112
|
+
}, null, 2));
|
|
113
|
+
console.log();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
await fs.readFile((filePath, 'utf8'))
|
|
118
|
+
.then((data) => {
|
|
119
|
+
const collection = JSON.parse(data);
|
|
120
|
+
console.log(`\nTesting API Collection: ${collection.name}`);
|
|
121
|
+
console.log(`===============================================`);
|
|
122
|
+
console.log(`Endpoints: ${collection.endpoints.length}\n`);
|
|
123
|
+
|
|
124
|
+
for (const endpoint of collection.endpoints) {
|
|
125
|
+
this.testEndpoint([endpoint.url, endpoint.method]).catch((err) => { });
|
|
126
|
+
this.sleep(1000);
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
.catch((err) => {
|
|
130
|
+
console.log(`Failed to load collection: ${err.message}\n`);
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
async exportReport(args) {
|
|
135
|
+
const filename = args[0] || `api-test-report-${Date.now()}.json`;
|
|
136
|
+
|
|
137
|
+
const report = {
|
|
138
|
+
timestamp: new Date().toISOString(),
|
|
139
|
+
vulnerabilities: this.vulnerabilities,
|
|
140
|
+
testResults: this.testResults,
|
|
141
|
+
summary: {
|
|
142
|
+
critical: this.vulnerabilities.filter(v => v.severity === 'CRITICAL').length,
|
|
143
|
+
high: this.vulnerabilities.filter(v => v.severity === 'HIGH').length,
|
|
144
|
+
medium: this.vulnerabilities.filter(v => v.severity === 'MEDIUM').length,
|
|
145
|
+
low: this.vulnerabilities.filter(v => v.severity === 'LOW').length
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
await fs.writeFile(filename, JSON.stringify(report, null, 2))
|
|
150
|
+
.then(() => console.log(`\nReport exported to: ${filename}\n`))
|
|
151
|
+
.catch((err) => console.log(`Export failed: ${err.message}\n`));
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
async makeRequest(url, method, body = null, customHeaders = {}) {
|
|
155
|
+
return new Promise((resolve) => {
|
|
156
|
+
const parsedUrl = new URL(url);
|
|
157
|
+
const lib = parsedUrl.protocol === 'https:' ? https : http;
|
|
158
|
+
|
|
159
|
+
const options = {
|
|
160
|
+
hostname: parsedUrl.hostname,
|
|
161
|
+
port: parsedUrl.port,
|
|
162
|
+
path: parsedUrl.pathname + parsedUrl.search,
|
|
163
|
+
method: method,
|
|
164
|
+
headers: { ...this.commonHeaders, ...customHeaders },
|
|
165
|
+
timeout: 5000,
|
|
166
|
+
rejectUnauthorized: false // For self-signed certs
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
if (body) {
|
|
170
|
+
options.headers['Content-Length'] = Buffer.byteLength(body);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const req = lib.request(options, (res) => {
|
|
174
|
+
let data = '';
|
|
175
|
+
|
|
176
|
+
res.on('data', (chunk) => {
|
|
177
|
+
data += chunk;
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
res.on('end', () => {
|
|
181
|
+
resolve({
|
|
182
|
+
statusCode: res.statusCode,
|
|
183
|
+
headers: res.headers,
|
|
184
|
+
body: data
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
req.on('error', (err) => {
|
|
190
|
+
resolve({ error: err.message });
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
req.on('timeout', () => {
|
|
194
|
+
req.destroy();
|
|
195
|
+
resolve({ error: 'Request timeout' });
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
if (body) {
|
|
199
|
+
req.write(body);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
req.end();
|
|
203
|
+
});
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
addResult(type, name, detail) {
|
|
207
|
+
this.testResults.push({ type, name, detail });
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
addVulnerability(severity, name, detail, remediation) {
|
|
211
|
+
this.vulnerabilities.push({ severity, name, detail, remediation });
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
displayResults() {
|
|
215
|
+
console.log('\n\nTest Results');
|
|
216
|
+
console.log(`===================================\n`);
|
|
217
|
+
|
|
218
|
+
// Display vulnerabilities by severity
|
|
219
|
+
const critical = this.vulnerabilities.filter(v => v.severity === 'CRITICAL');
|
|
220
|
+
const high = this.vulnerabilities.filter(v => v.severity === 'HIGH');
|
|
221
|
+
const medium = this.vulnerabilities.filter(v => v.severity === 'MEDIUM');
|
|
222
|
+
const low = this.vulnerabilities.filter(v => v.severity === 'LOW');
|
|
223
|
+
|
|
224
|
+
if (critical.length > 0) {
|
|
225
|
+
console.log('CRITICAL Vulnerabilities:');
|
|
226
|
+
critical.forEach(v => this.printVulnerability(v));
|
|
227
|
+
console.log();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (high.length > 0) {
|
|
231
|
+
console.log('HIGH Vulnerabilities:');
|
|
232
|
+
high.forEach(v => this.printVulnerability(v));
|
|
233
|
+
console.log();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (medium.length > 0) {
|
|
237
|
+
console.log('MEDIUM Vulnerabilities:');
|
|
238
|
+
medium.forEach(v => this.printVulnerability(v));
|
|
239
|
+
console.log();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (low.length > 0) {
|
|
243
|
+
console.log('LOW Vulnerabilities:');
|
|
244
|
+
low.forEach(v => this.printVulnerability(v));
|
|
245
|
+
console.log();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (this.vulnerabilities.length === 0) {
|
|
249
|
+
console.log(colorizer.green('No vulnerabilities detected!\n'));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Summary
|
|
253
|
+
console.log('Summary:');
|
|
254
|
+
console.log(` Critical: ${critical.length}`);
|
|
255
|
+
console.log(` High: ${high.length}`);
|
|
256
|
+
console.log(` Medium: ${medium.length}`);
|
|
257
|
+
console.log(` Low: ${low.length}`);
|
|
258
|
+
console.log(` Total Tests: ${this.testResults.length}`);
|
|
259
|
+
console.log();
|
|
260
|
+
|
|
261
|
+
// Security Score
|
|
262
|
+
const score = this.calculateSecurityScore(critical.length, high.length, medium.length, low.length);
|
|
263
|
+
console.log(`Security Score: ${score}/100`);
|
|
264
|
+
console.log();
|
|
265
|
+
},
|
|
266
|
+
|
|
267
|
+
printVulnerability(v) {
|
|
268
|
+
console.log(` • ${v.name}`);
|
|
269
|
+
console.log(` Issue: ${v.detail}`);
|
|
270
|
+
console.log(` Fix: ${v.remediation}`);
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
calculateSecurityScore(critical, high, medium, low) {
|
|
274
|
+
let score = 100;
|
|
275
|
+
score -= critical * 25;
|
|
276
|
+
score -= high * 15;
|
|
277
|
+
score -= medium * 10;
|
|
278
|
+
score -= low * 5;
|
|
279
|
+
return Math.max(0, score);
|
|
280
|
+
},
|
|
281
|
+
|
|
282
|
+
sleep(ms) {
|
|
283
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
284
|
+
},
|
|
285
|
+
|
|
286
|
+
tests: {
|
|
287
|
+
|
|
288
|
+
async security(url, method) {
|
|
289
|
+
console.log('Testing Basic Security...');
|
|
290
|
+
|
|
291
|
+
try {
|
|
292
|
+
// Test HTTPS
|
|
293
|
+
const parsedUrl = new URL(url);
|
|
294
|
+
if (parsedUrl.protocol === 'http:') {
|
|
295
|
+
this.addVulnerability('HIGH', 'Insecure Protocol',
|
|
296
|
+
'API uses HTTP instead of HTTPS', 'Use HTTPS for all endpoints');
|
|
297
|
+
} else {
|
|
298
|
+
this.addResult('PASS', 'HTTPS Protocol', 'Endpoint uses HTTPS');
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Make basic request
|
|
302
|
+
const response = await this.makeRequest(url, method);
|
|
303
|
+
|
|
304
|
+
if (response.statusCode) {
|
|
305
|
+
this.addResult('INFO', 'Status Code', `Response: ${response.statusCode}`);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Check for server header
|
|
309
|
+
if (response.headers && response.headers.server) {
|
|
310
|
+
this.addVulnerability('LOW', 'Server Header Exposed',
|
|
311
|
+
`Server: ${response.headers.server}`, 'Remove or obfuscate Server header');
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Check for X-Powered-By
|
|
315
|
+
if (response.headers && response.headers['x-powered-by']) {
|
|
316
|
+
this.addVulnerability('LOW', 'Technology Stack Exposed',
|
|
317
|
+
`X-Powered-By: ${response.headers['x-powered-by']}`, 'Remove X-Powered-By header');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
} catch (err) {
|
|
321
|
+
console.log(` ⚠️ Request failed: ${err.message}`);
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
|
|
325
|
+
async headers(url) {
|
|
326
|
+
console.log('Testing Security Headers...');
|
|
327
|
+
|
|
328
|
+
try {
|
|
329
|
+
const response = await this.makeRequest(url, 'GET');
|
|
330
|
+
const headers = response.headers || {};
|
|
331
|
+
|
|
332
|
+
// Critical security headers
|
|
333
|
+
const requiredHeaders = {
|
|
334
|
+
'strict-transport-security': { severity: 'HIGH', name: 'HSTS' },
|
|
335
|
+
'x-frame-options': { severity: 'MEDIUM', name: 'X-Frame-Options' },
|
|
336
|
+
'x-content-type-options': { severity: 'MEDIUM', name: 'X-Content-Type-Options' },
|
|
337
|
+
'content-security-policy': { severity: 'HIGH', name: 'CSP' },
|
|
338
|
+
'x-xss-protection': { severity: 'LOW', name: 'X-XSS-Protection' },
|
|
339
|
+
'referrer-policy': { severity: 'LOW', name: 'Referrer-Policy' }
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
for (const [header, info] of Object.entries(requiredHeaders)) {
|
|
343
|
+
if (!headers[header]) {
|
|
344
|
+
this.addVulnerability(info.severity, `Missing ${info.name}`,
|
|
345
|
+
`${info.name} header not set`, `Add ${header} header`);
|
|
346
|
+
} else {
|
|
347
|
+
this.addResult('PASS', info.name, `Header present: ${headers[header]}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Check CORS
|
|
352
|
+
if (headers['access-control-allow-origin'] === '*') {
|
|
353
|
+
this.addVulnerability('MEDIUM', 'Open CORS Policy',
|
|
354
|
+
'CORS allows all origins (*)', 'Restrict CORS to specific origins');
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
} catch (err) {
|
|
358
|
+
console.log(` ⚠️ Header test failed: ${err.message}`);
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
|
|
362
|
+
async authentication(url, method) {
|
|
363
|
+
console.log('Testing Authentication...');
|
|
364
|
+
|
|
365
|
+
try {
|
|
366
|
+
// Test without auth
|
|
367
|
+
const noAuthResponse = await this.makeRequest(url, method);
|
|
368
|
+
|
|
369
|
+
if (noAuthResponse.statusCode === 200) {
|
|
370
|
+
this.addVulnerability('HIGH', 'No Authentication Required',
|
|
371
|
+
'Endpoint accessible without authentication', 'Implement authentication');
|
|
372
|
+
} else if (noAuthResponse.statusCode === 401 || noAuthResponse.statusCode === 403) {
|
|
373
|
+
this.addResult('PASS', 'Authentication Required', 'Endpoint requires authentication');
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Test with invalid token
|
|
377
|
+
const invalidAuthResponse = await this.makeRequest(url, method, null, {
|
|
378
|
+
'Authorization': 'Bearer invalid_token_12345'
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
if (invalidAuthResponse.statusCode === 200) {
|
|
382
|
+
this.addVulnerability('CRITICAL', 'Broken Authentication',
|
|
383
|
+
'Endpoint accepts invalid tokens', 'Validate authentication tokens');
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Test common default credentials
|
|
387
|
+
const defaultCreds = [
|
|
388
|
+
{ user: 'admin', pass: 'admin' },
|
|
389
|
+
{ user: 'admin', pass: 'password' },
|
|
390
|
+
{ user: 'root', pass: 'root' }
|
|
391
|
+
];
|
|
392
|
+
|
|
393
|
+
for (const cred of defaultCreds) {
|
|
394
|
+
const basicAuth = Buffer.from(`${cred.user}:${cred.pass}`).toString('base64');
|
|
395
|
+
const response = await this.makeRequest(url, method, null, {
|
|
396
|
+
'Authorization': `Basic ${basicAuth}`
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
if (response.statusCode === 200) {
|
|
400
|
+
this.addVulnerability('CRITICAL', 'Default Credentials',
|
|
401
|
+
`Accepts default credentials: ${cred.user}/${cred.pass}`, 'Change default credentials');
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
} catch (err) {
|
|
407
|
+
console.log(` ⚠️ Authentication test failed: ${err.message}`);
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
|
|
411
|
+
async limiting(url, method) {
|
|
412
|
+
console.log('Testing Rate Limiting...');
|
|
413
|
+
|
|
414
|
+
try {
|
|
415
|
+
const requests = 15;
|
|
416
|
+
let successCount = 0;
|
|
417
|
+
let rateLimited = false;
|
|
418
|
+
|
|
419
|
+
for (let i = 0; i < requests; i++) {
|
|
420
|
+
const response = await this.makeRequest(url, method);
|
|
421
|
+
if (response.statusCode === 429) {
|
|
422
|
+
rateLimited = true;
|
|
423
|
+
break;
|
|
424
|
+
} else if (response.statusCode === 200) {
|
|
425
|
+
successCount++;
|
|
426
|
+
}
|
|
427
|
+
await this.sleep(100); // Small delay
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (!rateLimited && successCount === requests) {
|
|
431
|
+
this.addVulnerability('MEDIUM', 'No Rate Limiting',
|
|
432
|
+
'Endpoint accepts unlimited requests', 'Implement rate limiting');
|
|
433
|
+
} else if (rateLimited) {
|
|
434
|
+
this.addResult('PASS', 'Rate Limiting', 'Endpoint has rate limiting');
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
} catch (err) {
|
|
438
|
+
console.log(` ⚠️ Rate limit test failed: ${err.message}`);
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
async validation(url, method) {
|
|
443
|
+
console.log('Testing Input Validation...');
|
|
444
|
+
|
|
445
|
+
if (method === 'GET') {
|
|
446
|
+
await this.testQueryParams(url);
|
|
447
|
+
} else if (method === 'POST' || method === 'PUT') {
|
|
448
|
+
await this.testBodyPayloads(url, method);
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
|
|
452
|
+
async params(url) {
|
|
453
|
+
const parsedUrl = new URL(url);
|
|
454
|
+
|
|
455
|
+
// Test XSS in query params
|
|
456
|
+
for (const payload of this.payloads.xss.slice(0, 2)) {
|
|
457
|
+
const testUrl = `${url}${url.includes('?') ? '&' : '?'}test=${encodeURIComponent(payload)}`;
|
|
458
|
+
const response = await this.makeRequest(testUrl, 'GET');
|
|
459
|
+
|
|
460
|
+
if (response.body && response.body.includes(payload)) {
|
|
461
|
+
this.addVulnerability('HIGH', 'XSS Vulnerability',
|
|
462
|
+
'Unsanitized input reflected in response', 'Sanitize and encode all user input');
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Test SQL injection
|
|
468
|
+
for (const payload of this.payloads.sql.slice(0, 2)) {
|
|
469
|
+
const testUrl = `${url}${url.includes('?') ? '&' : '?'}id=${encodeURIComponent(payload)}`;
|
|
470
|
+
const response = await this.makeRequest(testUrl, 'GET');
|
|
471
|
+
|
|
472
|
+
if (response.body && (response.body.includes('SQL') || response.body.includes('syntax'))) {
|
|
473
|
+
this.addVulnerability('CRITICAL', 'SQL Injection',
|
|
474
|
+
'SQL error messages exposed', 'Use parameterized queries');
|
|
475
|
+
break;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Test path traversal
|
|
480
|
+
for (const payload of this.payloads.pathTraversal.slice(0, 2)) {
|
|
481
|
+
const testUrl = `${url}${url.includes('?') ? '&' : '?'}file=${encodeURIComponent(payload)}`;
|
|
482
|
+
const response = await this.makeRequest(testUrl, 'GET');
|
|
483
|
+
|
|
484
|
+
if (response.body && (response.body.includes('root:') || response.body.includes('[extensions]'))) {
|
|
485
|
+
this.addVulnerability('CRITICAL', 'Path Traversal',
|
|
486
|
+
'Directory traversal possible', 'Validate and sanitize file paths');
|
|
487
|
+
break;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
},
|
|
491
|
+
|
|
492
|
+
async payloads(url, method) {
|
|
493
|
+
// Test JSON injection
|
|
494
|
+
const jsonPayloads = [
|
|
495
|
+
{ test: this.payloads.xss[0] },
|
|
496
|
+
{ id: this.payloads.sql[0] },
|
|
497
|
+
{ filter: this.payloads.nosql[0] }
|
|
498
|
+
];
|
|
499
|
+
|
|
500
|
+
for (const payload of jsonPayloads) {
|
|
501
|
+
const response = await this.makeRequest(url, method, JSON.stringify(payload));
|
|
502
|
+
|
|
503
|
+
if (response.statusCode === 500) {
|
|
504
|
+
this.addVulnerability('MEDIUM', 'Insufficient Input Validation',
|
|
505
|
+
'Server error on malformed input', 'Implement proper input validation');
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Test oversized payload
|
|
511
|
+
const largePayload = JSON.stringify({ data: 'A'.repeat(10000000) }); // 10MB
|
|
512
|
+
const response = await this.makeRequest(url, method, largePayload);
|
|
513
|
+
|
|
514
|
+
if (response.statusCode === 200 || response.statusCode === 201) {
|
|
515
|
+
this.addVulnerability('LOW', 'No Payload Size Limit',
|
|
516
|
+
'Endpoint accepts very large payloads', 'Implement payload size limits');
|
|
517
|
+
}
|
|
518
|
+
},
|
|
519
|
+
|
|
520
|
+
async http(url) {
|
|
521
|
+
console.log('Testing HTTP Methods...');
|
|
522
|
+
|
|
523
|
+
const methods = ['OPTIONS', 'HEAD', 'PUT', 'DELETE', 'PATCH', 'TRACE'];
|
|
524
|
+
const allowedMethods = [];
|
|
525
|
+
|
|
526
|
+
for (const method of methods) {
|
|
527
|
+
const response = await this.makeRequest(url, method);
|
|
528
|
+
|
|
529
|
+
if (response.statusCode !== 405 && response.statusCode !== 501) {
|
|
530
|
+
allowedMethods.push(method);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if (allowedMethods.includes('TRACE')) {
|
|
535
|
+
this.addVulnerability('LOW', 'TRACE Method Enabled',
|
|
536
|
+
'TRACE method can lead to XST attacks', 'Disable TRACE method');
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (allowedMethods.length > 0) {
|
|
540
|
+
this.addResult('INFO', 'Allowed Methods', `Methods: ${allowedMethods.join(', ')}`);
|
|
541
|
+
}
|
|
542
|
+
},
|
|
543
|
+
},
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
module.exports = ApiAnalyzer;
|