-
Notifications
You must be signed in to change notification settings - Fork 608
/
Copy pathplugin.js
3238 lines (2869 loc) · 112 KB
/
plugin.js
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
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
const plugin_version = '2022-0908-1700'
const plugin_name = 'official'
const plugin_desc = '官方插件'
/*
* Copyright 2017-2021 Baidu Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// 常用链接
//
// Web 攻击检测能力说明、零规则检测算法介绍
// https://rasp.baidu.com/doc/usage/web.html
//
// CVE 漏洞覆盖说明
// https://rasp.baidu.com/doc/usage/cve.html
'use strict'
var plugin = new RASP(plugin_name)
// 检测逻辑开关
//
// block -> 拦截,并打印报警日志
// log -> 打印日志,不拦截
// ignore -> 关闭这个算法
// BEGIN ALGORITHM CONFIG //
var algorithmConfig = {
// 快速设置
meta: {
// 若 all_log 开启,表示为观察模式,会将所有的 block 都改为 log
all_log: true,
// 若 is_dev 开启,表示为线下环境,将开启更多消耗性能的检测算法
is_dev: false,
// 若 log_event 开启,将打印应用行为信息到 plugin.log
log_event: false,
// schema 版本
schema_version: 1
},
// SQL注入算法#1 - 匹配用户输入
// 1. 用户输入长度至少 8
// 2. 用户输入至少包含一个SQL关键词 - 即 pre_filter,[默认关闭]
// 3. 用户输入完整的出现在SQL语句中,且会导致SQL语句逻辑发生变化
sql_userinput: {
name: '算法1 - 用户输入匹配算法',
action: 'block',
min_length: 8,
pre_filter: 'select|file|from|;',
pre_enable: false,
anti_detect_filter: 'add|all|alter|analyze|and|any|as|asc|avg|begin|between|by|case|create|count|delete|desc|do|dumpfile|else|elseif|end|exists|false|file|float|flush|follows|from|group|having|identified|if|in|insert|interval|into|join|last|like|limit|loop|not|null|on|or|order|procedure|regexp|return|rlike|select|then|true|union|update|values|xor',
anti_detect_enable: true,
lcs_search: false,
// 是否允许数据库管理器 - 前端直接提交SQL语句
allow_full: true
},
// SQL注入算法#2 - 语句规范
sql_policy: {
name: '算法2 - 拦截异常SQL语句',
action: 'block',
// 粗规则 - 为了减少 tokenize 次数,当SQL语句包含一定特征时才进入
// 另外,我们只需要处理增删改查的语句,虽然 show 语句也可以报错注入,但是算法2没必要处理
pre_filter: ';|\\/\\*|(?:\\d{1,2}\\s*,\\s*){2}|(?:null\\s*,\\s*){2}|0x[\\da-f]{8}|\\W(information_schema|outfile|dumpfile|load_file|benchmark|pg_sleep|sleep|is_srvrolemember|updatexml|extractvalue|hex|char|chr|mid|ord|ascii|bin)\\W',
feature: {
// 是否禁止多语句执行,select ...; update ...;
stacked_query: false,
// 是否禁止16进制字符串,select 0x41424344
no_hex: false,
// 禁止版本号注释,select/*!500001,2,*/3
version_comment: true,
// 函数黑名单,具体列表见下方,select load_file(...)
function_blacklist: true,
// 敏感函数频次, 具体列表见下方,select chr(123)||chr(123)||chr(123)=chr(123)||chr(123)||chr(123)
function_count: false,
// 拦截 union select NULL,NULL 或者 union select 1,2,3,4
union_null: true,
// 是否拦截 into outfile 写文件操作
into_outfile: true,
// 是否拦截 information_schema 相关读取操作,默认关闭
information_schema: false
},
function_blacklist: {
// 文件操作
load_file: true,
// 时间差注入
benchmark: true,
sleep: true,
pg_sleep: true,
// 探测阶段
is_srvrolemember: true,
// 报错注入
updatexml: true,
extractvalue: true,
// 盲注函数,如有误报可删掉一些函数
hex: false,
mid: false,
ord: false,
ascii: false,
bin: false
},
function_count: {
chr: 5,
char: 5
}
},
sql_exception: {
name: '算法3 - 记录数据库异常',
action: 'log',
reference: 'https://rasp.baidu.com/doc/dev/official.html#sql-exception',
// error_code 最多允许 100 个,超过直接清空
mysql: {
error_code: [
// 1045, // Access denied for user 'bae'@'10.10.1.1'
// 1690, // DOUBLE value is out of range in 'exp(~((select 'root@localhost' from dual)))'
1060, // Duplicate column name '5.5.60-0ubuntu0.14.04.1'
1062, // Duplicate entry '::root@localhost::1' for key 'group_key'
1064, // You have an error in your SQL syntax
1105, // XPATH syntax error: '~root@localhost~'
1367 // Illegal non geometric 'user()' value found during parsing
]
},
pgsql: {
error_code: [
"42601", // normal syntax error
"22P02", // ERROR: invalid input syntax for type double precision: "DATABASE: test1"
],
error_state: [
"42601", // normal syntax error
"22P02", // ERROR: invalid input syntax for type double precision: "DATABASE: test1"
]
},
sqlite: {
error_code: [
1, // generic error, like syntax error、malformed MATCH expression: ["3.6.23.1] and other
]
},
oracle: {
error_code: [
933, // SQL command not properly ended
29257, // host string unknown
20000, // Oracle Text error
904, // invalid identifier
19202, // Error occurred in XML processing
1756, // quoted string not properly terminated
1740, // missing double quote in identifier
920, // invalid relational operator
907, // missing right parenthesis
911, // invalid character
]
},
hsql: {
error_code: [
-5583, // malformed quoted identifier
-5584, // malformed string
-5590, // unexpected end of statement
],
error_state: [
"42583", // malformed quoted identifier
"42584", // malformed string
"42590", // unexpected end of statement
]
},
mssql: {
error_code: [
105, // Unclosed quotation mark after the character string '%.*ls'.
245, // Conversion failed when converting the %ls value '%.*ls' to data type %ls.
]
},
db2: {
error_state: [
"42603", // The string constant beginning with "'xxx" does not have an ending string
]
}
},
// 此算法仅用于应急,默认不开启,用户编写时应注意redos风险
sql_regex: {
name: '算法4 - 正则表达式算法',
action: 'ignore',
regex: 'information_schema'
},
// SSRF - 来自用户输入,且为内网地址就拦截
ssrf_userinput: {
name: '算法1 - 用户输入匹配算法(支持 rebind 检测)',
action: 'block'
},
// SSRF - 是否允许访问 aws metadata
ssrf_aws: {
name: '算法2 - 拦截 AWS/Aliyun/GCP metadata 访问',
action: 'block'
},
// SSRF - 是否允许访问 dnslog 地址
ssrf_common: {
name: '算法3 - 拦截常见 dnslog 地址',
action: 'block'
},
// SSRF - 是否允许访问混淆后的IP地址
ssrf_obfuscate: {
name: '算法4 - 拦截混淆地址',
action: 'ignore'
},
// SSRF - 禁止使用 curl 读取 file:///etc/passwd、php://filter/XXXX 这样的内容
ssrf_protocol: {
name: '算法5 - 拦截 php:// 等异常协议',
action: 'block',
protocols: [
'file',
'gopher',
// python specific
'local_file',
'local-file',
// java specific
'jar',
'netdoc',
// php specific
'dict',
'php',
'phar',
'compress.zlib',
'compress.bzip2'
]
},
// 任意文件下载防护 - 来自用户输入
readFile_userinput: {
name: '算法1 - 用户输入匹配算法',
action: 'block',
lcs_search: false
},
// 任意文件下载防护 - 使用 file_get_contents 等函数读取 http(s):// 内容(注意,这里不区分是否为内网地址)
readFile_userinput_http: {
name: '算法2 - 用户输入匹配算法 + http 协议',
action: 'block'
},
// 任意文件下载防护 - 使用 file_get_contents 等函数读取 file://、php:// 协议
readFile_userinput_unwanted: {
name: '算法3 - 拦截 php:// 等异常协议',
action: 'block'
},
// 任意文件下载防护 - 使用 ../../ 跳出 web 目录读取敏感文件
readFile_outsideWebroot: {
name: '算法4 - 禁止使用 ../../ 访问web目录以外的文件',
action: 'ignore',
reference: 'https://rasp.baidu.com/doc/dev/official.html#case-out-webroot'
},
// 任意文件下载防护 - 读取敏感文件,最后一道防线
readFile_unwanted: {
name: '算法5 - 文件探针算法',
action: 'log'
},
// 写文件操作 - NTFS 流
writeFile_NTFS: {
name: '算法1 - 拦截 NTFS ::$DATA 写入操作',
action: 'block'
},
// 写文件操作 - PUT 上传脚本文件 - 无法关联实际上传的文件和写文件操作,暂时注释掉
// writeFile_PUT_script: {
// name: '算法2 - 拦截 PUT 方式上传 php/jsp 等脚本文件',
// action: 'block'
// },
// 写文件操作 - 脚本文件
// https://rasp.baidu.com/doc/dev/official.html#case-file-write
writeFile_script: {
name: '算法2 - 拦截 php/jsp 等脚本文件的写入操作',
reference: 'https://rasp.baidu.com/doc/dev/official.html#case-file-write',
action: 'block',
userinput: true,
lcs_search: false
},
writeFile_reflect: {
name: '算法3 - 拦截通过反射、反序列化执行的文件写入操作',
action: 'log'
},
// 任意文件删除 - 使用 ../跳出目录
deleteFile_userinput: {
name: '算法1 - 用户输入匹配,禁止使用 ../ 删除文件',
action: 'block',
lcs_search: false
},
// 重命名监控 - 将普通文件重命名为webshell,
// 案例有 MOVE 方式上传后门、CVE-2018-9134 dedecms v5.7 后台重命名 getshell
rename_webshell: {
name: '算法1 - 通过重命名方式获取 WebShell',
action: 'block'
},
// copy_webshell: {
// action: 'block'
// },
link_webshell: {
name: '算法1 - 通过链接方式获取 WebShell',
action: 'block'
},
// 文件管理器 - 用户输入匹配,仅当直接读取绝对路径时才检测
directory_userinput: {
name: '算法1 - 用户输入匹配算法',
action: 'block',
lcs_search: false
},
// 文件管理器 - 反射方式列目录
directory_reflect: {
name: '算法2 - 通过反射调用,查看目录内容',
action: 'block'
},
// 文件管理器 - 查看敏感目录
directory_unwanted: {
name: '算法3 - 尝试查看敏感目录',
action: 'log'
},
// 文件包含 - 用户输入匹配
include_userinput: {
name: '算法1 - 用户输入匹配算法',
action: 'block',
lcs_search: false
},
// 文件包含 - 特殊协议
include_protocol: {
name: '算法2 - 尝试包含 jar:// 等异常协议',
action: 'block',
protocols: [
'file',
'gopher',
// java specific
'jar',
'netdoc',
// php stream
'http',
'https',
// php specific
'dict',
'php',
// 'phar',
'compress.zlib',
'compress.bzip2',
'zip',
'rar'
]
},
// XXE - 代码安全开关,通过调用相关函数直接禁止外部实体
xxe_disable_entity: {
name: '算法1 - 禁止外部实体加载(记录日志等同于完全忽略)',
action: 'ignore',
clazz: {
// com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderFactoryImpl
java_dom: true,
// org/dom4j/io/SAXReader
java_dom4j: true,
// org/jdom/input/SAXBuilder,org/jdom2/input/SAXBuilder
java_jdom: true,
// com/sun/org/apache/xerces/internal/jaxp/SAXParserFactoryImpl
java_sax: true,
// javax/xml/stream/XMLInputFactory
java_stax: true
}
},
// XXE - 使用 gopher/ftp/dict/.. 等不常见协议访问外部实体
xxe_protocol: {
name: '算法2 - 使用 ftp:// 等异常协议加载外部实体',
action: 'block',
protocols: [
'ftp',
'dict',
'gopher',
// 'jar', // jenkins下存在误报
'netdoc',
'mailto'
]
},
// XXE - 使用 file 协议读取内容,可能误报,默认 log
xxe_file: {
name: '算法3 - 使用 file:// 协议读取文件',
reference: 'https://rasp.baidu.com/doc/dev/official.html#case-xxe',
action: 'log',
},
// 文件上传 - COPY/MOVE 方式,仅适合 tomcat
fileUpload_webdav: {
name: '算法1 - MOVE 方式上传脚本文件',
action: 'block'
},
// 文件上传 - Multipart 方式上传脚本文件
fileUpload_multipart_script: {
name: '算法2 - Multipart 方式上传 PHP/JSP 等脚本文件',
action: 'block'
},
// 文件上传 - Multipart 方式上传 HTML/JS 等文件
fileUpload_multipart_html: {
name: '算法3 - Multipart 方式上传 HTML/JS 等文件',
action: 'ignore'
},
// 文件上传 - Multipart 方式上传 DLL/EXE 等文件
fileUpload_multipart_exe: {
name: '算法3 - Multipart 方式上传 DLL/EXE 等文件',
action: 'ignore'
},
// OGNL 代码执行漏洞
ognl_blacklist: {
name: '算法1 - OGNL语句黑名单',
action: 'block',
expression: [
'ognl.OgnlContext',
'ognl.TypeConverter',
'ognl.MemberAccess',
'_memberAccess',
'ognl.ClassResolver',
'java.lang.Runtime',
'java.lang.Class',
'java.lang.ClassLoader',
'java.lang.System',
'java.lang.ProcessBuilder',
'java.lang.Object',
'java.lang.Shutdown',
'java.io.File',
'javax.script.ScriptEngineManager',
'excludedClasses',
'excludedPackageNamePatterns',
'excludedPackageNames',
'com.opensymphony.xwork2.ActionContext'
]
},
// OGNL 表达式长度限制
ognl_length_limit: {
name: '算法2 - OGNL表达式长度限制',
action: 'log',
max_length: 400
},
// 命令执行 - java 反射、反序列化,php eval 等方式
command_reflect: {
name: '算法1 - 通过反射执行命令,比如反序列化、加密后门',
action: 'block'
},
// 命令注入 - 命令执行后门,或者命令注入
command_userinput: {
name: '算法2 - 用户输入匹配算法,包括命令注入检测',
action: 'block',
min_length: 2,
java_unexploitable_filter: true,
},
// 命令注入 - 常见命令
command_common: {
name: '算法3 - 识别常用渗透命令(探针)',
action: 'log',
pattern: 'cat.{1,5}/etc/passwd|nc.{1,30}-e.{1,100}/bin/(?:ba)?sh|bash\\s-.{0,4}i.{1,20}/dev/tcp/|subprocess.call\\(.{0,6}/bin/(?:ba)?sh|fsockopen\\(.{1,50}/bin/(?:ba)?sh|perl.{1,80}socket.{1,120}open.{1,80}exec\\(.{1,5}/bin/(?:ba)?sh|\\{echo,.{10,400}{base64,-d}'
},
// 命令执行 - 语法错误和敏感操作
command_error: {
name: '算法4 - 查找语法错误和敏感操作',
action: 'log',
unbalanced_quote_enable: true,
sensitive_cmd_enable: true,
concat_char: ["|", ";"],
sensitive_cmd: ["curl", "bash", "cat", "sh"],
alarm_token_enable: true,
alarm_token: ["$IFS", "${IFS}"]
},
// 命令执行 - 是否拦截所有命令执行?如果没有执行命令的需求,可以改为 block,最大程度的保证服务器安全
command_other: {
name: '算法5 - 记录或者拦截所有命令执行操作',
action: 'ignore'
},
// 命令注入 - dnslog
command_dnslog: {
name: '算法6 - dnslog类命令',
action: 'log',
pattern_cmd: '(^|\\W)(curl|ping|wget|nslookup|dig)\\W',
pattern_domain: '\\.((ceye|exeye|sslip|nip)\\.io|dnslog\\.cn|(vcap|bxss)\\.me|xip\\.(name|io)|burpcollaborator\\.net|tu4\\.org|2xss\\.cc|request\\.bin|requestbin\\.net|pipedream\\.net)'
},
// transformer 反序列化攻击
deserialization_blacklist: {
name: '算法1 - 反序列化黑名单过滤',
action: 'block',
clazz: [
'org.apache.commons.collections.functors.ChainedTransformer',
'org.apache.commons.collections.functors.InvokerTransformer',
'org.apache.commons.collections.functors.InstantiateTransformer',
'org.apache.commons.collections4.functors.InvokerTransformer',
'org.apache.commons.collections4.functors.InstantiateTransformer',
'org.codehaus.groovy.runtime.ConvertedClosure',
'org.codehaus.groovy.runtime.MethodClosure',
'org.springframework.beans.factory.ObjectFactory',
'org.apache.xalan.xsltc.trax.TemplatesImpl',
'com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl',
'com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase'
]
},
jndi_disable_all: {
name: '算法1 - 拦截所有JNDI调用',
action: 'block'
},
dns_blacklist: {
name: '算法1 - 拦截DNS黑名单查询(比如DNSLog)',
action: 'block'
},
// xss 用户输入匹配算法
// 1. 当用户输入长度超过15,匹配上标签正则,且出现在响应里,直接拦截
// 2. 当用户输入长度超过15,匹配上标签正则这样的参数个数超过 10,判定为扫描攻击,直接拦截(v1.1.2 之后废弃)
xss_userinput: {
name: '算法2 - 拦截输出在响应里的反射XSS',
action: 'ignore',
filter_regex: "<![\\-\\[A-Za-z]|<([A-Za-z]{1,12})[\\/>\\x00-\\x20]",
min_length: 15,
// v1.1.2 之后废弃
max_detection_num: 10
},
// php 专有算法
xss_echo: {
name: '算法1 - PHP: 禁止直接输出GPC参数',
action: 'log',
filter_regex: "<![\\-\\[A-Za-z]|<([A-Za-z]{1,12})[\\/>\\x00-\\x20]"
},
webshell_eval: {
name: '算法1 - 拦截简单的PHP中国菜刀后门',
action: 'block'
},
webshell_command: {
name: '算法2 - 拦截简单的PHP命令执行后门',
action: 'block'
},
webshell_file_put_contents: {
name: '算法3 - 拦截简单的PHP文件上传后门',
action: 'block'
},
webshell_callable: {
name: '算法4 - 拦截简单的PHP array_map/walk/filter 后门',
action: 'block',
functions: [
'system', 'exec', 'passthru', 'proc_open', 'shell_exec', 'popen', 'pcntl_exec', 'assert'
]
},
webshell_ld_preload: {
name: '算法5 - 拦截PHP putenv 相关后门',
action: 'block',
env: [
'LD_PRELOAD',
'LD_AUDIT',
'GCONV_PATH'
]
},
eval_regex: {
name: '算法1 - 正则表达式',
action: 'ignore',
regex: 'base64_decode|gzuncompress|create_function'
},
loadLibrary_unc: {
name: '算法1 - 拦截 UNC 路径类库加载',
action: 'block'
},
// loadLibrary_other: {
// name: '算法2 - 记录或者拦截所有类库加载',
// action: 'ignore'
// },
response_dataLeak: {
name: '算法1 - 检查响应里是否有敏感信息',
action: 'ignore',
// 检查类型
kind: {
phone: true,
identity_card: true,
bank_card: true
},
// Content-Type 过滤
content_type: 'html|json|xml'
}
}
// END ALGORITHM CONFIG //
// 配置挂载到全局 RASP 变量
RASP.algorithmConfig = algorithmConfig
const clean = {
action: 'ignore',
message: 'Looks fine to me',
confidence: 0
}
var forcefulBrowsing = {
dotFiles: /\.(7z|tar|gz|bz2|xz|rar|zip|sql|db|sqlite)$/,
nonUserDirectory: /^\/(proc|sys|root)/,
// webdav 文件探针 - 最常被下载的文件
unwantedFilenames: [
// user files
'.DS_Store',
'id_rsa', 'id_rsa.pub', 'known_hosts', 'authorized_keys',
'.bash_history', '.csh_history', '.zsh_history', '.mysql_history',
// project files
'.htaccess', '.user.ini',
'web.config', 'web.xml', 'build.property.xml', 'bower.json',
'Gemfile', 'Gemfile.lock',
'.gitignore',
'error_log', 'error.log', 'nohup.out',
],
// 目录探针 - webshell 查看频次最高的目录
unwantedDirectory: [
'/',
'/home',
'/var/log',
'/private/var/log',
'/proc',
'/sys',
'C:\\',
'D:\\',
'E:\\'
],
// 文件探针 - webshell 查看频次最高的文件
absolutePaths: [
'/etc/issue',
'/etc/shadow',
'/etc/passwd',
// '/etc/hosts',
'/etc/apache2/apache2.conf',
'/root/.bash_history',
'/root/.bash_profile',
'c:\\windows\\system32\\inetsrv\\metabase.xml',
'c:\\windows\\system32\\drivers\\etc\\hosts'
]
}
// 指定检测header注入时检测的header名, 统一使用小写
var headerInjection = ["user-agent", "referer", "x-forwarded-for"]
// 如果你配置了非常规的扩展名映射,比如让 .abc 当做PHP脚本执行,那你可能需要增加更多扩展名
var scriptFileRegex = /\.(aspx?|jspx?|php[345]?|phar|phtml|sh|py|pl|rb|so|dll|dylib)\.?$/i
// 正常文件
var cleanFileRegex = /\.(jpg|jpeg|png|gif|bmp|txt|rar|zip)$/i
// 文件读取扩展名白名单,包含 压缩文件 office文件 图片文件
var readFileWhiteExt = new RegExp(/\.(do[c|t][x|m|]?|xl[s|t][x|m|b]?|pp[t|s|a][x|m]?|pot[x|m]|7z|tar|gz|bz2|xz|rar|zip|jpg|jpeg|png|gif|bmp|txt|)$/, 'i')
// 匹配 HTML/JS 等可以用于钓鱼、domain-fronting 的文件
var htmlFileRegex = /\.(htm|html|js)$/i
// 匹配 EXE/DLL 等可以执行的文件
var exeFileRegex = /\.(exe|dll|scr|vbs|cmd|bat)$/i
// 其他的 stream 都没啥用
var ntfsRegex = /::\$(DATA|INDEX)$/
// 已知用户输入匹配算法误报: 传入 1,2,3,4 -> IN(1,2,3,4) 和 传入 column_name, column_pass -> select column_name, column_pass from xxx
var commaSeparatedRegex = /^(, *)?(([a-zA-Z_]\w*|[0-9+\-x\.]+) *, *)+([a-zA-Z_]\w*|[0-9+\-x\.]+)$/
// 匹配内网地址
var internalRegex = /^(0\.0\.0|127|10|192\.168|172\.(1[6-9]|2[0-9]|3[01]))\./
// ssrf白名单主机名
var whiteHostName = /\.bcebos\.com$|(^|\.)oss-[\d\w\-]{0,30}\.aliyuncs\.com$/
var dnsLogDomains = [
'.vuleye.pw', '.ceye.io', '.exeye.io', '.vcap.me', '.xip.name', '.xip.io', '.sslip.io', '.nip.io', '.oastify.com', '.eyes.sh',
'.burpcollaborator.net', '.tu4.org', '.2xss.cc', '.bxss.me', '.godns.vip', '.dnslog.cn', '.0kee.360.cn', '.r87.me','.ngrok.io',
// yumusb/DNSLog-Platform-Golang
'.xn--9tr.com',
// requestbin 新地址
'.pipedream.net',
// 端口转发工具
'.vxtrans.com', '.vxtrans.link',
// 免费DDNS厂商
'.hopto.org', '.zapto.org', '.sytes.net', '.ddns.net',
// 其他
'.canarytokens.com'
]
// SQL注入算法1 - 预过滤正则
var sqliPrefilter1 = new RegExp(algorithmConfig.sql_userinput.pre_filter, 'i')
// SQL注入算法1 - 反探测正则
var sqliAntiDetect = new RegExp(algorithmConfig.sql_userinput.anti_detect_filter, 'i')
// SQL注入算法2 - 预过滤正则
var sqliPrefilter2 = new RegExp(algorithmConfig.sql_policy.pre_filter, 'i')
// SQL注入算法 - 管理器白名单
var sqliWhiteManager = new RegExp(/phpmyadmin/, 'i')
// java 匹配可能可利用的命令注入
var cmdJavaExploitable = new RegExp(/^[^ ]*sh.{1,12}-c/, 'i')
// 命令执行探针 - 常用渗透命令
var cmdPostPattern = new RegExp(algorithmConfig.command_common.pattern, 'i')
// 命令执行探针 - dnslog命令
var cmdDNSlogPatternCmd = new RegExp(algorithmConfig.command_dnslog.pattern_cmd)
var cmdDNSlogPatternDomain = new RegExp(algorithmConfig.command_dnslog.pattern_domain, 'i')
// 敏感信息泄露 - Content Type 正则
var dataLeakContentType = new RegExp(algorithmConfig.response_dataLeak.content_type, 'i')
if (! RASP.is_unittest)
{
// 记录日志模式: 将所有 block 改为 log
if (algorithmConfig.meta.all_log)
{
Object.keys(algorithmConfig).forEach(function (name) {
// XXE 外部实体开关不受影响
if (name != 'xxe_disable_entity')
{
if (algorithmConfig[name].action == 'block')
{
algorithmConfig[name].action = 'log'
}
}
})
}
// 研发模式:
// 1. 开启更多消耗性能的检测算法
// 2. 非攻击情况,检测到漏洞也报警
if (algorithmConfig.meta.is_dev)
{
// 关闭 select 预过滤正则
algorithmConfig.sql_userinput.pre_enable = false
// 关闭 1,2,3 误报过滤
commaSeparatedRegex = /^$/
// 关闭 xss_echo 非攻击过滤
algorithmConfig.xss_echo.filter_regex = ""
}
}
else {
algorithmConfig.eval_regex.action = "log"
}
// 校验 sql_regex 正则是否合法
if (algorithmConfig.sql_regex.action != 'ignore') {
if (! algorithmConfig.sql_regex.regex.trim()) {
plugin.log ("algorithmConfig.sql_regex.regex is empty, algorithm disabled")
algorithmConfig.sql_regex.action = 'ignore'
} else {
try {
new RegExp(algorithmConfig.sql_regex)
} catch (e) {
plugin.log ("Invalid regex in algorithmConfig.sql_regex.regex: ", e)
algorithmConfig.sql_regex.action = 'ignore'
}
}
}
// 校验 eval_regex 正则是否合法
if (algorithmConfig.eval_regex.action != 'ignore') {
if (! algorithmConfig.eval_regex.regex.trim()) {
plugin.log ("algorithmConfig.eval_regex.regex is empty, algorithm disabled")
algorithmConfig.eval_regex.action = 'ignore'
} else {
try {
new RegExp(algorithmConfig.eval_regex)
} catch (e) {
plugin.log ("Invalid regex in algorithmConfig.eval_regex.regex: ", e)
algorithmConfig.eval_regex.action = 'ignore'
}
}
}
// 常用函数
String.prototype.replaceAll = function(token, tokenValue, maxLength) {
if (maxLength === undefined) {
if (this.length * 2 < 4096) {
maxLength = 4096
} else {
maxLength = this.length * 2
}
}
// 空值判断,防止死循环
if (! token || token.length == 0 || this.length > maxLength) {
return this
}
var index = 0;
var string = this;
do {
string = string.replace(token, tokenValue);
} while((index = string.indexOf(token, index)) > -1);
return string
}
// function canonicalPath (path) {
// return path.replaceAll('/./', '/').replaceAll('//', '/').replaceAll('//', '/')
// }
// 我们不再需要简化路径,当出现两个 /../ 或者两个 \..\ 就可以判定为路径遍历攻击了,e.g
// /./././././home/../../../../etc/passwd
// \\..\\..\\..
// \/..\/..\/..
function has_traversal (path) {
// 左右斜杠,一视同仁
var path2 = "/" + path.replaceAll('\\', '/') + "/"
// 覆盖 ../../
// 以及 /../../
var left = path2.indexOf('/../')
var right = path2.lastIndexOf('/../')
if (left != -1 && right != -1 && left != right)
{
return true
}
return false
}
// 判断参数是否包含路径穿越,比path更严格
function param_has_traversal (param) {
// 左右斜杠,一视同仁
var path = "/" + param.replaceAll('\\', '/') + "/"
if (path.indexOf("/../") != -1)
{
return true
}
return false
}
function is_hostname_dnslog(hostname) {
for (var i = 0; i < dnsLogDomains.length; i ++)
{
if (hostname.toLowerCase().endsWith(dnsLogDomains[i]))
{
return true
}
}
return false
}
// function basename (path) {
// // 简单处理,同时支持 windows/linux
// var path2 = path.replaceAll('\\', '/')
// var idx = path2.lastIndexOf('/')
// return path.substr(idx + 1)
// }
// function has_file_extension(path) {
// var filename = basename(path)
// var index = filename.indexOf('.')
// if (index > 0 && index != filename.length - 1) {
// return true
// }
// return false
// }
function is_method_from_rasp(stack) {
// 检查栈顶 -> rasp堆栈之间,是否包含用户代码,即非 JDK相关的函数
for (; i < stacks.length; i ++) {
var method = stacks[i]
if (! method.startsWith('java.')
&& !method.startsWith('sun.')
&& !method.startsWith('com.sun.'))
{
return false
}
}
return true
}
function validate_stack_java(stacks) {
var known = {
'com.thoughtworks.xstream.XStream.unmarshal': "Using xstream library",
'java.beans.XMLDecoder.readObject': "Using WebLogic XMLDecoder library",
'org.apache.commons.collections4.functors.InvokerTransformer.transform': "Using Transformer library (v4)",
'org.apache.commons.collections.functors.InvokerTransformer.transform': "Using Transformer library",
'org.apache.commons.collections.functors.ChainedTransformer.transform': "Using Transformer library",
'org.jolokia.jsr160.Jsr160RequestDispatcher.dispatchRequest': "Using JNDI library (JSR 160)",
'com.sun.jndi.rmi.registry.RegistryContext.lookup': "Using JNDI registry service",
'org.apache.xbean.propertyeditor.JndiConverter': "Using JNDI binding class",
'com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig': "Using JTA transaction manager",
'com.sun.jndi.url.ldap.ldapURLContext.lookup': "Using LDAP factory service",
'com.alibaba.fastjson.JSON.parse': "Using fastjson library",
'com.alibaba.fastjson.JSON.parseObject': "Using fastjson library",
'com.alibaba.fastjson.JSON.parseArray': "Using fastjson library",
'org.springframework.expression.spel.support.ReflectiveMethodExecutor.execute': "Using SpEL expressions",
'freemarker.template.utility.Execute.exec': "Using FreeMarker template",
'org.jboss.el.util.ReflectionUtil.invokeMethod': "Using JBoss EL method",
'org.codehaus.groovy.runtime.ProcessGroovyMethods.execute': "Using Groovy library",
'bsh.Reflect.invokeMethod': "Using BeanShell library",
'jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptFunction.invoke': "Using Nashorn engine",
'org.apache.shiro.io.DefaultSerializer.deserialize': "Using Shiro framework (DefaultSerializer)",
'com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase.readObject': "Using C3p0 library"
}
var userCode = false, reachedInvoke = false, i = 0, message = undefined
// v1.1.1 要求在堆栈里过滤 com.baidu.openrasp 相关的类,因为没有实现正确而产生了多余的反射堆栈,这里需要兼容下防止误报
// v1.1.2 修复了这个问题,即堆栈顶部为命令执行的方法
if (stacks.length > 3
&& stacks[0].startsWith('sun.reflect.GeneratedMethodAccessor')
&& stacks[1] == 'sun.reflect.GeneratedMethodAccessorImpl.invoke'
&& stacks[2] == 'java.lang.reflect.Method.invoke')
{
i = 3
}
for (; i < stacks.length; i ++) {
var method = stacks[i]
// 检查反射调用 -> 命令执行之间,是否包含用户代码
if (! reachedInvoke) {
if (method == 'java.lang.reflect.Method.invoke') {
reachedInvoke = true
}
// 用户代码,即非 JDK、com.baidu.openrasp 相关的函数
if (! method.startsWith('java.')
&& !method.startsWith('sun.')
&& !method.startsWith('com.sun.')
&& !method.startsWith('com.baidu.openrasp.'))
{
userCode = true
}
}
if (method.startsWith('ysoserial.Pwner')) {
message = "Using YsoSerial tool"
break