@@ -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