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,41 @@
|
|
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 'set'
|
5
|
+
cs__scoped_require 'base64'
|
6
|
+
cs__scoped_require 'contrast/utils/tag_util'
|
7
|
+
cs__scoped_require 'contrast/utils/prevent_serialization'
|
8
|
+
|
9
|
+
module Contrast
|
10
|
+
module Agent
|
11
|
+
module Assess
|
12
|
+
# This class is used as an NoOP version of Properties. We'll pass this to
|
13
|
+
# any attempt to access Properties on a frozen object including
|
14
|
+
# AssessExtension iff that object did not have Properties before it was
|
15
|
+
# placed in a frozen state.
|
16
|
+
class FrozenProperties
|
17
|
+
include Contrast::Utils::PreventSerialization
|
18
|
+
|
19
|
+
def events
|
20
|
+
Contrast::Utils::ObjectShare::EMPTY_ARRAY
|
21
|
+
end
|
22
|
+
|
23
|
+
def properties
|
24
|
+
Contrast::Utils::ObjectShare::EMPTY_HASH
|
25
|
+
end
|
26
|
+
|
27
|
+
def tracked?
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
def tagged? _label
|
32
|
+
false
|
33
|
+
end
|
34
|
+
|
35
|
+
def any_tags_between? _start, _finish
|
36
|
+
false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,53 @@
|
|
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/prevent_serialization'
|
5
|
+
cs__scoped_require 'contrast/agent/assess/properties'
|
6
|
+
|
7
|
+
module Contrast
|
8
|
+
module Agent
|
9
|
+
module Assess
|
10
|
+
# This is just a wrapper around Properties so that if they are on a frozen
|
11
|
+
# object, they are left mutable for us.
|
12
|
+
class Insulator
|
13
|
+
# Return a new delegator with a properties method, used to track
|
14
|
+
# properties in a manner that won't be serialized.
|
15
|
+
#
|
16
|
+
# @return [SimpleDelegator<Object>]
|
17
|
+
def self.generate
|
18
|
+
delegator = SimpleDelegator.new(nil)
|
19
|
+
delegator.extend(Contrast::Utils::PreventPsychSerialization)
|
20
|
+
delegator
|
21
|
+
end
|
22
|
+
|
23
|
+
# Return the frozen properties delegator, which is a
|
24
|
+
#
|
25
|
+
# @return [SimpleDelegator<Object>]
|
26
|
+
def self.generate_frozen
|
27
|
+
@_generate_frozen ||= begin
|
28
|
+
delegator = SimpleDelegator.new(nil)
|
29
|
+
delegator.extend(Contrast::Utils::PreventPsychSerialization)
|
30
|
+
delegator
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Our patch of the SimpleDelegator class, allowing us to leverage its
|
39
|
+
# marshal_dump and marshal_load methods to hide our properties on an object so
|
40
|
+
# that they will not be dumped or loaded.
|
41
|
+
# We do this to prevent polluting data that may run on applications that are no
|
42
|
+
# longer instrumented with Contrast
|
43
|
+
class SimpleDelegator
|
44
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
45
|
+
def properties
|
46
|
+
@delegate_properties ||= Contrast::Agent::Assess::Properties.new
|
47
|
+
end
|
48
|
+
|
49
|
+
def frozen_properties
|
50
|
+
@delegate_frozen_properties ||= Contrast::Agent::Assess::FrozenProperties.new
|
51
|
+
end
|
52
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
53
|
+
end
|
@@ -0,0 +1,78 @@
|
|
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/patching/policy/method_policy'
|
5
|
+
|
6
|
+
module Contrast
|
7
|
+
module Agent
|
8
|
+
module Assess
|
9
|
+
module Policy
|
10
|
+
# This class is used to create dynamic source nodes & source nodes from a db model that receives untrusted data
|
11
|
+
class DynamicSourceFactory
|
12
|
+
DB_SOURCE_TYPE = 'TAINTED_DATABASE'
|
13
|
+
WRITE_QUERY_TIME = 'writeDateTimeUtc'
|
14
|
+
WRITE_QUERY_URL = 'writeRequestUrl'
|
15
|
+
READ_TABLE = 'readTable'
|
16
|
+
READ_COLUMN = 'readColumn'
|
17
|
+
class << self
|
18
|
+
def create_sources klass, tainted_columns
|
19
|
+
instance_methods = klass.instance_methods
|
20
|
+
instance_methods.concat(klass.private_instance_methods)
|
21
|
+
tainted_columns.each_pair do |field, events|
|
22
|
+
dynamic_source_node = create_source_node(klass, field)
|
23
|
+
Contrast::Agent::Assess::Policy::Policy.instance.add_node(dynamic_source_node, :dynamic_source)
|
24
|
+
|
25
|
+
method_policy = Contrast::Agent::Patching::Policy::MethodPolicy.new
|
26
|
+
method_policy.method_name = field.to_sym
|
27
|
+
method_policy.method_visibility = :public
|
28
|
+
method_policy.instance_method = true
|
29
|
+
method_policy.source_node = dynamic_source_node
|
30
|
+
Contrast::Agent::Patching::Policy::Patcher.patch_method(klass, instance_methods, method_policy)
|
31
|
+
|
32
|
+
current_context = Contrast::Agent::REQUEST_TRACKER.current
|
33
|
+
|
34
|
+
next unless current_context.activity.dynamic_sources[dynamic_source_node.id]
|
35
|
+
|
36
|
+
dynamic_source = create_dynamic_source(current_context, dynamic_source_node, field, events)
|
37
|
+
|
38
|
+
node_id = Contrast::Utils::StringUtils.force_utf8(dynamic_source_node.id)
|
39
|
+
current_context.activity.dynamic_sources[node_id] = dynamic_source
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def create_source_node klass, field
|
46
|
+
node = Contrast::Agent::Assess::Policy::SourceNode.new
|
47
|
+
node.class_name = klass.cs__name
|
48
|
+
node.instance_method = true
|
49
|
+
node.method_name = field.to_sym
|
50
|
+
node.method_visibility = :public
|
51
|
+
node.target_string = Contrast::Utils::ObjectShare::RETURN_KEY
|
52
|
+
node.type = DB_SOURCE_TYPE
|
53
|
+
node.add_property('dynamic_source_id', node.id)
|
54
|
+
node
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_dynamic_source current_context, source_node, field, events
|
58
|
+
dynamic_source = Contrast::Api::Dtm::DynamicSource.new
|
59
|
+
dynamic_source.class_name = Contrast::Utils::StringUtils.force_utf8(source_node.class_name)
|
60
|
+
dynamic_source.method_name = Contrast::Utils::StringUtils.force_utf8(field)
|
61
|
+
dynamic_source.instance_method = source_node.instance_method?
|
62
|
+
dynamic_source.target = Contrast::Utils::StringUtils.force_utf8(source_node.target_string)
|
63
|
+
events.each do |event|
|
64
|
+
dynamic_source.events << event.to_dtm_event
|
65
|
+
end
|
66
|
+
dynamic_source.properties[READ_TABLE] = Contrast::Utils::StringUtils.force_utf8(source_node.class_name)
|
67
|
+
dynamic_source.properties[READ_COLUMN] = Contrast::Utils::StringUtils.force_utf8(field)
|
68
|
+
dynamic_source.properties[WRITE_QUERY_TIME] = Contrast::Utils::StringUtils.force_utf8(Contrast::Utils::Timer.now_ms)
|
69
|
+
url = current_context.request.normalized_uri
|
70
|
+
dynamic_source.properties[WRITE_QUERY_URL] = Contrast::Utils::StringUtils.force_utf8(url)
|
71
|
+
dynamic_source
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,85 @@
|
|
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/policy/policy'
|
5
|
+
cs__scoped_require 'contrast/agent/patching/policy/patcher'
|
6
|
+
cs__scoped_require 'contrast/agent/patching/policy/method_policy'
|
7
|
+
cs__scoped_require 'contrast/agent/patching/policy/module_policy'
|
8
|
+
|
9
|
+
module Contrast
|
10
|
+
module Agent
|
11
|
+
module Assess
|
12
|
+
module Policy
|
13
|
+
# This is how we patch into our customer's code. It provides a way to
|
14
|
+
# track which classes we need to patch into and, once we've woven,
|
15
|
+
# provides a map for which methods our renamed functions need to call
|
16
|
+
# and how.
|
17
|
+
module Patcher
|
18
|
+
include Contrast::Components::Interface
|
19
|
+
access_component :logging, :analysis, :agent, :scope
|
20
|
+
|
21
|
+
class << self
|
22
|
+
def policy
|
23
|
+
Contrast::Agent::Assess::Policy::Policy.instance
|
24
|
+
end
|
25
|
+
|
26
|
+
def patcher
|
27
|
+
Contrast::Agent::Patching::Policy::Patcher
|
28
|
+
end
|
29
|
+
|
30
|
+
# Some of the methods we care about, especially those used as dynamic
|
31
|
+
# sources, are truly dynamic, in that they do not exist on class
|
32
|
+
# load. These methods only exist once a module or class eval has been
|
33
|
+
# called. This hook is provided so that patches to those methods can
|
34
|
+
# pass us execution flow once a new method has been made available.
|
35
|
+
def patch_assess_on_eval mod
|
36
|
+
return unless ASSESS.enabled?
|
37
|
+
|
38
|
+
with_contrast_scope { patcher.patch_specific_module(mod) }
|
39
|
+
rescue StandardError => e
|
40
|
+
logger.warn(
|
41
|
+
e,
|
42
|
+
"Unable to patch assess into #{ mod.cs__name } on eval")
|
43
|
+
end
|
44
|
+
|
45
|
+
# Exposed so that methods can be dynamically patched on creation at
|
46
|
+
# runtime, like those generated by
|
47
|
+
# ActiveRecord::AttributeMethods::Read::ClassMethods#define_method_attribute
|
48
|
+
CLASS_TYPES = [
|
49
|
+
Contrast::Utils::ObjectShare::CLASS,
|
50
|
+
Contrast::Utils::ObjectShare::MODULE
|
51
|
+
].cs__freeze
|
52
|
+
def patch_assess_method clazz, method_name
|
53
|
+
# Module.define_method is called a lot in Class and Module. We
|
54
|
+
# currently do not expect these define_methods to result in methods
|
55
|
+
# that require patching, so for the sake of performance, we're going
|
56
|
+
# to skip evaluating them
|
57
|
+
class_name = clazz.cs__name
|
58
|
+
return if CLASS_TYPES.include?(class_name)
|
59
|
+
return unless ASSESS.enabled?
|
60
|
+
|
61
|
+
source_nodes = Contrast::Agent::Patching::Policy::ModulePolicy.nodes_for_module(policy.sources, class_name)
|
62
|
+
return if source_nodes.empty?
|
63
|
+
|
64
|
+
method_array = []
|
65
|
+
method_array << method_name
|
66
|
+
source_nodes.each do |source_node|
|
67
|
+
next unless source_node.method_name.to_s == method_name
|
68
|
+
|
69
|
+
method_policy = Contrast::Agent::Patching::Policy::MethodPolicy.new(source_node: source_node,
|
70
|
+
method_name: source_node.method_name,
|
71
|
+
method_visibility: source_node.method_visibility,
|
72
|
+
instance_method: true)
|
73
|
+
patcher.patch_method(clazz, method_array, method_policy)
|
74
|
+
end
|
75
|
+
rescue StandardError => e
|
76
|
+
logger.warn(
|
77
|
+
e,
|
78
|
+
"Unable to patch assess into #{ class_name }##{ method_name } on define_method_attribute")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,116 @@
|
|
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 'json'
|
5
|
+
cs__scoped_require 'contrast/agent/assess/rule/provider/hardcoded_value_rule'
|
6
|
+
cs__scoped_require 'contrast/agent/assess/rule/provider/hardcoded_key'
|
7
|
+
cs__scoped_require 'contrast/agent/assess/rule/provider/hardcoded_password'
|
8
|
+
cs__scoped_require 'contrast/agent/assess/policy/policy_node'
|
9
|
+
cs__scoped_require 'contrast/agent/assess/policy/source_node'
|
10
|
+
cs__scoped_require 'contrast/agent/assess/policy/propagation_node'
|
11
|
+
cs__scoped_require 'contrast/agent/assess/policy/trigger_node'
|
12
|
+
cs__scoped_require 'contrast/agent/patching/policy/policy'
|
13
|
+
|
14
|
+
module Contrast
|
15
|
+
module Agent
|
16
|
+
module Assess
|
17
|
+
module Policy
|
18
|
+
# This is just a holder for our policy. Takes the policy JSON and
|
19
|
+
# converts it into hashes that we can access nicely
|
20
|
+
class Policy < Contrast::Agent::Patching::Policy::Policy
|
21
|
+
# Indicates the folder in `resources` where this policy lives.
|
22
|
+
def self.policy_folder
|
23
|
+
'assess'
|
24
|
+
end
|
25
|
+
|
26
|
+
# Indicates is this feature has been disabled by the configuration,
|
27
|
+
# read at startup, and therefore can never be enabled.
|
28
|
+
def disabled_globally?
|
29
|
+
ASSESS.forcibly_disabled?
|
30
|
+
end
|
31
|
+
|
32
|
+
def node_type
|
33
|
+
Contrast::Agent::Assess::Policy::TriggerNode
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize
|
37
|
+
super
|
38
|
+
load_providers
|
39
|
+
end
|
40
|
+
|
41
|
+
# Our policy for dataflow rules is a 'dope ass' JSON file. Rather than
|
42
|
+
# hard code in a bunch of things to monkey patch, we let the JSON file
|
43
|
+
# define the conditions in which sources, propagators, and triggers are
|
44
|
+
# applied.
|
45
|
+
# This let's us be flexible and extensible
|
46
|
+
# * when we want to do lvl 2 rules, we could have the customers unzip
|
47
|
+
# our gem, insert things into the json, zip, and go *
|
48
|
+
def from_hash_string string
|
49
|
+
# The default behavior of the agent is to load the policy on startup,
|
50
|
+
# as at this point we do not know in which mode we'll be run.
|
51
|
+
#
|
52
|
+
# If the configuration file explicitly disables a feature, we know
|
53
|
+
# that we will not ever be able to enable it, so in that case, we
|
54
|
+
# can skip policy loading.
|
55
|
+
return if disabled_globally?
|
56
|
+
|
57
|
+
policy_data = JSON.parse(string)
|
58
|
+
|
59
|
+
policy_data[SOURCES_KEY].each do |source_hash|
|
60
|
+
source = Contrast::Agent::Assess::Policy::SourceNode.new(source_hash)
|
61
|
+
add_node(source, :source)
|
62
|
+
end
|
63
|
+
|
64
|
+
policy_data[PROPAGATION_KEY].each do |propagator_hash|
|
65
|
+
prop = Contrast::Agent::Assess::Policy::PropagationNode.new(propagator_hash)
|
66
|
+
add_node(prop, :propagator)
|
67
|
+
end
|
68
|
+
|
69
|
+
policy_data[RULES_KEY].each do |rule_hash|
|
70
|
+
rule_hash[TRIGGERS_KEY].each do |trigger_hash|
|
71
|
+
trigger_node = node_type.new(trigger_hash, rule_hash)
|
72
|
+
add_node(trigger_node)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
tracked_classes.concat(policy_data[TRACKED_CLASSES_KEY])
|
77
|
+
end
|
78
|
+
|
79
|
+
# Providers is a term that we're taking from Java until we come up with
|
80
|
+
# a name that we (I) don't hate. Basically, these are more static like
|
81
|
+
# rules. They don't do dataflow or response scanning. Instead, they
|
82
|
+
# watch for things to be loaded (configs, classes, whateves) and
|
83
|
+
# determine if these loaded things are unsafe.
|
84
|
+
#
|
85
|
+
# ** if we want, we could add this as a section to the aforementioned
|
86
|
+
# 'dope ass' JSON
|
87
|
+
def load_providers
|
88
|
+
PROVIDER_CLASSES.each do |clazz|
|
89
|
+
instance = clazz.new
|
90
|
+
providers[instance.rule_id] = instance
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
PROVIDER_CLASSES = [
|
95
|
+
Contrast::Agent::Assess::Rule::Provider::HardcodedKey,
|
96
|
+
Contrast::Agent::Assess::Rule::Provider::HardcodedPassword
|
97
|
+
].cs__freeze
|
98
|
+
|
99
|
+
# Handles updating the dynamic sources of this Application and indicates
|
100
|
+
# if doing so results in a state that requires repatching -- i.e. new
|
101
|
+
# dynamic sources have been discovered by agents monitoring other
|
102
|
+
# instances of this application
|
103
|
+
def update_dynamic_sources dynamic_sources_map
|
104
|
+
dynamic_sources_map.each do |key, dynamic_source|
|
105
|
+
# key is the dynamic source node id
|
106
|
+
next if sources.any? { |source| source.id == key }
|
107
|
+
|
108
|
+
dynamic_source_node = Contrast::Agent::Assess::Policy::SourceNode.build_dynamic_source(key, dynamic_source)
|
109
|
+
add_node(dynamic_source_node, :dynamic_source)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,289 @@
|
|
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/patching/policy/policy_node'
|
5
|
+
|
6
|
+
module Contrast
|
7
|
+
module Agent
|
8
|
+
module Assess
|
9
|
+
module Policy
|
10
|
+
# This class functions to translate our policy.json into an actionable
|
11
|
+
# Ruby object, allowing for dynamic patching over hardcoded patching.
|
12
|
+
class PolicyNode < Contrast::Agent::Patching::Policy::PolicyNode
|
13
|
+
attr_accessor :tags, :type
|
14
|
+
attr_reader :sources, :targets, :source_string, :target_string
|
15
|
+
|
16
|
+
def initialize policy_hash = {}
|
17
|
+
super(policy_hash)
|
18
|
+
@source_string = policy_hash[JSON_SOURCE]
|
19
|
+
@target_string = policy_hash[JSON_TARGET]
|
20
|
+
@tags = Set.new(policy_hash[JSON_TAGS])
|
21
|
+
generate_sources
|
22
|
+
generate_targets
|
23
|
+
end
|
24
|
+
|
25
|
+
def feature
|
26
|
+
'Assess'
|
27
|
+
end
|
28
|
+
|
29
|
+
def node_class
|
30
|
+
'Node'
|
31
|
+
end
|
32
|
+
|
33
|
+
def node_type
|
34
|
+
:TYPE_METHOD
|
35
|
+
end
|
36
|
+
|
37
|
+
def target
|
38
|
+
@_target ||= begin
|
39
|
+
if targets&.any?
|
40
|
+
targets[0]
|
41
|
+
elsif sources&.any?
|
42
|
+
sources[0]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def source_string= value
|
48
|
+
@source_string = value
|
49
|
+
generate_sources
|
50
|
+
end
|
51
|
+
|
52
|
+
def target_string= value
|
53
|
+
@target_string = value
|
54
|
+
generate_targets
|
55
|
+
end
|
56
|
+
|
57
|
+
# Sometimes we need to tie information to an event. We'll add a
|
58
|
+
# properties section to the patch node, which can pass them along to
|
59
|
+
# the pre-dtm event
|
60
|
+
def add_property name, value
|
61
|
+
return unless name && value
|
62
|
+
|
63
|
+
@properties ||= {}
|
64
|
+
@properties[name] = value
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_property name
|
68
|
+
return unless @properties
|
69
|
+
|
70
|
+
@properties[name]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Given a source in the format A,B,C, populate the sources of this node
|
74
|
+
# 1) Split on ','
|
75
|
+
# 2) If 'O', add the source, else it's P (we don't have R sources) and
|
76
|
+
# needs to be converted. P type will either be P:name or P# where #
|
77
|
+
# is the index of the paramter. Drop the P and store the int as int
|
78
|
+
# or name as symbol
|
79
|
+
def generate_sources
|
80
|
+
if source_string
|
81
|
+
@sources = []
|
82
|
+
source_string.split(Contrast::Utils::ObjectShare::COMMA).each do |s|
|
83
|
+
is_object = (s == Contrast::Utils::ObjectShare::OBJECT_KEY)
|
84
|
+
if is_object
|
85
|
+
@sources << s
|
86
|
+
else
|
87
|
+
parameter_source = s[1..-1]
|
88
|
+
@sources << if parameter_source.start_with?(Contrast::Utils::ObjectShare::COLON)
|
89
|
+
parameter_source[1..-1].to_sym
|
90
|
+
else
|
91
|
+
parameter_source.to_i
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
else
|
96
|
+
@sources = Contrast::Utils::ObjectShare::EMPTY_ARRAY
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Given a target in the format A,B,C, populate the targets of this node
|
101
|
+
# 1) Split on ','
|
102
|
+
# 2) If 'O' or 'R', add the target, else it's P and needs to be
|
103
|
+
# converted. P type will either be P:name or P# where # is the index
|
104
|
+
# of the paramter. Drop the P and store the int as int or name as
|
105
|
+
# symbol
|
106
|
+
def generate_targets
|
107
|
+
if target_string
|
108
|
+
@targets = []
|
109
|
+
target_string.split(Contrast::Utils::ObjectShare::COMMA).each do |t|
|
110
|
+
case t
|
111
|
+
when Contrast::Utils::ObjectShare::OBJECT_KEY
|
112
|
+
@targets << t
|
113
|
+
when Contrast::Utils::ObjectShare::RETURN_KEY
|
114
|
+
@targets << t
|
115
|
+
else
|
116
|
+
parameter_target = t[1..-1]
|
117
|
+
@targets << if parameter_target.start_with?(Contrast::Utils::ObjectShare::COLON)
|
118
|
+
parameter_target[1..-1].to_sym
|
119
|
+
else
|
120
|
+
parameter_target.to_i
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
else
|
125
|
+
@targets = Contrast::Utils::ObjectShare::EMPTY_ARRAY
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Don't let nodes be created that will be missing things we need
|
130
|
+
# later on. Really, if they don't have these things, they couldn't have
|
131
|
+
# done their jobs anyway.
|
132
|
+
def validate
|
133
|
+
super
|
134
|
+
validate_tags
|
135
|
+
end
|
136
|
+
|
137
|
+
# TeamServer is picky. The tags here match to ENUMs there. If there
|
138
|
+
# isn't a matching ENUM in TS land, the database gets got. We really
|
139
|
+
# don't want to get them, so we're going to prevent the node from being
|
140
|
+
# made.
|
141
|
+
def validate_tags
|
142
|
+
return unless tags
|
143
|
+
|
144
|
+
tags.each do |tag|
|
145
|
+
next if VALID_TAGS.include?(tag) || VALID_SOURCE_TAGS.include?(tag)
|
146
|
+
|
147
|
+
raise(ArgumentError,
|
148
|
+
"#{ node_class } #{ id } had an invalid tag. #{ tag } is not a known value.")
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
ALL_TYPE = 'A'
|
153
|
+
CREATION_TYPE = 'CREATION'
|
154
|
+
TRIGGER_TYPE = 'TRIGGER'
|
155
|
+
TO_MARKER = '2'
|
156
|
+
# Convert our action, built from our source and target, into
|
157
|
+
# the TS appropriate action. That's a single source to single
|
158
|
+
# target marker (A,O,P,R)
|
159
|
+
#
|
160
|
+
# Creation (source nodes) don't have sources (they are the source)
|
161
|
+
# Trigger (trigger nodes) don't have targets (they are the target)
|
162
|
+
# Everything else (propagation nodes) are Source2Target
|
163
|
+
def build_action
|
164
|
+
@event_action ||= begin
|
165
|
+
source = source_string
|
166
|
+
target = target_string
|
167
|
+
if source.nil?
|
168
|
+
:CREATION
|
169
|
+
elsif target.nil?
|
170
|
+
:TRIGGER
|
171
|
+
else
|
172
|
+
# TeamServer can't handle the multi-source or multi-target
|
173
|
+
# values. Give it some help by changing them to 'A'
|
174
|
+
source = ALL_TYPE if source.include?(Contrast::Utils::ObjectShare::COMMA)
|
175
|
+
target = ALL_TYPE if target.include?(Contrast::Utils::ObjectShare::COMMA)
|
176
|
+
str = source[0] + TO_MARKER + target[0] # TODO: RUBY-139 PERF -- save in the patcher
|
177
|
+
str.to_sym
|
178
|
+
end
|
179
|
+
end
|
180
|
+
@event_action
|
181
|
+
end
|
182
|
+
|
183
|
+
# EventTagTypeDTM
|
184
|
+
VALID_TAGS = %w[
|
185
|
+
XML_ENCODED
|
186
|
+
XML_DECODED
|
187
|
+
HTML_ENCODED
|
188
|
+
HTML_DECODED
|
189
|
+
URL_ENCODED
|
190
|
+
URL_DECODED
|
191
|
+
CSS_ENCODED
|
192
|
+
CSS_DECODED
|
193
|
+
BASE64_ENCODED
|
194
|
+
BASE64_DECODED
|
195
|
+
JAVASCRIPT_ENCODED
|
196
|
+
JAVASCRIPT_DECODED
|
197
|
+
JAVA_ENCODED
|
198
|
+
JAVA_DECODED
|
199
|
+
CSV_ENCODED
|
200
|
+
CSV_DECODED
|
201
|
+
SQL_ENCODED
|
202
|
+
SQL_DECODED
|
203
|
+
LDAP_ENCODED
|
204
|
+
LDAP_DECODED
|
205
|
+
XPATH_ENCODED
|
206
|
+
XPATH_DECODED
|
207
|
+
OS_ENCODED
|
208
|
+
OS_DECODED
|
209
|
+
VBSCRIPT_ENCODED
|
210
|
+
VBSCRIPT_DECODED
|
211
|
+
POTENTIAL_SANITIZED
|
212
|
+
POTENTIAL_VALIDATED
|
213
|
+
NO_CONTROL_CHARS
|
214
|
+
CUSTOM
|
215
|
+
|
216
|
+
CUSTOM_ENCODED
|
217
|
+
CUSTOM_ENCODED_CMD_INJECTION
|
218
|
+
CUSTOM_ENCODED_EXPRESSION_LANGUAGE_INJECTION
|
219
|
+
CUSTOM_ENCODED_HEADER_INJECTION
|
220
|
+
CUSTOM_ENCODED_HQL_INJECTION
|
221
|
+
CUSTOM_ENCODED_LDAP_INJECTION
|
222
|
+
CUSTOM_ENCODED_LOG_INJECTION
|
223
|
+
CUSTOM_ENCODED_NOSQL_INJECTION
|
224
|
+
CUSTOM_ENCODED_PATH_TRAVERSAL
|
225
|
+
CUSTOM_ENCODED_REDOS
|
226
|
+
CUSTOM_ENCODED_REFLECTED_XSS
|
227
|
+
CUSTOM_ENCODED_REFLECTION_INJECTION
|
228
|
+
CUSTOM_ENCODED_SMTP_INJECTION
|
229
|
+
CUSTOM_ENCODED_SQL_INJECTION
|
230
|
+
CUSTOM_ENCODED_SSRF
|
231
|
+
CUSTOM_ENCODED_STORED_XSS
|
232
|
+
CUSTOM_ENCODED_TRUST_BOUNDARY_VIOLATION
|
233
|
+
CUSTOM_ENCODED_UNSAFE_CODE_EXECUTION
|
234
|
+
CUSTOM_ENCODED_UNSAFE_READLINE
|
235
|
+
CUSTOM_ENCODED_UNSAFE_XML_DECODE
|
236
|
+
CUSTOM_ENCODED_UNTRUSTED_DESERIALIZATION
|
237
|
+
CUSTOM_ENCODED_UNVALIDATED_FORWARD
|
238
|
+
CUSTOM_ENCODED_UNVALIDATED_REDIRECT
|
239
|
+
CUSTOM_ENCODED_XPATH_INJECTION
|
240
|
+
CUSTOM_ENCODED_XXE
|
241
|
+
CUSTOM_SECURITY_CONTROL_APPLIED
|
242
|
+
|
243
|
+
CUSTOM_VALIDATED
|
244
|
+
CUSTOM_VALIDATED_CMD_INJECTION
|
245
|
+
CUSTOM_VALIDATED_EXPRESSION_LANGUAGE_INJECTION
|
246
|
+
CUSTOM_VALIDATED_HEADER_INJECTION
|
247
|
+
CUSTOM_VALIDATED_HQL_INJECTION
|
248
|
+
CUSTOM_VALIDATED_LDAP_INJECTION
|
249
|
+
CUSTOM_VALIDATED_LOG_INJECTION
|
250
|
+
CUSTOM_VALIDATED_NOSQL_INJECTION
|
251
|
+
CUSTOM_VALIDATED_PATH_TRAVERSAL
|
252
|
+
CUSTOM_VALIDATED_REDOS
|
253
|
+
CUSTOM_VALIDATED_REFLECTED_XSS
|
254
|
+
CUSTOM_VALIDATED_REFLECTION_INJECTION
|
255
|
+
CUSTOM_VALIDATED_SMTP_INJECTION
|
256
|
+
CUSTOM_VALIDATED_SQL_INJECTION
|
257
|
+
CUSTOM_VALIDATED_SSRF
|
258
|
+
CUSTOM_VALIDATED_STORED_XSS
|
259
|
+
CUSTOM_VALIDATED_TRUST_BOUNDARY_VIOLATION
|
260
|
+
CUSTOM_VALIDATED_UNSAFE_CODE_EXECUTION
|
261
|
+
CUSTOM_VALIDATED_UNSAFE_READLINE
|
262
|
+
CUSTOM_VALIDATED_UNSAFE_XML_DECODE
|
263
|
+
CUSTOM_VALIDATED_UNTRUSTED_DESERIALIZATION
|
264
|
+
CUSTOM_VALIDATED_UNVALIDATED_FORWARD
|
265
|
+
CUSTOM_VALIDATED_UNVALIDATED_REDIRECT
|
266
|
+
CUSTOM_VALIDATED_XPATH_INJECTION
|
267
|
+
CUSTOM_VALIDATED_XXE
|
268
|
+
|
269
|
+
DATABASE_WRITE
|
270
|
+
].cs__freeze
|
271
|
+
|
272
|
+
VALID_SOURCE_TAGS = %w[
|
273
|
+
NO_NEWLINES
|
274
|
+
UNTRUSTED
|
275
|
+
CROSS_SITE
|
276
|
+
LIMITED_CHARS
|
277
|
+
].cs__freeze
|
278
|
+
|
279
|
+
# The keys used to read from policy.json to create the individual
|
280
|
+
# policy nodes. These are common across node types
|
281
|
+
JSON_SOURCE = 'source'
|
282
|
+
JSON_TARGET = 'target'
|
283
|
+
JSON_TAGS = 'tags'
|
284
|
+
JSON_DATAFLOW = 'dataflow'
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|