-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrules.js
More file actions
422 lines (412 loc) · 16.1 KB
/
Copy pathrules.js
File metadata and controls
422 lines (412 loc) · 16.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
/*!
* JayShield by JayHackPro
* Find and remove web malware, webshells, and backdoors.
* Released under JayHackPro® Inc. Designed by Jayden Yoon ZK.
* MIT License: use it freely, and keep this notice. The brand stays behind the code.
* https://github.com/JayHackPro/JayShield
*/
/**
* The signature ruleset.
*
* Each rule describes a well-documented malware technique, not a single
* strain, so one rule catches a whole family and its copies. Signatures
* like these are the same kind of defensive definitions that ClamAV,
* Linux Malware Detect, and public YARA rule sets ship. They describe what
* hostile code looks like so it can be found and removed. They are not
* malware and cannot run.
*
* Fields:
* id stable identifier, used in reports and in --ignore-rule
* name short human title
* severity critical | high | medium | low
* category webshell | obfuscation | backdoor | exec | upload |
* injection | miner | skimmer | spam | test
* kinds file kinds the rule applies to, or ["any"]
* pattern a RegExp; the scanner reports the line of every match
* description one plain sentence on why this is suspicious
* references further reading
*/
/** Map a file extension to a coarse "kind" the rules can target. */
export function kindForPath(filePath) {
const lower = String(filePath).toLowerCase();
const dot = lower.lastIndexOf(".");
const ext = dot === -1 ? "" : lower.slice(dot + 1);
switch (ext) {
case "php":
case "php3":
case "php4":
case "php5":
case "php7":
case "phtml":
case "pht":
case "phar":
return "php";
case "js":
case "cjs":
case "mjs":
case "jsx":
case "ts":
return "js";
case "html":
case "htm":
case "xhtml":
case "shtml":
case "tpl":
return "html";
case "asp":
case "aspx":
case "ashx":
return "asp";
case "py":
return "python";
case "pl":
case "cgi":
return "perl";
case "sh":
case "bash":
return "shell";
default:
return "other";
}
}
export const RULES = [
// ----- PHP obfuscation: decode-then-run, the signature of almost every shell
{
id: "php.eval_decode",
name: "Obfuscated eval of a decoded payload",
severity: "critical",
category: "obfuscation",
kinds: ["php"],
pattern: /\b(?:eval|assert)\s*\(\s*(?:base64_decode|gzinflate|gzuncompress|gzdecode|str_rot13|convert_uudecode|hex2bin|pack|rawurldecode|urldecode)\s*\(/i,
description: "Code is hidden inside a decode call and run on the fly, the hallmark of a packed webshell.",
references: ["https://owasp.org/www-community/attacks/Web_Shell"]
},
{
id: "php.eval_user_input",
name: "eval of raw request input",
severity: "critical",
category: "backdoor",
kinds: ["php"],
pattern: /\b(?:eval|assert)\s*\(\s*(?:stripslashes\s*\(\s*)?\$_(?:GET|POST|REQUEST|COOKIE|SERVER|FILES)\b/i,
description: "Runs whatever an attacker sends in the request as PHP code, a direct backdoor.",
references: ["https://www.php.net/manual/en/function.eval.php"]
},
{
id: "php.preg_replace_e",
name: "preg_replace with the /e code modifier",
severity: "critical",
category: "backdoor",
kinds: ["php"],
pattern: /preg_replace\s*\(\s*(["'])(?:(?!\1).)*\/[a-z]*e[a-z]*\1/i,
description: "The removed /e modifier executes the replacement as PHP, a classic remote code path.",
references: ["https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php"]
},
{
id: "php.create_function",
name: "create_function dynamic code",
severity: "high",
category: "obfuscation",
kinds: ["php"],
pattern: /\bcreate_function\s*\(/i,
description: "Builds and runs code from strings at runtime, removed from PHP and now seen almost only in backdoors.",
references: ["https://www.php.net/manual/en/function.create-function.php"]
},
{
id: "php.variable_function_input",
name: "Variable function called from request input",
severity: "critical",
category: "backdoor",
kinds: ["php"],
pattern: /\$_(?:GET|POST|REQUEST|COOKIE)\s*\[[^\]]{0,40}\]\s*\(\s*\$_(?:GET|POST|REQUEST|COOKIE)\b/i,
description: "Lets the request pick both the function to call and its arguments, a compact universal backdoor.",
references: ["https://owasp.org/www-community/attacks/Web_Shell"]
},
{
id: "php.exec_user_input",
name: "Shell command built from request input",
severity: "critical",
category: "exec",
kinds: ["php"],
pattern: /\b(?:system|exec|shell_exec|passthru|popen|proc_open|pcntl_exec)\s*\(\s*(?:[^)]{0,60})?\$_(?:GET|POST|REQUEST|COOKIE|SERVER)\b/i,
description: "Passes attacker-controlled text to the operating system shell, remote command execution.",
references: ["https://owasp.org/www-community/attacks/Command_Injection"]
},
{
id: "php.call_user_func_input",
name: "Function name chosen by request input",
severity: "critical",
category: "backdoor",
kinds: ["php"],
pattern: /\bcall_user_func(?:_array)?\s*\(\s*\$_(?:GET|POST|REQUEST|COOKIE)\b/i,
description: "Lets the request name the function to run, a compact backdoor.",
references: ["https://owasp.org/www-community/attacks/Web_Shell"]
},
{
id: "php.extract_input",
name: "extract of request input",
severity: "medium",
category: "injection",
kinds: ["php"],
pattern: /\bextract\s*\(\s*\$_(?:GET|POST|REQUEST|SERVER|COOKIE)\b/i,
description: "Turns request keys into local variables, which lets an attacker overwrite values the code trusts.",
references: ["https://www.php.net/manual/en/function.extract.php"]
},
{
id: "php.reverse_shell",
name: "Reverse shell socket",
severity: "critical",
category: "backdoor",
kinds: ["php", "python", "perl"],
pattern: /\/bin\/(?:ba)?sh\s+-i|\bfsockopen\s*\([^)]{0,160}\)\s*;?\s*(?:\$\w+\s*=\s*)?(?:exec|shell_exec|proc_open|passthru|system|popen)\s*\(/i,
description: "Opens a network socket and hands a shell back to the attacker.",
references: ["https://owasp.org/www-community/attacks/Web_Shell"]
},
{
id: "php.char_obfuscation",
name: "Character-code string obfuscation",
severity: "medium",
category: "obfuscation",
kinds: ["php"],
pattern: /(?:chr\s*\(\s*\d+\s*\)\s*\.\s*){6,}/i,
description: "A string is assembled from many chr() calls to hide what it spells.",
references: ["https://owasp.org/www-community/attacks/Web_Shell"]
},
{
id: "php.hex_obfuscation",
name: "Long hex-escaped string",
severity: "medium",
category: "obfuscation",
kinds: ["php", "js"],
pattern: /(?:\\x[0-9a-f]{2}){12,}/i,
description: "A long run of hex escapes is a common way to hide function names and payloads.",
references: ["https://owasp.org/www-community/attacks/Web_Shell"]
},
{
id: "php.global_variable_function",
name: "Function call through GLOBALS or variable variable",
severity: "high",
category: "obfuscation",
kinds: ["php"],
pattern: /\$GLOBALS\s*\[[^\]]{1,30}\]\s*\(|\$\{\s*['"][^'"]+['"]\s*\}\s*\(/,
description: "Calls a function whose name is hidden behind an array or variable lookup to dodge simple scans.",
references: ["https://owasp.org/www-community/attacks/Web_Shell"]
},
{
id: "php.remote_include_eval",
name: "Remote payload fetched and run",
severity: "critical",
category: "backdoor",
kinds: ["php"],
pattern: /\b(?:eval|assert|include|require)(?:_once)?\s*\(\s*(?:file_get_contents|curl_exec|fopen)\s*\(/i,
description: "Downloads code from elsewhere and runs it, so the real payload never sits on disk.",
references: ["https://owasp.org/www-community/attacks/Web_Shell"]
},
{
id: "php.upload_handler",
name: "Unrestricted file upload handler",
severity: "low",
category: "upload",
kinds: ["php"],
pattern: /\bmove_uploaded_file\s*\(\s*\$_FILES\b/i,
description: "Accepts an uploaded file. Worth confirming it blocks executable types and a safe folder.",
references: ["https://owasp.org/www-community/attacks/Unrestricted_File_Upload"]
},
// ----- Known webshell family fingerprints
{
id: "shell.c99",
name: "c99 webshell",
severity: "critical",
category: "webshell",
kinds: ["php", "other"],
pattern: /c99sh(?:ell)?|c99_|\$c99/i,
description: "Fingerprint of the c99 webshell, a full remote file manager and command runner.",
references: ["https://owasp.org/www-community/attacks/Web_Shell"]
},
{
id: "shell.r57",
name: "r57 webshell",
severity: "critical",
category: "webshell",
kinds: ["php", "other"],
pattern: /r57shell|\$r57|r57\.gen/i,
description: "Fingerprint of the r57 webshell family.",
references: ["https://owasp.org/www-community/attacks/Web_Shell"]
},
{
id: "shell.wso",
name: "WSO webshell",
severity: "critical",
category: "webshell",
kinds: ["php", "other"],
pattern: /WSO(?:hex)?|wso_ex|\$default_charset\s*=.*['"]FilesMan['"]/i,
description: "Fingerprint of the WSO webshell, one of the most widely reused PHP shells.",
references: ["https://owasp.org/www-community/attacks/Web_Shell"]
},
{
id: "shell.b374k",
name: "b374k webshell",
severity: "critical",
category: "webshell",
kinds: ["php", "other"],
pattern: /b374k|\$b374k|b374k\s*shell/i,
description: "Fingerprint of the b374k webshell.",
references: ["https://owasp.org/www-community/attacks/Web_Shell"]
},
{
id: "shell.filesman",
name: "FilesMan webshell action",
severity: "high",
category: "webshell",
kinds: ["php", "other"],
pattern: /['"]FilesMan['"]|actbox|actarj/,
description: "The FilesMan action string is shared by a large family of copy-paste PHP shells.",
references: ["https://owasp.org/www-community/attacks/Web_Shell"]
},
{
id: "shell.generic_banner",
name: "Webshell banner text",
severity: "high",
category: "webshell",
kinds: ["php", "html", "other"],
pattern: /Hacked\s*By\b|Defaced\s*by\b|Powered\s*by\s*[A-Za-z0-9]+\s*Shell\b|\bShell\s*by\s*[A-Za-z0-9]+|Mass\s*Deface/i,
description: "Text seen on the pages that webshells and defacement kits print.",
references: ["https://owasp.org/www-community/attacks/Web_Shell"]
},
{
id: "php.password_gate",
name: "Hardcoded password gate",
severity: "high",
category: "backdoor",
kinds: ["php"],
pattern: /\b(?:md5|sha1|crc32|hash)\s*\(\s*\$_(?:GET|POST|REQUEST|COOKIE)\b[^)]{0,40}\)\s*===?\s*(['"])[0-9a-f]{16,64}\1/i,
description: "Hashes a request value and compares it to a fixed hash, the login check of a private backdoor.",
references: ["https://owasp.org/www-community/attacks/Web_Shell"]
},
// ----- JavaScript and HTML injection
{
id: "js.document_write_unescape",
name: "document.write of unescaped payload",
severity: "high",
category: "injection",
kinds: ["js", "html"],
pattern: /document\.write\s*\(\s*unescape\s*\(/i,
description: "Writes hidden markup into the page at load, a long-running site-injection pattern.",
references: ["https://owasp.org/www-community/attacks/xss/"]
},
{
id: "js.eval_decode",
name: "eval of a decoded string",
severity: "high",
category: "obfuscation",
kinds: ["js", "html"],
pattern: /\beval\s*\(\s*(?:atob|unescape|decodeURIComponent|String\.fromCharCode)\s*\(/i,
description: "Runs code that was decoded at the last moment to get past a quick read.",
references: ["https://owasp.org/www-community/attacks/xss/"]
},
{
id: "js.fromcharcode",
name: "Long fromCharCode obfuscation",
severity: "medium",
category: "obfuscation",
kinds: ["js", "html"],
pattern: /String\.fromCharCode\s*\(\s*(?:\d{1,3}\s*,\s*){15,}/i,
description: "A script assembled from many character codes to hide what it does.",
references: ["https://owasp.org/www-community/attacks/xss/"]
},
{
id: "js.hidden_iframe",
name: "Hidden or zero-size iframe",
severity: "high",
category: "injection",
kinds: ["html", "php", "js"],
pattern: /<iframe\b[^>]*(?:(?:width|height)\s*=\s*["']?\s*[01]\b|style\s*=\s*["'][^"']*(?:display\s*:\s*none|visibility\s*:\s*hidden|position\s*:\s*absolute[^"']*(?:top|left)\s*:\s*-?\d))/i,
description: "An invisible iframe usually delivers malware or ad fraud to visitors without a trace on the page.",
references: ["https://owasp.org/www-community/attacks/Content_Spoofing"]
},
{
id: "js.cookie_exfil",
name: "Cookie sent to an image or request",
severity: "high",
category: "skimmer",
kinds: ["js", "html"],
pattern: /(?:new\s+Image\s*\(\s*\)\s*\.\s*src|XMLHttpRequest|navigator\.sendBeacon)[^;\n]{0,80}document\.cookie/i,
description: "Copies the visitor session cookie off to another server, a session-theft skimmer.",
references: ["https://owasp.org/www-community/attacks/Session_hijacking_attack"]
},
{
id: "js.location_decode",
name: "Redirect to a decoded URL",
severity: "medium",
category: "injection",
kinds: ["js", "html"],
pattern: /(?:window\.)?location(?:\.href)?\s*=\s*(?:atob|unescape|decodeURIComponent)\s*\(/i,
description: "Sends visitors to a hidden address, common in traffic-selling and phishing injections.",
references: ["https://owasp.org/www-community/attacks/xss/"]
},
{
id: "js.packer",
name: "Packed eval(function(p,a,c,k,e",
severity: "low",
category: "obfuscation",
kinds: ["js", "html"],
pattern: /eval\s*\(\s*function\s*\(\s*p\s*,\s*a\s*,\s*c\s*,\s*k\s*,\s*e/i,
description: "The Dean Edwards packer. Used by some real libraries, but also to hide injected scripts, so worth a look.",
references: ["https://owasp.org/www-community/attacks/xss/"]
},
// ----- Cryptocurrency miners
{
id: "miner.browser",
name: "In-browser cryptocurrency miner",
severity: "high",
category: "miner",
kinds: ["js", "html", "php"],
pattern: /coinhive|coin-hive|cryptonight|CoinImp|deepMiner|webminepool|crypto-loot|cryptoloot|minero\.cc|coinpot|jsecoin/i,
description: "Loads a mining script that spends your visitors' devices and electricity for someone else.",
references: ["https://www.cisa.gov/news-events/news/defending-against-cryptojacking"]
},
// ----- SEO and pharma spam injection
{
id: "spam.hidden_links",
name: "Hidden link block",
severity: "medium",
category: "spam",
kinds: ["html", "php"],
pattern: /<(?:div|span)\b[^>]*style\s*=\s*["'][^"']*(?:display\s*:\s*none|position\s*:\s*absolute[^"']*left\s*:\s*-\d{3,})[^"']*["'][^>]*>\s*(?:<a\b[^>]*>[^<]*<\/a>\s*){2,}/i,
description: "A block of links hidden from visitors but read by search engines, the shape of injected spam.",
references: ["https://developers.google.com/search/docs/essentials/spam-policies"]
},
{
id: "spam.pharma",
name: "Pharma spam keywords in hidden markup",
severity: "low",
category: "spam",
kinds: ["html", "php"],
pattern: /(?:display\s*:\s*none|visibility\s*:\s*hidden)[^<]{0,120}(?:viagra|cialis|levitra|payday\s*loan|casino)\b/i,
description: "Hidden pharmacy or gambling keywords, a sign of an SEO spam infection.",
references: ["https://developers.google.com/search/docs/essentials/spam-policies"]
},
// ----- The industry-standard antivirus test file
{
id: "test.eicar",
name: "EICAR antivirus test file",
severity: "medium",
category: "test",
kinds: ["any"],
pattern: /EICAR-STANDARD-ANTIVIRUS-TEST-FILE/,
description: "The harmless EICAR test string. Not a threat, but every scanner should detect it, so this proves JayShield is working.",
references: ["https://www.eicar.org/download-anti-malware-testfile/"]
}
];
/** Compile a global-flagged copy of a rule pattern so we can find every hit. */
export function globalize(pattern) {
const flags = pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g";
return new RegExp(pattern.source, flags);
}
/** Return the rules that apply to a given file kind, honoring an ignore set. */
export function rulesForKind(kind, ignore = new Set()) {
return RULES.filter(
(rule) =>
!ignore.has(rule.id) &&
(rule.kinds.includes("any") || rule.kinds.includes(kind))
);
}