contrast-agent 3.8.4
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.
- checksums.yaml +7 -0
- data/.clang-format +5 -0
- data/.dockerignore +10 -0
- data/.gitignore +58 -0
- data/.gitmodules +6 -0
- data/.rspec +6 -0
- data/.simplecov +4 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +12 -0
- data/Rakefile +15 -0
- data/exe/contrast_service +29 -0
- data/ext/build_funchook.rb +48 -0
- data/ext/cs__assess_active_record_named/cs__active_record_named.c +47 -0
- data/ext/cs__assess_active_record_named/cs__active_record_named.h +10 -0
- data/ext/cs__assess_active_record_named/extconf.rb +2 -0
- data/ext/cs__assess_array/cs__assess_array.c +38 -0
- data/ext/cs__assess_array/cs__assess_array.h +9 -0
- data/ext/cs__assess_array/extconf.rb +2 -0
- data/ext/cs__assess_basic_object/cs__assess_basic_object.c +50 -0
- data/ext/cs__assess_basic_object/cs__assess_basic_object.h +17 -0
- data/ext/cs__assess_basic_object/extconf.rb +2 -0
- data/ext/cs__assess_fiber_track/cs__assess_fiber_track.c +86 -0
- data/ext/cs__assess_fiber_track/cs__assess_fiber_track.h +34 -0
- data/ext/cs__assess_fiber_track/extconf.rb +2 -0
- data/ext/cs__assess_hash/cs__assess_hash.c +64 -0
- data/ext/cs__assess_hash/cs__assess_hash.h +24 -0
- data/ext/cs__assess_hash/extconf.rb +2 -0
- data/ext/cs__assess_kernel/cs__assess_kernel.c +36 -0
- data/ext/cs__assess_kernel/cs__assess_kernel.h +10 -0
- data/ext/cs__assess_kernel/extconf.rb +2 -0
- data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +47 -0
- data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +18 -0
- data/ext/cs__assess_marshal_module/extconf.rb +2 -0
- data/ext/cs__assess_module/cs__assess_module.c +78 -0
- data/ext/cs__assess_module/cs__assess_module.h +25 -0
- data/ext/cs__assess_module/extconf.rb +2 -0
- data/ext/cs__assess_regexp/cs__assess_regexp.c +48 -0
- data/ext/cs__assess_regexp/cs__assess_regexp.h +22 -0
- data/ext/cs__assess_regexp/extconf.rb +2 -0
- data/ext/cs__assess_regexp_track/cs__assess_regexp_track.c +63 -0
- data/ext/cs__assess_regexp_track/cs__assess_regexp_track.h +29 -0
- data/ext/cs__assess_regexp_track/extconf.rb +2 -0
- data/ext/cs__assess_string/cs__assess_string.c +38 -0
- data/ext/cs__assess_string/cs__assess_string.h +19 -0
- data/ext/cs__assess_string/extconf.rb +2 -0
- data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.c +31 -0
- data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.h +13 -0
- data/ext/cs__assess_string_interpolation26/extconf.rb +2 -0
- data/ext/cs__common/cs__common.c +60 -0
- data/ext/cs__common/cs__common.h +28 -0
- data/ext/cs__common/extconf.rb +20 -0
- data/ext/cs__contrast_patch/cs__contrast_patch.c +445 -0
- data/ext/cs__contrast_patch/cs__contrast_patch.h +196 -0
- data/ext/cs__contrast_patch/extconf.rb +2 -0
- data/ext/cs__protect_kernel/cs__protect_kernel.c +37 -0
- data/ext/cs__protect_kernel/cs__protect_kernel.h +11 -0
- data/ext/cs__protect_kernel/extconf.rb +2 -0
- data/ext/cs__scope/cs__scope.c +96 -0
- data/ext/cs__scope/cs__scope.h +33 -0
- data/ext/cs__scope/extconf.rb +2 -0
- data/ext/extconf_common.rb +49 -0
- data/funchook/LICENSE +360 -0
- data/funchook/Makefile +29 -0
- data/funchook/Makefile.in +29 -0
- data/funchook/README.md +121 -0
- data/funchook/appveyor.yml +42 -0
- data/funchook/autogen.sh +3 -0
- data/funchook/autom4te.cache/output.0 +4976 -0
- data/funchook/autom4te.cache/requests +78 -0
- data/funchook/autom4te.cache/traces.0 +364 -0
- data/funchook/config.guess +1530 -0
- data/funchook/config.log +490 -0
- data/funchook/config.status +1016 -0
- data/funchook/config.sub +1773 -0
- data/funchook/configure +4976 -0
- data/funchook/configure.ac +59 -0
- data/funchook/distorm/COPYING +26 -0
- data/funchook/distorm/MANIFEST +25 -0
- data/funchook/distorm/MANIFEST.in +4 -0
- data/funchook/distorm/README.md +12 -0
- data/funchook/distorm/disOps/disOps.py +795 -0
- data/funchook/distorm/disOps/x86db.py +404 -0
- data/funchook/distorm/disOps/x86header.py +247 -0
- data/funchook/distorm/disOps/x86sets.py +1664 -0
- data/funchook/distorm/examples/cs/TestdiStorm/Program.cs +79 -0
- data/funchook/distorm/examples/cs/TestdiStorm/Properties/AssemblyInfo.cs +36 -0
- data/funchook/distorm/examples/cs/TestdiStorm/TestdiStorm.csproj +69 -0
- data/funchook/distorm/examples/cs/distorm-net.sln +26 -0
- data/funchook/distorm/examples/cs/distorm-net/CodeInfo.cs +23 -0
- data/funchook/distorm/examples/cs/distorm-net/DecodedInst.cs +15 -0
- data/funchook/distorm/examples/cs/distorm-net/DecodedResult.cs +14 -0
- data/funchook/distorm/examples/cs/distorm-net/DecomposedInst.cs +36 -0
- data/funchook/distorm/examples/cs/distorm-net/DecomposedResult.cs +14 -0
- data/funchook/distorm/examples/cs/distorm-net/Opcodes.cs +1268 -0
- data/funchook/distorm/examples/cs/distorm-net/Opcodes.tt +37 -0
- data/funchook/distorm/examples/cs/distorm-net/Operand.cs +25 -0
- data/funchook/distorm/examples/cs/distorm-net/Properties/AssemblyInfo.cs +36 -0
- data/funchook/distorm/examples/cs/distorm-net/diStorm3.cs +411 -0
- data/funchook/distorm/examples/cs/distorm-net/distorm-net.csproj +80 -0
- data/funchook/distorm/examples/cs/readme +3 -0
- data/funchook/distorm/examples/ddk/README +48 -0
- data/funchook/distorm/examples/ddk/distorm.ini +11 -0
- data/funchook/distorm/examples/ddk/dummy.c +15 -0
- data/funchook/distorm/examples/ddk/main.c +91 -0
- data/funchook/distorm/examples/ddk/makefile +1 -0
- data/funchook/distorm/examples/ddk/sources +10 -0
- data/funchook/distorm/examples/java/Makefile +23 -0
- data/funchook/distorm/examples/java/distorm/src/Main.java +43 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/CodeInfo.java +27 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/DecodedInst.java +32 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/DecodedResult.java +11 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/DecomposedInst.java +89 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/DecomposedResult.java +11 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/OpcodeEnum.java +131 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/Opcodes.java +1123 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/Operand.java +24 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/distorm3.java +41 -0
- data/funchook/distorm/examples/java/jdistorm.c +405 -0
- data/funchook/distorm/examples/java/jdistorm.h +40 -0
- data/funchook/distorm/examples/java/jdistorm.sln +20 -0
- data/funchook/distorm/examples/java/jdistorm.vcproj +208 -0
- data/funchook/distorm/examples/linux/Makefile +15 -0
- data/funchook/distorm/examples/linux/main.c +181 -0
- data/funchook/distorm/examples/tests/Makefile +15 -0
- data/funchook/distorm/examples/tests/main.cpp +42 -0
- data/funchook/distorm/examples/tests/main.py +66 -0
- data/funchook/distorm/examples/tests/test_distorm3.py +1672 -0
- data/funchook/distorm/examples/tests/tests.sln +20 -0
- data/funchook/distorm/examples/tests/tests.vcxproj +82 -0
- data/funchook/distorm/examples/tests/tests.vcxproj.filters +22 -0
- data/funchook/distorm/examples/win32/disasm.sln +25 -0
- data/funchook/distorm/examples/win32/disasm.vcxproj +201 -0
- data/funchook/distorm/examples/win32/disasm.vcxproj.filters +14 -0
- data/funchook/distorm/examples/win32/main.cpp +163 -0
- data/funchook/distorm/include/distorm.h +482 -0
- data/funchook/distorm/include/mnemonics.h +301 -0
- data/funchook/distorm/make/linux/Makefile +28 -0
- data/funchook/distorm/make/mac/Makefile +24 -0
- data/funchook/distorm/make/win32/cdistorm.vcxproj +239 -0
- data/funchook/distorm/make/win32/cdistorm.vcxproj.filters +80 -0
- data/funchook/distorm/make/win32/distorm.sln +25 -0
- data/funchook/distorm/make/win32/resource.h +14 -0
- data/funchook/distorm/make/win32/resource.rc +99 -0
- data/funchook/distorm/python/distorm3/__init__.py +957 -0
- data/funchook/distorm/python/distorm3/sample.py +51 -0
- data/funchook/distorm/setup.cfg +10 -0
- data/funchook/distorm/setup.py +266 -0
- data/funchook/distorm/src/config.h +169 -0
- data/funchook/distorm/src/decoder.c +641 -0
- data/funchook/distorm/src/decoder.h +33 -0
- data/funchook/distorm/src/distorm.c +413 -0
- data/funchook/distorm/src/instructions.c +597 -0
- data/funchook/distorm/src/instructions.h +463 -0
- data/funchook/distorm/src/insts.c +7939 -0
- data/funchook/distorm/src/insts.h +64 -0
- data/funchook/distorm/src/mnemonics.c +284 -0
- data/funchook/distorm/src/operands.c +1290 -0
- data/funchook/distorm/src/operands.h +28 -0
- data/funchook/distorm/src/prefix.c +368 -0
- data/funchook/distorm/src/prefix.h +64 -0
- data/funchook/distorm/src/textdefs.c +172 -0
- data/funchook/distorm/src/textdefs.h +57 -0
- data/funchook/distorm/src/wstring.c +47 -0
- data/funchook/distorm/src/wstring.h +35 -0
- data/funchook/distorm/src/x86defs.h +82 -0
- data/funchook/include/funchook.h +123 -0
- data/funchook/install-sh +527 -0
- data/funchook/src/Makefile +70 -0
- data/funchook/src/Makefile.in +70 -0
- data/funchook/src/__strerror.h +109 -0
- data/funchook/src/config.h +101 -0
- data/funchook/src/config.h.in +100 -0
- data/funchook/src/decoder.o +0 -0
- data/funchook/src/distorm.o +0 -0
- data/funchook/src/funchook.c +440 -0
- data/funchook/src/funchook.o +0 -0
- data/funchook/src/funchook_internal.h +155 -0
- data/funchook/src/funchook_io.c +182 -0
- data/funchook/src/funchook_io.h +64 -0
- data/funchook/src/funchook_io.o +0 -0
- data/funchook/src/funchook_syscall.S +134 -0
- data/funchook/src/funchook_syscall.o +0 -0
- data/funchook/src/funchook_unix.c +480 -0
- data/funchook/src/funchook_unix.o +0 -0
- data/funchook/src/funchook_windows.c +397 -0
- data/funchook/src/funchook_x86.c +622 -0
- data/funchook/src/funchook_x86.o +0 -0
- data/funchook/src/instructions.o +0 -0
- data/funchook/src/insts.o +0 -0
- data/funchook/src/libfunchook.so +0 -0
- data/funchook/src/mnemonics.o +0 -0
- data/funchook/src/operands.o +0 -0
- data/funchook/src/os_func.c +115 -0
- data/funchook/src/os_func.h +75 -0
- data/funchook/src/os_func.o +0 -0
- data/funchook/src/os_func_unix.c +94 -0
- data/funchook/src/os_func_unix.o +0 -0
- data/funchook/src/os_func_windows.c +32 -0
- data/funchook/src/prefix.o +0 -0
- data/funchook/src/printf_base.c +1688 -0
- data/funchook/src/printf_base.h +46 -0
- data/funchook/src/printf_base.o +0 -0
- data/funchook/src/textdefs.o +0 -0
- data/funchook/src/wstring.o +0 -0
- data/funchook/test/Makefile +43 -0
- data/funchook/test/Makefile.in +43 -0
- data/funchook/test/funchook_test +0 -0
- data/funchook/test/libfunchook_test.c +25 -0
- data/funchook/test/libfunchook_test.so +0 -0
- data/funchook/test/libfunchook_test2.c +18 -0
- data/funchook/test/suffix.list +600 -0
- data/funchook/test/test_main.c +430 -0
- data/funchook/test/test_main.o +0 -0
- data/funchook/test/x86_64_test.S +10 -0
- data/funchook/test/x86_64_test.o +0 -0
- data/funchook/test/x86_test.S +339 -0
- data/funchook/win32/config.h +1 -0
- data/funchook/win32/funchook.sln +52 -0
- data/funchook/win32/funchook.vcxproj +188 -0
- data/funchook/win32/funchook.vcxproj.filters +84 -0
- data/funchook/win32/funchook_test.vcxproj +170 -0
- data/funchook/win32/funchook_test.vcxproj.filters +22 -0
- data/funchook/win32/funchook_test_dll.vcxproj +184 -0
- data/funchook/win32/funchook_test_dll.vcxproj.filters +30 -0
- data/funchook/win32/funchook_test_exe.def +3 -0
- data/lib/contrast-agent.rb +8 -0
- data/lib/contrast.rb +57 -0
- data/lib/contrast/agent.rb +80 -0
- data/lib/contrast/agent/assess.rb +45 -0
- data/lib/contrast/agent/assess/adjusted_span.rb +25 -0
- data/lib/contrast/agent/assess/class_reverter.rb +82 -0
- data/lib/contrast/agent/assess/contrast_event.rb +398 -0
- data/lib/contrast/agent/assess/frozen_properties.rb +41 -0
- data/lib/contrast/agent/assess/insulator.rb +53 -0
- data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +78 -0
- data/lib/contrast/agent/assess/policy/patcher.rb +85 -0
- data/lib/contrast/agent/assess/policy/policy.rb +116 -0
- data/lib/contrast/agent/assess/policy/policy_node.rb +289 -0
- data/lib/contrast/agent/assess/policy/policy_scanner.rb +44 -0
- data/lib/contrast/agent/assess/policy/preshift.rb +94 -0
- data/lib/contrast/agent/assess/policy/propagation_method.rb +260 -0
- data/lib/contrast/agent/assess/policy/propagation_node.rb +127 -0
- data/lib/contrast/agent/assess/policy/propagator.rb +35 -0
- data/lib/contrast/agent/assess/policy/propagator/append.rb +54 -0
- data/lib/contrast/agent/assess/policy/propagator/base.rb +37 -0
- data/lib/contrast/agent/assess/policy/propagator/center.rb +73 -0
- data/lib/contrast/agent/assess/policy/propagator/custom.rb +36 -0
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +62 -0
- data/lib/contrast/agent/assess/policy/propagator/insert.rb +55 -0
- data/lib/contrast/agent/assess/policy/propagator/keep.rb +26 -0
- data/lib/contrast/agent/assess/policy/propagator/next.rb +42 -0
- data/lib/contrast/agent/assess/policy/propagator/prepend.rb +50 -0
- data/lib/contrast/agent/assess/policy/propagator/remove.rb +76 -0
- data/lib/contrast/agent/assess/policy/propagator/replace.rb +27 -0
- data/lib/contrast/agent/assess/policy/propagator/reverse.rb +38 -0
- data/lib/contrast/agent/assess/policy/propagator/select.rb +86 -0
- data/lib/contrast/agent/assess/policy/propagator/splat.rb +60 -0
- data/lib/contrast/agent/assess/policy/propagator/split.rb +49 -0
- data/lib/contrast/agent/assess/policy/propagator/substitution.rb +169 -0
- data/lib/contrast/agent/assess/policy/propagator/trim.rb +81 -0
- data/lib/contrast/agent/assess/policy/rewriter_patch.rb +79 -0
- data/lib/contrast/agent/assess/policy/source_method.rb +209 -0
- data/lib/contrast/agent/assess/policy/source_node.rb +62 -0
- data/lib/contrast/agent/assess/policy/trigger_method.rb +209 -0
- data/lib/contrast/agent/assess/policy/trigger_node.rb +198 -0
- data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +77 -0
- data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +31 -0
- data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +40 -0
- data/lib/contrast/agent/assess/properties.rb +392 -0
- data/lib/contrast/agent/assess/rule.rb +18 -0
- data/lib/contrast/agent/assess/rule/base.rb +72 -0
- data/lib/contrast/agent/assess/rule/csrf.rb +66 -0
- data/lib/contrast/agent/assess/rule/csrf/csrf_action.rb +28 -0
- data/lib/contrast/agent/assess/rule/csrf/csrf_applicator.rb +69 -0
- data/lib/contrast/agent/assess/rule/csrf/csrf_watcher.rb +132 -0
- data/lib/contrast/agent/assess/rule/provider.rb +21 -0
- data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +62 -0
- data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +73 -0
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +121 -0
- data/lib/contrast/agent/assess/rule/redos.rb +68 -0
- data/lib/contrast/agent/assess/rule/response_scanning_rule.rb +47 -0
- data/lib/contrast/agent/assess/rule/response_watcher.rb +36 -0
- data/lib/contrast/agent/assess/rule/watcher.rb +36 -0
- data/lib/contrast/agent/assess/tag.rb +151 -0
- data/lib/contrast/agent/at_exit_hook.rb +33 -0
- data/lib/contrast/agent/class_reopener.rb +195 -0
- data/lib/contrast/agent/deadzone/policy/deadzone_node.rb +26 -0
- data/lib/contrast/agent/deadzone/policy/policy.rb +57 -0
- data/lib/contrast/agent/disable_reaction.rb +24 -0
- data/lib/contrast/agent/exclusion_matcher.rb +190 -0
- data/lib/contrast/agent/feature_state.rb +379 -0
- data/lib/contrast/agent/inventory/policy/policy.rb +32 -0
- data/lib/contrast/agent/inventory/policy/trigger_node.rb +22 -0
- data/lib/contrast/agent/logger_manager.rb +116 -0
- data/lib/contrast/agent/middleware.rb +352 -0
- data/lib/contrast/agent/module_data.rb +16 -0
- data/lib/contrast/agent/patching/policy/after_load_patch.rb +37 -0
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +58 -0
- data/lib/contrast/agent/patching/policy/method_policy.rb +94 -0
- data/lib/contrast/agent/patching/policy/module_policy.rb +116 -0
- data/lib/contrast/agent/patching/policy/patch.rb +312 -0
- data/lib/contrast/agent/patching/policy/patch_status.rb +192 -0
- data/lib/contrast/agent/patching/policy/patcher.rb +310 -0
- data/lib/contrast/agent/patching/policy/policy.rb +138 -0
- data/lib/contrast/agent/patching/policy/policy_node.rb +80 -0
- data/lib/contrast/agent/patching/policy/policy_unpatcher.rb +28 -0
- data/lib/contrast/agent/patching/policy/trigger_node.rb +81 -0
- data/lib/contrast/agent/protect/policy/policy.rb +37 -0
- data/lib/contrast/agent/protect/policy/trigger_node.rb +23 -0
- data/lib/contrast/agent/protect/rule.rb +58 -0
- data/lib/contrast/agent/protect/rule/base.rb +300 -0
- data/lib/contrast/agent/protect/rule/base_service.rb +88 -0
- data/lib/contrast/agent/protect/rule/cmd_injection.rb +156 -0
- data/lib/contrast/agent/protect/rule/csrf.rb +118 -0
- data/lib/contrast/agent/protect/rule/csrf/csrf_evaluator.rb +103 -0
- data/lib/contrast/agent/protect/rule/csrf/csrf_token_injector.rb +85 -0
- data/lib/contrast/agent/protect/rule/default_scanner.rb +300 -0
- data/lib/contrast/agent/protect/rule/deserialization.rb +193 -0
- data/lib/contrast/agent/protect/rule/http_method_tampering.rb +80 -0
- data/lib/contrast/agent/protect/rule/no_sqli.rb +101 -0
- data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +40 -0
- data/lib/contrast/agent/protect/rule/path_traversal.rb +143 -0
- data/lib/contrast/agent/protect/rule/sqli.rb +101 -0
- data/lib/contrast/agent/protect/rule/sqli/default_sql_scanner.rb +16 -0
- data/lib/contrast/agent/protect/rule/sqli/mysql_sql_scanner.rb +38 -0
- data/lib/contrast/agent/protect/rule/sqli/postgres_sql_scanner.rb +22 -0
- data/lib/contrast/agent/protect/rule/sqli/sqlite_sql_scanner.rb +19 -0
- data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +20 -0
- data/lib/contrast/agent/protect/rule/xss.rb +24 -0
- data/lib/contrast/agent/protect/rule/xxe.rb +120 -0
- data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +82 -0
- data/lib/contrast/agent/railtie.rb +30 -0
- data/lib/contrast/agent/reaction_processor.rb +47 -0
- data/lib/contrast/agent/request.rb +493 -0
- data/lib/contrast/agent/request_context.rb +225 -0
- data/lib/contrast/agent/require_state.rb +61 -0
- data/lib/contrast/agent/response.rb +215 -0
- data/lib/contrast/agent/rewriter.rb +244 -0
- data/lib/contrast/agent/scope.rb +28 -0
- data/lib/contrast/agent/service_heartbeat.rb +37 -0
- data/lib/contrast/agent/settings_state.rb +148 -0
- data/lib/contrast/agent/socket_client.rb +125 -0
- data/lib/contrast/agent/thread.rb +26 -0
- data/lib/contrast/agent/tracepoint_hook.rb +51 -0
- data/lib/contrast/agent/version.rb +8 -0
- data/lib/contrast/api.rb +17 -0
- data/lib/contrast/api/.gitkeep +0 -0
- data/lib/contrast/api/connection_status.rb +49 -0
- data/lib/contrast/api/socket.rb +43 -0
- data/lib/contrast/api/speedracer.rb +206 -0
- data/lib/contrast/api/tcp_socket.rb +31 -0
- data/lib/contrast/api/unix_socket.rb +25 -0
- data/lib/contrast/common_agent_configuration.rb +86 -0
- data/lib/contrast/components/agent.rb +85 -0
- data/lib/contrast/components/app_context.rb +188 -0
- data/lib/contrast/components/assess.rb +67 -0
- data/lib/contrast/components/config.rb +135 -0
- data/lib/contrast/components/contrast_service.rb +113 -0
- data/lib/contrast/components/heap_dump.rb +34 -0
- data/lib/contrast/components/interface.rb +178 -0
- data/lib/contrast/components/inventory.rb +23 -0
- data/lib/contrast/components/logger.rb +92 -0
- data/lib/contrast/components/protect.rb +38 -0
- data/lib/contrast/components/sampling.rb +41 -0
- data/lib/contrast/components/scope.rb +106 -0
- data/lib/contrast/components/settings.rb +140 -0
- data/lib/contrast/config.rb +33 -0
- data/lib/contrast/config/agent_configuration.rb +24 -0
- data/lib/contrast/config/application_configuration.rb +27 -0
- data/lib/contrast/config/assess_configuration.rb +22 -0
- data/lib/contrast/config/assess_rules_configuration.rb +18 -0
- data/lib/contrast/config/base_configuration.rb +105 -0
- data/lib/contrast/config/default_value.rb +16 -0
- data/lib/contrast/config/exception_configuration.rb +21 -0
- data/lib/contrast/config/heap_dump_configuration.rb +23 -0
- data/lib/contrast/config/inventory_configuration.rb +20 -0
- data/lib/contrast/config/logger_configuration.rb +20 -0
- data/lib/contrast/config/protect_configuration.rb +20 -0
- data/lib/contrast/config/protect_rule_configuration.rb +37 -0
- data/lib/contrast/config/protect_rules_configuration.rb +30 -0
- data/lib/contrast/config/root_configuration.rb +26 -0
- data/lib/contrast/config/ruby_configuration.rb +39 -0
- data/lib/contrast/config/sampling_configuration.rb +22 -0
- data/lib/contrast/config/server_configuration.rb +23 -0
- data/lib/contrast/config/service_configuration.rb +22 -0
- data/lib/contrast/configuration.rb +214 -0
- data/lib/contrast/core_extensions/assess.rb +51 -0
- data/lib/contrast/core_extensions/assess/array.rb +58 -0
- data/lib/contrast/core_extensions/assess/assess_extension.rb +145 -0
- data/lib/contrast/core_extensions/assess/basic_object.rb +15 -0
- data/lib/contrast/core_extensions/assess/erb.rb +42 -0
- data/lib/contrast/core_extensions/assess/exec_trigger.rb +48 -0
- data/lib/contrast/core_extensions/assess/fiber.rb +125 -0
- data/lib/contrast/core_extensions/assess/hash.rb +22 -0
- data/lib/contrast/core_extensions/assess/kernel.rb +95 -0
- data/lib/contrast/core_extensions/assess/module.rb +14 -0
- data/lib/contrast/core_extensions/assess/regexp.rb +206 -0
- data/lib/contrast/core_extensions/assess/string.rb +75 -0
- data/lib/contrast/core_extensions/assess/tilt_template_trigger.rb +73 -0
- data/lib/contrast/core_extensions/delegator.rb +14 -0
- data/lib/contrast/core_extensions/eval_trigger.rb +52 -0
- data/lib/contrast/core_extensions/inventory.rb +22 -0
- data/lib/contrast/core_extensions/inventory/datastores.rb +37 -0
- data/lib/contrast/core_extensions/module.rb +42 -0
- data/lib/contrast/core_extensions/object.rb +27 -0
- data/lib/contrast/core_extensions/protect.rb +20 -0
- data/lib/contrast/core_extensions/protect/applies_command_injection_rule.rb +70 -0
- data/lib/contrast/core_extensions/protect/applies_deserialization_rule.rb +58 -0
- data/lib/contrast/core_extensions/protect/applies_no_sqli_rule.rb +81 -0
- data/lib/contrast/core_extensions/protect/applies_path_traversal_rule.rb +119 -0
- data/lib/contrast/core_extensions/protect/applies_sqli_rule.rb +63 -0
- data/lib/contrast/core_extensions/protect/applies_xxe_rule.rb +141 -0
- data/lib/contrast/core_extensions/protect/kernel.rb +30 -0
- data/lib/contrast/core_extensions/protect/psych.rb +7 -0
- data/lib/contrast/core_extensions/thread.rb +31 -0
- data/lib/contrast/internal_exception.rb +8 -0
- data/lib/contrast/rails_extensions/assess/action_controller_inheritance.rb +48 -0
- data/lib/contrast/rails_extensions/assess/active_record.rb +32 -0
- data/lib/contrast/rails_extensions/assess/active_record_named.rb +61 -0
- data/lib/contrast/rails_extensions/assess/configuration.rb +26 -0
- data/lib/contrast/rails_extensions/buffer.rb +30 -0
- data/lib/contrast/rails_extensions/rack.rb +45 -0
- data/lib/contrast/security_exception.rb +14 -0
- data/lib/contrast/sinatra_extensions/assess/cookie.rb +26 -0
- data/lib/contrast/sinatra_extensions/inventory/sinatra_base.rb +59 -0
- data/lib/contrast/tasks/service.rb +95 -0
- data/lib/contrast/utils/assess/sampling_util.rb +96 -0
- data/lib/contrast/utils/assess/tracking_util.rb +39 -0
- data/lib/contrast/utils/boolean_util.rb +33 -0
- data/lib/contrast/utils/cache.rb +69 -0
- data/lib/contrast/utils/class_util.rb +58 -0
- data/lib/contrast/utils/comment_range.rb +19 -0
- data/lib/contrast/utils/data_store_util.rb +23 -0
- data/lib/contrast/utils/duck_utils.rb +58 -0
- data/lib/contrast/utils/env_configuration_item.rb +52 -0
- data/lib/contrast/utils/environment_util.rb +152 -0
- data/lib/contrast/utils/freeze_util.rb +36 -0
- data/lib/contrast/utils/gemfile_reader.rb +191 -0
- data/lib/contrast/utils/hash_digest.rb +148 -0
- data/lib/contrast/utils/heap_dump_util.rb +113 -0
- data/lib/contrast/utils/invalid_configuration_util.rb +88 -0
- data/lib/contrast/utils/inventory_util.rb +126 -0
- data/lib/contrast/utils/io_util.rb +61 -0
- data/lib/contrast/utils/object_share.rb +117 -0
- data/lib/contrast/utils/operating_environment.rb +38 -0
- data/lib/contrast/utils/os.rb +49 -0
- data/lib/contrast/utils/path_util.rb +151 -0
- data/lib/contrast/utils/performs_logging.rb +152 -0
- data/lib/contrast/utils/preflight_util.rb +13 -0
- data/lib/contrast/utils/prevent_serialization.rb +52 -0
- data/lib/contrast/utils/rack_assess_session_cookie.rb +104 -0
- data/lib/contrast/utils/rails_assess_configuration.rb +95 -0
- data/lib/contrast/utils/random_util.rb +22 -0
- data/lib/contrast/utils/resource_loader.rb +23 -0
- data/lib/contrast/utils/ruby_ast_rewriter.rb +74 -0
- data/lib/contrast/utils/scope_util.rb +99 -0
- data/lib/contrast/utils/service_response_util.rb +116 -0
- data/lib/contrast/utils/service_sender_util.rb +98 -0
- data/lib/contrast/utils/sha256_builder.rb +69 -0
- data/lib/contrast/utils/sinatra_helper.rb +49 -0
- data/lib/contrast/utils/stack_trace_utils.rb +209 -0
- data/lib/contrast/utils/string_utils.rb +72 -0
- data/lib/contrast/utils/tag_util.rb +139 -0
- data/lib/contrast/utils/thread_tracker.rb +54 -0
- data/lib/contrast/utils/timer.rb +78 -0
- data/resources/assess/policy.json +1673 -0
- data/resources/csrf/inject.js +44 -0
- data/resources/deadzone/policy.json +55 -0
- data/resources/factory-bot-spec/spec_helper.rb +30 -0
- data/resources/inventory/policy.json +110 -0
- data/resources/protect/policy.json +417 -0
- data/resources/rubocops/kernel/catch_cop.rb +37 -0
- data/resources/rubocops/kernel/require_cop.rb +37 -0
- data/resources/rubocops/kernel/require_relative_cop.rb +33 -0
- data/resources/rubocops/module/autoload_cop.rb +37 -0
- data/resources/rubocops/module/const_defined_cop.rb +37 -0
- data/resources/rubocops/module/const_get_cop.rb +37 -0
- data/resources/rubocops/module/const_set_cop.rb +37 -0
- data/resources/rubocops/module/constants_cop.rb +37 -0
- data/resources/rubocops/module/name_cop.rb +37 -0
- data/resources/rubocops/object/class_cop.rb +37 -0
- data/resources/rubocops/object/freeze_cop.rb +37 -0
- data/resources/rubocops/object/frozen_cop.rb +37 -0
- data/resources/rubocops/object/is_a_cop.rb +37 -0
- data/resources/rubocops/object/method_cop.rb +37 -0
- data/resources/rubocops/object/respond_to_cop.rb +37 -0
- data/resources/rubocops/object/singleton_class_cop.rb +37 -0
- data/resources/rubocops/regexp/spelling_cop.rb +44 -0
- data/resources/rubocops/thread/new_cop.rb +39 -0
- data/resources/ruby-spec/ancestors_spec.rb +70 -0
- data/resources/ruby-spec/modulo_spec.rb +831 -0
- data/resources/ruby-spec/parameters_spec.rb +261 -0
- data/resources/ruby-spec/ruby_spec_spec_helper.rb +35 -0
- data/resources/test_marker.txt +1 -0
- data/ruby-agent.gemspec +129 -0
- data/service_executables/.gitkeep +0 -0
- data/service_executables/VERSION +1 -0
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- metadata +945 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Contrast
|
|
5
|
+
module Agent
|
|
6
|
+
module Assess
|
|
7
|
+
# This is the base module for our assess rule classes. It is intended to
|
|
8
|
+
# facilitate the patching of the application for Assess functionality. Any
|
|
9
|
+
# class under this namespace should be required here, providing a single
|
|
10
|
+
# point of require for this functionality.
|
|
11
|
+
module Rule
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
cs__scoped_require 'contrast/agent/assess/rule/base'
|
|
18
|
+
cs__scoped_require 'contrast/agent/assess/rule/provider'
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
cs__scoped_require 'contrast/components/interface'
|
|
5
|
+
|
|
6
|
+
cs__scoped_require 'zlib'
|
|
7
|
+
cs__scoped_require 'digest'
|
|
8
|
+
|
|
9
|
+
module Contrast
|
|
10
|
+
module Agent
|
|
11
|
+
module Assess
|
|
12
|
+
module Rule
|
|
13
|
+
# The base class for each of our Assess Rules
|
|
14
|
+
class Base
|
|
15
|
+
include Contrast::Components::Interface
|
|
16
|
+
access_component :logging, :analysis, :agent, :settings
|
|
17
|
+
|
|
18
|
+
def initialize
|
|
19
|
+
SETTINGS.assess_rules[name] = self
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Should return the name as it is known to Teamserver; defaults to
|
|
23
|
+
# class
|
|
24
|
+
def name
|
|
25
|
+
cs__class.name
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def enabled?
|
|
29
|
+
ASSESS.enabled? && !ASSESS.rule_disabled?(name)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def prefilter _context; end
|
|
33
|
+
|
|
34
|
+
# If a rule needs to inspect the response body it is not stream safe
|
|
35
|
+
# The rule should override this and return false
|
|
36
|
+
def stream_safe?
|
|
37
|
+
true
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def postfilter _context; end
|
|
41
|
+
|
|
42
|
+
# this rule is excluded if any of the given exclusions have a
|
|
43
|
+
# protection rule that matches this rule name
|
|
44
|
+
def excluded? exclusions
|
|
45
|
+
Array(exclusions).any? do |ex|
|
|
46
|
+
ex.assess_rule?(name)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def send_report finding
|
|
51
|
+
finding.rule_id = name
|
|
52
|
+
finding.hash_code = generate_hash(finding)
|
|
53
|
+
finding.preflight = Contrast::Utils::PreflightUtil.create_preflight(finding)
|
|
54
|
+
finding.version = Contrast::Agent::Assess::Policy::TriggerMethod::CURRENT_FINDING_VERSION
|
|
55
|
+
finding.tags = ASSESS.tags.to_s
|
|
56
|
+
|
|
57
|
+
current_context = Contrast::Agent::REQUEST_TRACKER.current
|
|
58
|
+
current_context.activity.findings << finding
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def generate_hash finding
|
|
62
|
+
Contrast::Utils::HashDigest.generate_trigger_hash(finding)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def trace_tags
|
|
66
|
+
@_trace_tags ||= ASSESS.tags.to_s
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Contrast
|
|
5
|
+
module Agent
|
|
6
|
+
module Assess
|
|
7
|
+
module Rule
|
|
8
|
+
# The Ruby implementation of the CSRF Assess Rule.
|
|
9
|
+
class Csrf < Contrast::Agent::Assess::Rule::ResponseScanningRule
|
|
10
|
+
NAME = 'csrf'
|
|
11
|
+
def name
|
|
12
|
+
NAME
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
DB_STATE_CHANGE = 'db'
|
|
16
|
+
ACTION_LIMIT = 3
|
|
17
|
+
QUERY_SIZE_LIMIT = 50
|
|
18
|
+
STATE_CHANGING_ACTIONS_KEY = 'csrf.statechange.actions'
|
|
19
|
+
def record_db_state_change context, query
|
|
20
|
+
return unless context
|
|
21
|
+
|
|
22
|
+
changes = context.get_property(STATE_CHANGING_ACTIONS_KEY)
|
|
23
|
+
changes ||= []
|
|
24
|
+
return unless changes.length < ACTION_LIMIT
|
|
25
|
+
|
|
26
|
+
return unless state_change?(query)
|
|
27
|
+
|
|
28
|
+
action = Contrast::Agent::Assess::Rule::Csrf::CsrfAction.new
|
|
29
|
+
action.type = DB_STATE_CHANGE
|
|
30
|
+
action.evidence = query[0..QUERY_SIZE_LIMIT]
|
|
31
|
+
|
|
32
|
+
changes << action
|
|
33
|
+
|
|
34
|
+
context.add_property(STATE_CHANGING_ACTIONS_KEY, changes)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
STATE_CHANGE_QUERY_ACTIONS = %w[
|
|
38
|
+
insert
|
|
39
|
+
update
|
|
40
|
+
delete
|
|
41
|
+
drop
|
|
42
|
+
create
|
|
43
|
+
alter
|
|
44
|
+
upsert
|
|
45
|
+
].cs__freeze
|
|
46
|
+
# Returns true if the given query starts with any
|
|
47
|
+
# of the STATE_CHANGE_QUERY_ACTIONS listed above
|
|
48
|
+
def state_change? query
|
|
49
|
+
return false unless query.is_a?(String) && !query.empty?
|
|
50
|
+
|
|
51
|
+
query.downcase.start_with?(*STATE_CHANGE_QUERY_ACTIONS)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# some watchers keep state and need to be reset in each request.
|
|
55
|
+
# this one is not one of those.
|
|
56
|
+
def watcher
|
|
57
|
+
@_watcher ||= Contrast::Agent::Assess::Rule::Csrf::Watcher.new
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Indicates if this request has been checked for a CSRF token
|
|
61
|
+
CHECKED = 'csrf.token.checked'
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Contrast
|
|
5
|
+
module Agent
|
|
6
|
+
module Assess
|
|
7
|
+
module Rule
|
|
8
|
+
class Csrf
|
|
9
|
+
# CSRF is only reported on those Requests which also result in a
|
|
10
|
+
# state changing action (database call). This class servers as a
|
|
11
|
+
# record of that action.
|
|
12
|
+
class CsrfAction
|
|
13
|
+
attr_accessor :type, :evidence
|
|
14
|
+
|
|
15
|
+
TYPE = 'type'
|
|
16
|
+
EVIDENCE = 'evidence'
|
|
17
|
+
def to_h
|
|
18
|
+
{
|
|
19
|
+
TYPE => type,
|
|
20
|
+
EVIDENCE => evidence
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
cs__scoped_require 'contrast/utils/object_share'
|
|
5
|
+
cs__scoped_require 'contrast/components/interface'
|
|
6
|
+
|
|
7
|
+
module Contrast
|
|
8
|
+
module Agent
|
|
9
|
+
module Assess
|
|
10
|
+
module Rule
|
|
11
|
+
class Csrf
|
|
12
|
+
# This class is called by our patches to determine if a CSRF
|
|
13
|
+
# vulnerability exists within an application. It is used through a
|
|
14
|
+
# CUSTOM propagation in order to capture that a Database call was
|
|
15
|
+
# made in response to a request that did not have the Contrast CSRF
|
|
16
|
+
# token.
|
|
17
|
+
class CsrfApplicator
|
|
18
|
+
include Contrast::Components::Interface
|
|
19
|
+
access_component :logging, :analysis, :scope
|
|
20
|
+
|
|
21
|
+
CS__CSRF_LOG_MSG = 'applying CSRF assess rule'
|
|
22
|
+
|
|
23
|
+
def self.rule
|
|
24
|
+
@_rule ||= Contrast::Agent::FeatureState.instance.assess_rule(
|
|
25
|
+
Contrast::Agent::Assess::Rule::Csrf::NAME)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.csrf_tagger patcher, preshift, _ret, _block
|
|
29
|
+
return unless rule&.enabled?
|
|
30
|
+
|
|
31
|
+
idx = patcher.sources[0].to_i
|
|
32
|
+
args = preshift.args
|
|
33
|
+
return unless args&.length.to_i > idx
|
|
34
|
+
|
|
35
|
+
sql = args[idx]
|
|
36
|
+
return unless sql
|
|
37
|
+
|
|
38
|
+
with_contrast_scope do
|
|
39
|
+
logger.debug(nil, CS__CSRF_LOG_MSG)
|
|
40
|
+
rule.record_db_state_change(
|
|
41
|
+
Contrast::Agent::REQUEST_TRACKER.current,
|
|
42
|
+
sql)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.cs__assess_apply_csrf_rule sql
|
|
47
|
+
context = Contrast::Agent::REQUEST_TRACKER.current
|
|
48
|
+
|
|
49
|
+
return unless context&.app_loaded?
|
|
50
|
+
return unless ASSESS.enabled?
|
|
51
|
+
return unless sql
|
|
52
|
+
|
|
53
|
+
rule = Contrast::Agent::FeatureState.instance.assess_rule(
|
|
54
|
+
Contrast::Agent::Assess::Rule::Csrf::NAME)
|
|
55
|
+
return unless rule&.enabled?
|
|
56
|
+
|
|
57
|
+
with_contrast_scope do
|
|
58
|
+
logger.debug(CS__CSRF_LOG_MSG)
|
|
59
|
+
rule.record_db_state_change(context, sql)
|
|
60
|
+
end
|
|
61
|
+
rescue StandardError => e
|
|
62
|
+
logger.warn(e, 'Error running CSRF assess rule')
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
cs__scoped_require 'contrast/agent/assess/rule/response_watcher'
|
|
5
|
+
|
|
6
|
+
module Contrast
|
|
7
|
+
module Agent
|
|
8
|
+
module Assess
|
|
9
|
+
module Rule
|
|
10
|
+
class Csrf
|
|
11
|
+
# Watchers are how those Rules which do not act on dataflow function.
|
|
12
|
+
# This one is used by the CSRF rule to determine if a request was
|
|
13
|
+
# made in a way that is susceptible to a CSRF attack.
|
|
14
|
+
class Watcher < Contrast::Agent::Assess::Rule::ResponseWatcher
|
|
15
|
+
def supports? context
|
|
16
|
+
return false unless super(context)
|
|
17
|
+
return false unless user_agent?(context)
|
|
18
|
+
return false unless form_content_type?(context)
|
|
19
|
+
return false unless form_method?(context)
|
|
20
|
+
return false if empty_get?(context)
|
|
21
|
+
|
|
22
|
+
true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
X_REQUESTED_WITH = 'X-REQUESTED-WITH'
|
|
26
|
+
# ignore this request if X-Requested-With is set
|
|
27
|
+
def x_requested_with? context
|
|
28
|
+
!context.request.normalized_request_headers[X_REQUESTED_WITH].nil?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
USER_AGENT = 'USER-AGENT'
|
|
32
|
+
# ignore this request if User-Agent is NOT set
|
|
33
|
+
# since that indicates this isn't a browser interaction
|
|
34
|
+
def user_agent? context
|
|
35
|
+
!context.request.normalized_request_headers[USER_AGENT].nil?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
CONTENT_TYPE = 'CONTENT-TYPE'
|
|
39
|
+
FORM_TYPES = %w[
|
|
40
|
+
text/plain
|
|
41
|
+
multipart/form-data
|
|
42
|
+
application/x-www-form-urlencoded
|
|
43
|
+
].cs__freeze
|
|
44
|
+
# ignore this request if the Content-Type is NOT set
|
|
45
|
+
# to a form content type
|
|
46
|
+
def form_content_type? context
|
|
47
|
+
type = context.request.content_type
|
|
48
|
+
# We need to account for the charset being part of the header. It doesn't
|
|
49
|
+
# affect how we determine CSRF-ability or not
|
|
50
|
+
type = type.split(Contrast::Utils::ObjectShare::SEMICOLON)[0] if type
|
|
51
|
+
FORM_TYPES.include?(type)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
FORM_METHODS = %w[GET POST].cs__freeze
|
|
55
|
+
# ignore this request if the request method
|
|
56
|
+
# is not one that can be set with forms
|
|
57
|
+
def form_method? context
|
|
58
|
+
FORM_METHODS.include?(context.request.request_method)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
GET = 'GET'
|
|
62
|
+
# ignore this request if the method is get
|
|
63
|
+
# and the query string is empty
|
|
64
|
+
def empty_get? context
|
|
65
|
+
request = context.request
|
|
66
|
+
request.request_method ==
|
|
67
|
+
GET &&
|
|
68
|
+
(request.query_string.nil? || request.query_string.empty?)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# If a parameter contains 'csrf' or 'token', we consider
|
|
72
|
+
# it to be a guard against CSRF and therefore determine
|
|
73
|
+
# that this request is not vulnerable.
|
|
74
|
+
CSRF_PATTERN = /csrf/i.cs__freeze
|
|
75
|
+
TOKEN_PATTERN = /token/i.cs__freeze
|
|
76
|
+
def vulnerable? context
|
|
77
|
+
# having the property 'csrf.token.checked' indicates
|
|
78
|
+
# that a CSRF check was preformed at some point during
|
|
79
|
+
# this request, so we consider it to not be vulnerable
|
|
80
|
+
return false if context.get_property(CHECKED)
|
|
81
|
+
|
|
82
|
+
params = context.request.parameters
|
|
83
|
+
params.each_key do |key|
|
|
84
|
+
return false if key.match?(CSRF_PATTERN)
|
|
85
|
+
return false if key.match?(TOKEN_PATTERN) && looks_like_token?(params[key])
|
|
86
|
+
end
|
|
87
|
+
# having no actions means there's no vulnerability
|
|
88
|
+
return false unless context.get_property(STATE_CHANGING_ACTIONS_KEY)&.any?
|
|
89
|
+
|
|
90
|
+
true
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
MINIMUM_CSRF_TOKEN_SIZE = 8
|
|
94
|
+
MAXIMUM_CSRF_TOKEN_SIZE = 24
|
|
95
|
+
TOKEN_REGEXP = /^[A-Za-z0-9]*$/.cs__freeze
|
|
96
|
+
def looks_like_token? value
|
|
97
|
+
return false unless value
|
|
98
|
+
|
|
99
|
+
values = [value]
|
|
100
|
+
values.each do |parameter|
|
|
101
|
+
next unless parameter
|
|
102
|
+
|
|
103
|
+
length = parameter.length
|
|
104
|
+
next if length < MINIMUM_CSRF_TOKEN_SIZE
|
|
105
|
+
next if length > MAXIMUM_CSRF_TOKEN_SIZE
|
|
106
|
+
return true if parameter.match?(TOKEN_REGEXP)
|
|
107
|
+
end
|
|
108
|
+
false
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
DATA_KEY = 'actions'
|
|
112
|
+
def build_finding context
|
|
113
|
+
actions = context.get_property(STATE_CHANGING_ACTIONS_KEY)
|
|
114
|
+
return if actions.nil? || actions.empty?
|
|
115
|
+
|
|
116
|
+
string = actions.map(&:to_h).to_json
|
|
117
|
+
finding = Contrast::Api::Dtm::Finding.new
|
|
118
|
+
finding.rule_id = Contrast::Agent::Assess::Rule::Csrf::NAME
|
|
119
|
+
finding.session_id = Contrast::Agent::FeatureState.instance.current_session_id
|
|
120
|
+
hash_code = Contrast::Utils::HashDigest.generate_response_hash(finding)
|
|
121
|
+
finding.hash_code = Contrast::Utils::StringUtils.force_utf8(hash_code)
|
|
122
|
+
finding.properties[DATA_KEY] = Contrast::Utils::StringUtils.force_utf8(string)
|
|
123
|
+
finding
|
|
124
|
+
rescue StandardError => e
|
|
125
|
+
logger.error(e, 'Unable to build a finding for CSRF')
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Contrast
|
|
5
|
+
module Agent
|
|
6
|
+
module Assess
|
|
7
|
+
module Rule
|
|
8
|
+
# Provider rules are those which do not fit into the standard dataflow
|
|
9
|
+
# paradigm. For our purposes, these rules are currently those which
|
|
10
|
+
# function on class definition to determine if there are dangerous
|
|
11
|
+
# constants defined therein.
|
|
12
|
+
module Provider
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
cs__scoped_require 'contrast/agent/assess/rule/provider/hardcoded_value_rule'
|
|
20
|
+
cs__scoped_require 'contrast/agent/assess/rule/provider/hardcoded_key'
|
|
21
|
+
cs__scoped_require 'contrast/agent/assess/rule/provider/hardcoded_password'
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Contrast
|
|
5
|
+
module Agent
|
|
6
|
+
module Assess
|
|
7
|
+
module Rule
|
|
8
|
+
module Provider
|
|
9
|
+
# Determine if there are any cryptographic keys hardcoded into the sourcecode
|
|
10
|
+
# of the application. A constant is a cryptographic key if:
|
|
11
|
+
# 1) the name contains a KEY_FIELD_NAME value
|
|
12
|
+
# 2) the value is a non-empty array of only Fixnums
|
|
13
|
+
class HardcodedKey
|
|
14
|
+
include Contrast::Agent::Assess::Rule::Provider::HardcodedValueRule
|
|
15
|
+
|
|
16
|
+
NAME = 'hardcoded-key'
|
|
17
|
+
def rule_id
|
|
18
|
+
NAME
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# These are names, determined by the security team (Matt & Ar), that
|
|
22
|
+
# indicate a field is likely to be a password or secret token of some
|
|
23
|
+
# sort.
|
|
24
|
+
KEY_FIELD_NAMES = %w[KEY AES DES IV SECRET].cs__freeze
|
|
25
|
+
|
|
26
|
+
# These are markers whose presence indicates that a field is more
|
|
27
|
+
# likely to be a descriptor or requirement than an actual key.
|
|
28
|
+
# We should ignore fields that contain them.
|
|
29
|
+
NON_KEY_PARTIAL_NAMES = %w[CONTENT_CODES RESPONSE_CODES ERROR_CODES].cs__freeze
|
|
30
|
+
|
|
31
|
+
def name_passes? constant_string
|
|
32
|
+
KEY_FIELD_NAMES.any? { |name| constant_string.index(name) } &&
|
|
33
|
+
NON_KEY_PARTIAL_NAMES.none? { |name| constant_string.index(name) }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# If the value is a byte array, or at least an array of numbers, it
|
|
37
|
+
# passes for this rule
|
|
38
|
+
def value_type_passes? value
|
|
39
|
+
return false unless value.is_a?(Array) && value.any?
|
|
40
|
+
|
|
41
|
+
value.each do |byte|
|
|
42
|
+
return false unless byte.is_a?(Integer)
|
|
43
|
+
end
|
|
44
|
+
true
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# There isn't a filter for the byte value. The check is not evaluated
|
|
48
|
+
# for this rule
|
|
49
|
+
def value_passes? _value
|
|
50
|
+
true
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
REDACTED_MARKER = ' = [**REDACTED**]'
|
|
54
|
+
def redacted_marker
|
|
55
|
+
REDACTED_MARKER
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|