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,352 @@
|
|
|
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 'ipaddr'
|
|
5
|
+
cs__scoped_require 'json'
|
|
6
|
+
cs__scoped_require 'rack'
|
|
7
|
+
cs__scoped_require 'contrast/core_extensions/object'
|
|
8
|
+
cs__scoped_require 'contrast/security_exception'
|
|
9
|
+
cs__scoped_require 'contrast/utils/object_share'
|
|
10
|
+
cs__scoped_require 'contrast/utils/gemfile_reader'
|
|
11
|
+
cs__scoped_require 'contrast/utils/operating_environment'
|
|
12
|
+
cs__scoped_require 'contrast/agent/service_heartbeat'
|
|
13
|
+
cs__scoped_require 'contrast/components/interface'
|
|
14
|
+
cs__scoped_require 'contrast/utils/heap_dump_util'
|
|
15
|
+
|
|
16
|
+
cs__scoped_require 'contrast/utils/path_util'
|
|
17
|
+
cs__scoped_require 'contrast/utils/timer'
|
|
18
|
+
cs__scoped_require 'contrast/utils/freeze_util'
|
|
19
|
+
cs__scoped_require 'contrast/utils/service_sender_util'
|
|
20
|
+
cs__scoped_require 'contrast/utils/service_response_util'
|
|
21
|
+
|
|
22
|
+
module Contrast
|
|
23
|
+
module Agent
|
|
24
|
+
# This class allows the Agent to plug into the Rack middleware stack,
|
|
25
|
+
# providing hooks to relevant application events, such as request start and
|
|
26
|
+
# application code.
|
|
27
|
+
class Middleware
|
|
28
|
+
include Contrast::Components::Interface
|
|
29
|
+
access_component :contrast_service, :logging, :agent, :analysis, :config, :scope
|
|
30
|
+
|
|
31
|
+
attr_reader :app
|
|
32
|
+
|
|
33
|
+
LOG_DEBUG_MIDDLEWARE_ENV = 'middleware: log environment'
|
|
34
|
+
LOG_DEBUG_MIDDLEWARE_LIB = 'middleware: instrument shared libraries'
|
|
35
|
+
LOG_DEBUG_MIDDLEWARE_START = 'middleware: startup agent'
|
|
36
|
+
LOG_DEBUG_MIDDLEWARE_SERVICE = 'middleware: starting service'
|
|
37
|
+
|
|
38
|
+
# allows the Agent to function as a middleware
|
|
39
|
+
#
|
|
40
|
+
# @param app [Rack::Application] the application to be instrumented
|
|
41
|
+
# @param _legacy_param [nil] was a flag we no longer need, but Sinatra may call it
|
|
42
|
+
def initialize app, _legacy_param = nil
|
|
43
|
+
@app = app
|
|
44
|
+
|
|
45
|
+
# TODO: RUBY-545 nomenclature here needs to be updated.
|
|
46
|
+
# enabled/initialized are really only reflective of whether we were
|
|
47
|
+
# able to parse the config, which is the bare minimum for the agent
|
|
48
|
+
# to do anything.
|
|
49
|
+
unless AGENT.enabled?
|
|
50
|
+
logger.error('Contrast middleware initializer detected an early-stage setup failure (likely config parse). Disabling.')
|
|
51
|
+
# ensure the agent is disabled (probably redundant)
|
|
52
|
+
AGENT.disable!
|
|
53
|
+
return
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
logger.debug_with_time(LOG_DEBUG_MIDDLEWARE_ENV) do
|
|
57
|
+
settings.log_environment
|
|
58
|
+
settings.log_configuration
|
|
59
|
+
settings.log_specific_libraries
|
|
60
|
+
settings.log_all_libraries
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Initialization order should be:
|
|
64
|
+
# - start separate service sending threads
|
|
65
|
+
# - start heartbeat thread, which triggers service startup
|
|
66
|
+
# - start patching to achieve instrumentation
|
|
67
|
+
|
|
68
|
+
logger.debug_with_time(LOG_DEBUG_MIDDLEWARE_SERVICE) do
|
|
69
|
+
# get threads ready to poll for messages on the queue
|
|
70
|
+
run_service_sender_thread
|
|
71
|
+
|
|
72
|
+
# sends first message to service, which triggers service startup
|
|
73
|
+
run_service_heartbeat_thread
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Default instrumentation
|
|
77
|
+
logger.debug_with_time(LOG_DEBUG_MIDDLEWARE_LIB) do
|
|
78
|
+
AGENT.run_instrumentation
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
Contrast::Agent::AtExitHook.exit_hook
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def settings
|
|
85
|
+
Contrast::Agent::FeatureState.instance
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
LOG_DEBUG_MIDDLEWARE_START_CALL = 'middleware: startup agent (call)'
|
|
89
|
+
# def _call env
|
|
90
|
+
def call env
|
|
91
|
+
Contrast::Utils::HeapDumpUtil.run
|
|
92
|
+
|
|
93
|
+
if AGENT.enabled?
|
|
94
|
+
response = call_with_agent(env)
|
|
95
|
+
with_contrast_scope { do_static_analysis_catchup }
|
|
96
|
+
response
|
|
97
|
+
else
|
|
98
|
+
call_without_agent(env)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def call_without_agent env
|
|
103
|
+
app.call(env)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
REQUEST_PATH = 'REQUEST_PATH'
|
|
107
|
+
LOG_DEBUG_REQUEST = 'HTTP request cycle'
|
|
108
|
+
def call_with_agent env
|
|
109
|
+
rack_request = generate_request(env)
|
|
110
|
+
|
|
111
|
+
context = Contrast::Agent::RequestContext.new(rack_request, true) # 'true' here is legacy, by the time we're here, we're ready
|
|
112
|
+
|
|
113
|
+
# default response
|
|
114
|
+
streaming = false
|
|
115
|
+
# make the context available for the lifecycle of this request
|
|
116
|
+
Contrast::Agent::REQUEST_TRACKER.lifespan(context) do
|
|
117
|
+
# record entire time
|
|
118
|
+
logger.debug_with_time(LOG_DEBUG_REQUEST) do
|
|
119
|
+
# process filters that can short circuit application processing
|
|
120
|
+
with_contrast_scope do
|
|
121
|
+
context.service_extract_request
|
|
122
|
+
prefilter(context)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# run application by passing request down the Rack chain using
|
|
126
|
+
# the original env
|
|
127
|
+
response = application_code(env)
|
|
128
|
+
|
|
129
|
+
# if streaming, allow for early return with application response
|
|
130
|
+
streaming = possibly_streaming?(env)
|
|
131
|
+
if streaming
|
|
132
|
+
with_contrast_scope { postfilter(context, streaming) }
|
|
133
|
+
return response
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# update context with final response information
|
|
137
|
+
context.extract_after(response)
|
|
138
|
+
|
|
139
|
+
# process filters that look at response headers and body
|
|
140
|
+
with_contrast_scope { postfilter(context) }
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# return the response stored in the context in case any postfilter rules
|
|
145
|
+
# updated the response data
|
|
146
|
+
context&.response&.rack_response || response
|
|
147
|
+
|
|
148
|
+
# handle security exception
|
|
149
|
+
rescue StandardError => e
|
|
150
|
+
handle_exception(e)
|
|
151
|
+
ensure
|
|
152
|
+
begin
|
|
153
|
+
handle_ensure(context, streaming)
|
|
154
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
155
|
+
logger.error(e, 'Exception raised while flushing messages to Contrast service!')
|
|
156
|
+
raise
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
LOG_WARN_FRAMEWORK_PARSE = 'Unable to generate framework specific request - falling back to Rack'
|
|
161
|
+
# Given the rack environment of this call, generate a framework specific
|
|
162
|
+
# request object to bind to this context. In the event that multiple
|
|
163
|
+
# supported frameworks are defined OR we cannot determine the framework
|
|
164
|
+
# currently in use or there is an exception during request generation, we
|
|
165
|
+
# will fall back on Rack::Request object
|
|
166
|
+
def generate_request env
|
|
167
|
+
rails_defined = defined?(Rails)
|
|
168
|
+
sinatra_defined = defined?(Sinatra) && defined?(Sinatra::Request)
|
|
169
|
+
|
|
170
|
+
if rails_defined && !sinatra_defined
|
|
171
|
+
# code from /lib/action_cable/connection/base
|
|
172
|
+
environment = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application
|
|
173
|
+
ActionDispatch::Request.new(environment || env)
|
|
174
|
+
# !defined? currently redundant, won't be if we have more frameworks
|
|
175
|
+
elsif sinatra_defined && !rails_defined
|
|
176
|
+
Sinatra::Request.new(env)
|
|
177
|
+
else # many OR none
|
|
178
|
+
Rack::Request.new(env)
|
|
179
|
+
end
|
|
180
|
+
rescue StandardError => e
|
|
181
|
+
logger.warn(e, LOG_WARN_FRAMEWORK_PARSE)
|
|
182
|
+
Rack::Request.new(env)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
LOG_ERROR_STREAM_CHECK = 'Unable to check for streaming'
|
|
186
|
+
ACTION_CONTROLLER_INSTANCE = 'action_controller.instance'
|
|
187
|
+
# First check to see if an action could potentially be streaming a response
|
|
188
|
+
def possibly_streaming? env
|
|
189
|
+
return false unless defined?(ActionController::Live)
|
|
190
|
+
|
|
191
|
+
env[ACTION_CONTROLLER_INSTANCE].cs__class.included_modules.include?(ActionController::Live)
|
|
192
|
+
rescue StandardError => e
|
|
193
|
+
logger.warn(LOG_ERROR_STREAM_CHECK, e)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
LOG_ERROR_ENSURE = 'Context not defined in middleware ensure.'
|
|
197
|
+
# Send a server activity message and an application activity message
|
|
198
|
+
# and return response
|
|
199
|
+
def handle_ensure context, streaming
|
|
200
|
+
if context
|
|
201
|
+
logger.debug('Middleware request lifecycle complete; flushing context activity to Contrast service.')
|
|
202
|
+
Contrast::Utils::GemfileReader.instance.generate_library_usage(context.activity)
|
|
203
|
+
[context.server_activity, context.activity, context.observed_route].each do |message|
|
|
204
|
+
CONTRAST_SERVICE.send_message message
|
|
205
|
+
end
|
|
206
|
+
else
|
|
207
|
+
logger.error(LOG_ERROR_ENSURE)
|
|
208
|
+
end
|
|
209
|
+
return unless streaming
|
|
210
|
+
|
|
211
|
+
context.reset_activity
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
SECURITY_EXCEPTION_MARKER = 'Contrast::SecurityException'
|
|
215
|
+
LOG_RETHROW_ERROR = 'Re-throwing original error'
|
|
216
|
+
# We're only going to suppress SecurityExceptions indicating a blocked attack.
|
|
217
|
+
# And, only if the config.agent.ruby.exceptions.capture? is set
|
|
218
|
+
def handle_exception exception
|
|
219
|
+
if exception.is_a?(Contrast::SecurityException) ||
|
|
220
|
+
exception.message&.include?(SECURITY_EXCEPTION_MARKER)
|
|
221
|
+
|
|
222
|
+
exception_control = Contrast::Agent::FeatureState.instance.exception_control
|
|
223
|
+
raise exception unless exception_control[:enable]
|
|
224
|
+
|
|
225
|
+
[exception_control[:status], {}, [exception_control[:message]]]
|
|
226
|
+
else
|
|
227
|
+
# Log original re-raise
|
|
228
|
+
logger.debug(exception, LOG_RETHROW_ERROR)
|
|
229
|
+
raise exception
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
LOG_DEBUG_PREFILTER = 'prefilter'
|
|
234
|
+
LOG_ERROR_PREFILTER = 'Unexpected exception during prefilter'
|
|
235
|
+
# Iterate through rules that only depend upon the request object.
|
|
236
|
+
def prefilter context
|
|
237
|
+
return unless context.app_loaded?
|
|
238
|
+
|
|
239
|
+
logger.debug_with_time(LOG_DEBUG_PREFILTER) do
|
|
240
|
+
prefilter_assess(context) if ASSESS.enabled? && context.analyze_request?
|
|
241
|
+
prefilter_protect(context) if PROTECT.enabled?
|
|
242
|
+
end
|
|
243
|
+
rescue Contrast::SecurityException => e
|
|
244
|
+
logger.warn("RASP threw security exception in prefilter: exception=#{ e.message }")
|
|
245
|
+
raise e
|
|
246
|
+
rescue StandardError => e
|
|
247
|
+
logger.error(LOG_ERROR_PREFILTER, e)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def prefilter_assess context
|
|
251
|
+
rules = ASSESS.rules
|
|
252
|
+
logger.debug("Assess: Running #{ rules.length } rules in prefilter.")
|
|
253
|
+
prefilter_rules(rules, context)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def prefilter_protect context
|
|
257
|
+
rules = PROTECT.rules
|
|
258
|
+
logger.debug("Protect: Running #{ rules.length } rules in prefilter.")
|
|
259
|
+
prefilter_rules(rules, context)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def prefilter_rules rules, context
|
|
263
|
+
rules.each do |_, rule|
|
|
264
|
+
rule.prefilter(context)
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
LOG_DEBUG_APPLICATION = 'application'
|
|
269
|
+
# Run the next level of the Rack stack as normal
|
|
270
|
+
def application_code env
|
|
271
|
+
logger.debug_with_time(LOG_DEBUG_APPLICATION) do
|
|
272
|
+
app.call(env)
|
|
273
|
+
end
|
|
274
|
+
rescue Contrast::SecurityException => e
|
|
275
|
+
logger.info("RASP threw security exception in application code: exception=#{ e.message }")
|
|
276
|
+
raise e
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
LOG_DEBUG_POSTFILTER = 'postfilter'
|
|
280
|
+
LOG_ERROR_POSTFILTER = 'Unexpected exception during postfilter'
|
|
281
|
+
# Iterate through rules that depend on the full response object
|
|
282
|
+
def postfilter context, streaming = false
|
|
283
|
+
return unless context.app_loaded?
|
|
284
|
+
|
|
285
|
+
logger.debug_with_time(LOG_DEBUG_POSTFILTER) do
|
|
286
|
+
if ASSESS.enabled? && context.analyze_response?
|
|
287
|
+
logger.debug("Assess:\tRunning #{ ASSESS.rules.length } rules in postfilter.")
|
|
288
|
+
postfilter_rules(ASSESS.rules, context, streaming)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
if PROTECT.enabled?
|
|
292
|
+
logger.debug("Protect:\tRunning #{ PROTECT.rules.length } rules in postfilter.")
|
|
293
|
+
postfilter_rules(PROTECT.rules, context, streaming)
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
rescue Contrast::SecurityException => e
|
|
297
|
+
logger.warn("RASP threw security exception: exception=#{ e.message }")
|
|
298
|
+
raise e
|
|
299
|
+
rescue StandardError => e
|
|
300
|
+
logger.error(LOG_ERROR_POSTFILTER, e)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Iterate through a list of rules with the current context and the full response body
|
|
304
|
+
def postfilter_rules rules, context, streaming
|
|
305
|
+
rules.each do |_, rule|
|
|
306
|
+
if !streaming || rule.stream_safe?
|
|
307
|
+
rule.postfilter(context)
|
|
308
|
+
else
|
|
309
|
+
logger.debug("Skipping rule: #{ rule.name } in streamed response.")
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def run_service_heartbeat_thread
|
|
315
|
+
# Rspec stubs over this method for simplicity's sake in testing.
|
|
316
|
+
# Take care if you refactor this back into #initialize.
|
|
317
|
+
Contrast::Agent::ServiceHeartbeat.new.start
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def run_service_sender_thread
|
|
321
|
+
# Rspec stubs over this method for simplicity's sake in testing.
|
|
322
|
+
# Take care if you refactor this back into #initialize.
|
|
323
|
+
Contrast::Utils::ServiceSenderUtil.start
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
LOG_DEBUG_MW_INV = 'middleware: send inventory'
|
|
327
|
+
LOG_WARN_STATIC_ANALYSIS = 'Unable to run post-initialization static analysis'
|
|
328
|
+
# this is memoized, should only be meaningful after the first agented
|
|
329
|
+
# HTTP request
|
|
330
|
+
def do_static_analysis_catchup
|
|
331
|
+
@_do_static_analysis_catchup ||= begin
|
|
332
|
+
# Everything in here should be asynchronous, as we need to return
|
|
333
|
+
# the HTTP response from middleware ASAP.
|
|
334
|
+
|
|
335
|
+
# Review already-loaded inventory
|
|
336
|
+
logger.debug_with_time('initializer: report loaded gemset') do
|
|
337
|
+
Contrast::Utils::GemfileReader.instance.map_loaded_classes
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# Report already-loaded inventory
|
|
341
|
+
logger.debug_with_time(LOG_DEBUG_MW_INV) do
|
|
342
|
+
settings.send_inventory_message
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
true
|
|
346
|
+
end
|
|
347
|
+
rescue StandardError => e
|
|
348
|
+
logger.warn(LOG_WARN_STATIC_ANALYSIS, e)
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
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
|
+
# A simple wrapper around a Module and a call to its name, used to avoid
|
|
7
|
+
# calling the Module#name method and generating extra Strings
|
|
8
|
+
class ModuleData
|
|
9
|
+
attr_accessor :mod, :name
|
|
10
|
+
def initialize mod, name = nil
|
|
11
|
+
@mod = mod
|
|
12
|
+
@name = name || mod.cs__name
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
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 Patching
|
|
7
|
+
module Policy
|
|
8
|
+
# Used to handle tracking patches that need to apply special instrumentation when a module is loaded
|
|
9
|
+
class AfterLoadPatch
|
|
10
|
+
attr_reader :applied, :module_name, :instrumentation_file_path
|
|
11
|
+
def initialize module_name, instrumentation_file_path
|
|
12
|
+
@applied = false
|
|
13
|
+
@module_name = module_name
|
|
14
|
+
@instrumentation_file_path = instrumentation_file_path
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def applied?
|
|
18
|
+
@applied
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def applies? loaded_module_name
|
|
22
|
+
loaded_module_name == module_name
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def target_defined?
|
|
26
|
+
Module.cs__truly_defined?(module_name)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def instrument!
|
|
30
|
+
cs__scoped_require instrumentation_file_path
|
|
31
|
+
@applied = true
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
cs__scoped_require 'contrast/agent/patching/policy/after_load_patch'
|
|
6
|
+
|
|
7
|
+
module Contrast
|
|
8
|
+
module Agent
|
|
9
|
+
module Patching
|
|
10
|
+
module Policy
|
|
11
|
+
# Some modules diverge from our generic instrumentation and require custom instrumentation
|
|
12
|
+
# after they've been loaded
|
|
13
|
+
module AfterLoadPatcher
|
|
14
|
+
include Contrast::Components::Interface
|
|
15
|
+
access_component :logging
|
|
16
|
+
|
|
17
|
+
AFTER_LOAD_PATCHES = Set.new([
|
|
18
|
+
Contrast::Agent::Patching::Policy::AfterLoadPatch.new(
|
|
19
|
+
'ActiveRecord::AttributeMethods::TimeZoneConversion::ClassMethods',
|
|
20
|
+
'contrast/rails_extensions/assess/action_controller_inheritance'),
|
|
21
|
+
Contrast::Agent::Patching::Policy::AfterLoadPatch.new('ActiveRecord::Scoping::Named::ClassMethods',
|
|
22
|
+
'contrast/rails_extensions/assess/active_record_named'),
|
|
23
|
+
Contrast::Agent::Patching::Policy::AfterLoadPatch.new('ActiveRecord::AttributeMethods::Read::ClassMethods',
|
|
24
|
+
'contrast/rails_extensions/assess/active_record'),
|
|
25
|
+
Contrast::Agent::Patching::Policy::AfterLoadPatch.new('Sinatra::Base',
|
|
26
|
+
'contrast/sinatra_extensions/inventory/sinatra_base')
|
|
27
|
+
])
|
|
28
|
+
|
|
29
|
+
# After initialization run a catchup check to instrument any already loaded modules we care about
|
|
30
|
+
def catchup_after_load_patches
|
|
31
|
+
applied = []
|
|
32
|
+
AFTER_LOAD_PATCHES.each do |after_load_patch|
|
|
33
|
+
next unless after_load_patch.target_defined?
|
|
34
|
+
|
|
35
|
+
logger.debug("Detected loading of #{ after_load_patch.module_name } - applying instrumentation")
|
|
36
|
+
after_load_patch.instrument!
|
|
37
|
+
applied << after_load_patch
|
|
38
|
+
end
|
|
39
|
+
AFTER_LOAD_PATCHES.subtract(applied)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Use for any checks after we've initialized
|
|
43
|
+
def load_patches_for_module module_name
|
|
44
|
+
return if AFTER_LOAD_PATCHES.empty?
|
|
45
|
+
|
|
46
|
+
patch = AFTER_LOAD_PATCHES.find { |after_load_patch| after_load_patch.applies?(module_name) }
|
|
47
|
+
return unless patch
|
|
48
|
+
|
|
49
|
+
logger.debug("Detected loading of #{ module_name } - applying instrumentation")
|
|
50
|
+
|
|
51
|
+
patch.instrument!
|
|
52
|
+
AFTER_LOAD_PATCHES.subtract([patch]) if patch.applied?
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|