Skip to content

Commit f7dd88e

Browse files
committed
Enhanced SQL Injection Detection:
Added patterns for common SQLi in query parameters Included more SQL keywords and functions Added support for URL-encoded characters Improved Directory Traversal Detection: Added support for various encoded paths (%2e%2e, ..%2f, etc.) Added detection for Windows-style paths Added patterns for common sensitive files Better Query Parameter Handling: Now properly splits and checks both path and query parameters Added fullPath to parsed line objects for complete request analysis Enhanced Logging: Added detailed logging for detected attacks Included HTTP method in attack logs Added duplicate attack prevention Attack Tracking: Improved recent attacks tracking with more details Added better deduplication of similar attacks Limited to 100 most recent attacks
1 parent 4b5f86c commit f7dd88e

File tree

1 file changed

+77
-24
lines changed

1 file changed

+77
-24
lines changed

workers/logParser.js

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,19 @@ self.onmessage = (e) => {
5757
// Enhanced attack patterns with comprehensive security checks
5858
const attackPatterns = {
5959
"SQL Injection": new RegExp([
60-
// More comprehensive SQLi patterns
61-
"(?:%27|'|--|;|--\\s|/\\*.*?\\*/|#|%23)", // Basic SQLi indicators
62-
"\\b(?:UNION\\s+SELECT|SELECT\\s+.*?\\bFROM|INSERT\\s+INTO|DELETE\\s+FROM|UPDATE\\s+\\w+\\s+SET|DROP\\s+TABLE|CREATE\\s+TABLE|ALTER\\s+TABLE)\\b",
63-
"\\b(?:OR|AND)\\s+['\\d]\\s*[=<>]",
64-
"\\b(?:EXEC(?:UTE)?|EXEC\\s+SP_|XP_|sp_|xp_|WAITFOR\\s+DELAY)",
65-
"\\b(?:CHAR\\(|CONCAT\\()"
60+
// Basic SQLi indicators
61+
"(?:%27|'|--|;|--\\s|/\\*.*?\\*/|#|%23|%2527)",
62+
// SQL commands and patterns
63+
"\\b(?:UNION\\s+(?:ALL\\s+)?SELECT|SELECT\\s+.*?\\bFROM|INSERT\\s+INTO|DELETE\\s+FROM|UPDATE\\s+\\w+\\s+SET|DROP\\s+(?:TABLE|DATABASE)|CREATE\\s+(?:TABLE|DATABASE)|ALTER\\s+TABLE)\\b",
64+
// Logical operators and comparisons
65+
"\\b(?:OR|AND|X?OR|NOT|LIKE|RLIKE|REGEXP)\\s+['\\d]\\s*[=<>~!]?=",
66+
// Database functions and procedures
67+
"\\b(?:EXEC(?:UTE)?(?:\\(|\\s)|EXEC\\s+SP_|XP_|sp_|xp_|WAITFOR\\s+DELAY|SLEEP\\s*\\(|BENCHMARK\\s*\\(|PG_SLEEP\\s*\\(|UPDATEXML\\s*\\(|EXTRACTVALUE\\s*\\()",
68+
// String operations
69+
"\\b(?:CHAR\\(|CONCAT\\(|GROUP_CONCAT\\()",
70+
// Common SQLi in parameters
71+
"[?&][^=]+=(?:%27|'|%2527).*?(?:OR|AND|X?OR|NOT).*?=",
72+
"[?&][^=]+=.*?(?:--|#|%23|;)"
6673
].join('|'), 'i'),
6774

6875
"XSS": new RegExp([
@@ -93,15 +100,19 @@ self.onmessage = (e) => {
93100

94101
"Directory Traversal": new RegExp(
95102
// Match directory traversal sequences with at least two levels up
96-
'(?:^|/)(?:\\.{2}/){2,}' +
97-
'|(?:^|\\\\)(?:\\.{2}\\\\){2,}' + // Escaped backslashes for Windows paths
103+
'(?:^|/|\\\\)(?:\\.{1,2}[\./\\]){2,}' +
98104
// Match encoded traversal sequences
99-
'|(?:^|/)(?:%2e%2e[/\\\\]){2,}' +
105+
'|(?:^|/|\\)(?:%2e%2e|%252e%252e|%c0%ae%c0%ae|%u002e%u002e)[/\\\\]' +
100106
// Match absolute paths to sensitive files
101-
'|/etc/(?:passwd|shadow|group)(?:/|$|\\0)' +
102-
'|/proc/self/environ(?:/|$|\\0)' +
107+
'|/(?:etc/(?:passwd|shadow|group|hosts)|proc/self/environ|windows/win\.ini|boot\.ini|php\.ini|my\.cnf)(?:/|$|\\0)' +
103108
// Match Windows-style absolute paths
104-
'|^[a-zA-Z]:\\\\[^\\/]+',
109+
'|^[a-zA-Z]:\\\\[^\\/]+' +
110+
// Match common path traversal patterns
111+
'|\\.\\.(?:%2f|%252f|%5c|%255c)' +
112+
// Match null byte injection
113+
'|\\x00|%00|\\0' +
114+
// Match double encoding
115+
'|%25(?:2e|25|5c|2f|5f|3d|3f|26|3a|3b)',
105116
'i'
106117
),
107118

@@ -145,12 +156,18 @@ self.onmessage = (e) => {
145156
);
146157
if (!match) return null;
147158

159+
// Split path and query parameters
160+
const fullPath = match[5];
161+
const [path, query] = fullPath.split('?');
162+
148163
return {
149164
ipAddress: match[1],
150165
remoteUser: match[2],
151166
timestamp: match[3],
152167
method: match[4],
153-
path: match[5],
168+
path: path,
169+
query: query || '',
170+
fullPath: fullPath,
154171
status: match[6],
155172
bodyBytesSent: match[7],
156173
referer: match[8],
@@ -164,12 +181,18 @@ self.onmessage = (e) => {
164181
);
165182
if (!match) return null;
166183

184+
// Split path and query parameters for Apache
185+
const fullPath = match[5];
186+
const [path, query] = fullPath.split('?');
187+
167188
return {
168189
ipAddress: match[1],
169190
remoteUser: match[2],
170191
timestamp: match[3],
171192
method: match[4],
172-
path: match[5],
193+
path: path,
194+
query: query || '',
195+
fullPath: fullPath,
173196
status: match[6],
174197
bodyBytesSent: match[7] === "-" ? "0" : match[7],
175198
referer: "-",
@@ -259,20 +282,50 @@ self.onmessage = (e) => {
259282
}
260283

261284
let attackType = null;
285+
// Use the full path with query parameters for attack detection
286+
const fullPath = parsedLine.fullPath || path;
287+
288+
// Check for attacks in both path and query parameters
262289
for (const [type, pattern] of Object.entries(attackPatterns)) {
263-
if (pattern.test(path)) {
290+
if (pattern.test(fullPath)) {
291+
console.log(`[ATTACK DETECTED] Type: ${type}, Path: ${fullPath}`);
292+
293+
// Initialize attack type counter if it doesn't exist
294+
if (!stats.attackDistribution[type]) {
295+
stats.attackDistribution[type] = 0;
296+
}
297+
264298
stats.attackDistribution[type]++;
265299
stats.requestStats.totalAttackAttempts++;
266-
stats.ipStats.attackCounts[ipAddress]++;
300+
stats.ipStats.attackCounts[ipAddress] = (stats.ipStats.attackCounts[ipAddress] || 0) + 1;
267301
attackType = type;
268-
stats.recentAttacks.push({
269-
timestamp,
270-
ipAddress,
271-
remoteUser,
272-
attackType: type,
273-
requestPath: path,
274-
});
275-
break;
302+
303+
// Add to recent attacks if not already there (to avoid duplicates)
304+
const attackKey = `${ipAddress}:${type}:${path}`;
305+
const attackExists = stats.recentAttacks.some(attack =>
306+
`${attack.ipAddress}:${attack.attackType}:${attack.requestPath}` === attackKey
307+
);
308+
309+
if (!attackExists) {
310+
stats.recentAttacks.push({
311+
timestamp,
312+
ipAddress,
313+
remoteUser,
314+
attackType: type,
315+
requestPath: path,
316+
fullPath: fullPath, // Store full path for reference
317+
method: method // Include HTTP method
318+
});
319+
320+
// Keep only the 100 most recent attacks
321+
if (stats.recentAttacks.length > 100) {
322+
stats.recentAttacks.shift();
323+
}
324+
325+
console.log(`[NEW ATTACK] ${type} from ${ipAddress} at ${timestamp}: ${method} ${fullPath}`);
326+
}
327+
328+
// Don't break here to check for multiple attack types
276329
}
277330
}
278331

0 commit comments

Comments
 (0)