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,44 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
cs__scoped_require 'contrast/utils/object_share'
|
|
5
|
+
cs__scoped_require 'contrast/components/interface'
|
|
6
|
+
cs__scoped_require 'contrast/core_extensions/assess/assess_extension'
|
|
7
|
+
|
|
8
|
+
module Contrast
|
|
9
|
+
module Agent
|
|
10
|
+
module Assess
|
|
11
|
+
module Policy
|
|
12
|
+
# This is how we scan our customer's code. It provides a way to analyze
|
|
13
|
+
# the classes we need to observe to find vulnerabilities in the context
|
|
14
|
+
# of a file vs data flow, such as the detection of Hardcoded Passwords
|
|
15
|
+
# or Keys.
|
|
16
|
+
module PolicyScanner
|
|
17
|
+
include Contrast::Components::Interface
|
|
18
|
+
access_component :analysis, :logging
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
def scan trace_point
|
|
22
|
+
return unless ASSESS.enabled?
|
|
23
|
+
return unless ASSESS.require_scan?
|
|
24
|
+
|
|
25
|
+
return unless trace_point.path
|
|
26
|
+
return if trace_point.path.start_with?(Gem.dir)
|
|
27
|
+
|
|
28
|
+
mod = trace_point.self
|
|
29
|
+
return if mod.cs__frozen? || mod.singleton_class?
|
|
30
|
+
|
|
31
|
+
policy.providers.each_value do |provider|
|
|
32
|
+
provider.analyze mod
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def policy
|
|
37
|
+
Contrast::Agent::Assess::Policy::Policy.instance
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
cs__scoped_require 'contrast/components/interface'
|
|
5
|
+
|
|
6
|
+
module Contrast
|
|
7
|
+
module Agent
|
|
8
|
+
module Assess
|
|
9
|
+
# In order to properly shift tags to account for the changes this method
|
|
10
|
+
# caused, we'll need to store the state before the change occurred.
|
|
11
|
+
class PreShift
|
|
12
|
+
include Contrast::Components::Interface
|
|
13
|
+
access_component :analysis, :logging
|
|
14
|
+
|
|
15
|
+
UNDUPLICABLE_MODULES = [
|
|
16
|
+
Enumerator # dup'ing results in 'can't copy execution context'
|
|
17
|
+
].cs__freeze
|
|
18
|
+
|
|
19
|
+
attr_accessor :object, :object_length, :args, :arg_lengths
|
|
20
|
+
|
|
21
|
+
class << self
|
|
22
|
+
# Save the state before we do the propagation. This is one of the
|
|
23
|
+
# few things that we'll call BEFORE calling the original method.
|
|
24
|
+
# Unfortunately, we may waste some time here if the method then
|
|
25
|
+
# throws an exception, but hey, it threw an exception. These few
|
|
26
|
+
# extra objects aren't the real problem in that case.
|
|
27
|
+
#
|
|
28
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode]
|
|
29
|
+
# The node responsible for the propagation action required by this
|
|
30
|
+
# method.
|
|
31
|
+
# @param object [Object] the object on which the method is to be
|
|
32
|
+
# called.
|
|
33
|
+
# @param args [Array<Object>] the arguments to be passed to the
|
|
34
|
+
# method.
|
|
35
|
+
# @return [Contrast::Agent::Assess::PreShift, nil] a holder saving
|
|
36
|
+
# the state of the object and arguments just prior to the method
|
|
37
|
+
# being called or nil if one is not required.
|
|
38
|
+
def build_preshift propagation_node, object, args
|
|
39
|
+
return nil unless propagation_node
|
|
40
|
+
return nil unless ASSESS.enabled?
|
|
41
|
+
|
|
42
|
+
initializing = propagation_node.method_name == :initialize
|
|
43
|
+
return nil if unsafe_io_object?(object, initializing)
|
|
44
|
+
|
|
45
|
+
needs_object = propagation_node.needs_object?
|
|
46
|
+
needs_args = propagation_node.needs_args?
|
|
47
|
+
|
|
48
|
+
preshift = Contrast::Agent::Assess::PreShift.new
|
|
49
|
+
append_object_details(preshift, initializing, object) if needs_object
|
|
50
|
+
append_arg_details(preshift, args) if needs_args
|
|
51
|
+
|
|
52
|
+
preshift
|
|
53
|
+
rescue StandardError => e
|
|
54
|
+
logger.error(e, 'Unable to build preshift for method.')
|
|
55
|
+
nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def unsafe_io_object? object, initializing
|
|
61
|
+
Contrast::Utils::DuckUtils.quacks_like_closable_io(object) && !initializing && object.closed?
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def can_dup? initializing, object
|
|
65
|
+
return false if initializing
|
|
66
|
+
|
|
67
|
+
check = object.is_a?(Module) ? object : object.cs__class
|
|
68
|
+
!UNDUPLICABLE_MODULES.include?(check)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def append_object_details preshift, initializing, object
|
|
72
|
+
preshift.object = can_dup?(initializing, object) ? object.dup : object
|
|
73
|
+
preshift.object.cs__copy_from(object) if object.cs__frozen? && Contrast::Utils::DuckUtils.quacks_to?(preshift.object, :cs__copy_from)
|
|
74
|
+
preshift.object_length = if Contrast::Utils::DuckUtils.quacks_to?(preshift.object, :length)
|
|
75
|
+
object.length
|
|
76
|
+
else
|
|
77
|
+
0
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def append_arg_details preshift, args
|
|
82
|
+
preshift.args = args.dup
|
|
83
|
+
preshift.args.each_with_index do |arg, index|
|
|
84
|
+
next unless args[index].cs__frozen? && Contrast::Utils::DuckUtils.quacks_to?(arg, :cs__copy_from)
|
|
85
|
+
|
|
86
|
+
arg.cs__copy_from(args[index])
|
|
87
|
+
end
|
|
88
|
+
preshift.arg_lengths = preshift.args.map { |arg| Contrast::Utils::DuckUtils.quacks_to?(arg, :length) ? arg.length : 0 }
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,260 @@
|
|
|
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
|
+
# This class is responsible for the continuation of traces. A Propagator is any
|
|
5
|
+
# method that transforms an untrusted value. In general, these methods work on
|
|
6
|
+
# the String class or a holder of Strings
|
|
7
|
+
cs__scoped_require 'set'
|
|
8
|
+
|
|
9
|
+
cs__scoped_require 'contrast/utils/object_share'
|
|
10
|
+
cs__scoped_require 'contrast/utils/sha256_builder'
|
|
11
|
+
|
|
12
|
+
cs__scoped_require 'contrast/agent/assess/policy/propagator'
|
|
13
|
+
|
|
14
|
+
cs__scoped_require 'contrast/components/interface'
|
|
15
|
+
|
|
16
|
+
module Contrast
|
|
17
|
+
module Agent
|
|
18
|
+
module Assess
|
|
19
|
+
module Policy
|
|
20
|
+
# This module contains the logic for determining how to propagate tags
|
|
21
|
+
# and events from a source to a target
|
|
22
|
+
module PropagationMethod
|
|
23
|
+
include Contrast::Components::Interface
|
|
24
|
+
access_component :logging
|
|
25
|
+
|
|
26
|
+
APPEND_ACTION = 'APPEND'
|
|
27
|
+
CENTER_ACTION = 'CENTER'
|
|
28
|
+
INSERT_ACTION = 'INSERT'
|
|
29
|
+
KEEP_ACTION = 'KEEP'
|
|
30
|
+
NEXT_ACTION = 'NEXT'
|
|
31
|
+
PREPEND_ACTION = 'PREPEND'
|
|
32
|
+
REPLACE_ACTION = 'REPLACE'
|
|
33
|
+
REMOVE_ACTION = 'REMOVE'
|
|
34
|
+
REVERSE_ACTION = 'REVERSE'
|
|
35
|
+
SPLAT_ACTION = 'SPLAT'
|
|
36
|
+
SPLIT_ACTION = 'SPLIT'
|
|
37
|
+
TAG_ACTION = 'TAG'
|
|
38
|
+
DB_WRITE_ACTION = 'DB_WRITE'
|
|
39
|
+
CUSTOM_ACTION = 'CUSTOM'
|
|
40
|
+
|
|
41
|
+
class << self
|
|
42
|
+
def determine_target propagation_node, ret, object, args
|
|
43
|
+
target_key = propagation_node.targets[0]
|
|
44
|
+
return ret if target_key == Contrast::Utils::ObjectShare::RETURN_KEY
|
|
45
|
+
return object if target_key == Contrast::Utils::ObjectShare::OBJECT_KEY
|
|
46
|
+
|
|
47
|
+
return args[target_key] if target_key.is_a?(Integer)
|
|
48
|
+
|
|
49
|
+
arg = nil
|
|
50
|
+
args.each do |search|
|
|
51
|
+
next unless search.is_a?(Hash)
|
|
52
|
+
|
|
53
|
+
arg = search[target_key]
|
|
54
|
+
break if arg
|
|
55
|
+
end
|
|
56
|
+
arg
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def apply_propagation method_policy, preshift, object, ret, args, block
|
|
60
|
+
return unless method_policy.propagation_node
|
|
61
|
+
return unless preshift
|
|
62
|
+
|
|
63
|
+
propagation_node = method_policy.propagation_node
|
|
64
|
+
|
|
65
|
+
target = determine_target(propagation_node, ret, object, args)
|
|
66
|
+
PropagationMethod.apply_propagator(propagation_node, preshift, target, object, ret, 0, args, block)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
PROPAGATION_ACTIONS = {
|
|
70
|
+
APPEND_ACTION => Contrast::Agent::Assess::Policy::Propagator::Append,
|
|
71
|
+
CENTER_ACTION => Contrast::Agent::Assess::Policy::Propagator::Center,
|
|
72
|
+
INSERT_ACTION => Contrast::Agent::Assess::Policy::Propagator::Insert,
|
|
73
|
+
KEEP_ACTION => Contrast::Agent::Assess::Policy::Propagator::Keep,
|
|
74
|
+
NEXT_ACTION => Contrast::Agent::Assess::Policy::Propagator::Next,
|
|
75
|
+
PREPEND_ACTION => Contrast::Agent::Assess::Policy::Propagator::Prepend,
|
|
76
|
+
REPLACE_ACTION => Contrast::Agent::Assess::Policy::Propagator::Replace,
|
|
77
|
+
REMOVE_ACTION => Contrast::Agent::Assess::Policy::Propagator::Remove,
|
|
78
|
+
REVERSE_ACTION => Contrast::Agent::Assess::Policy::Propagator::Reverse,
|
|
79
|
+
SPLAT_ACTION => Contrast::Agent::Assess::Policy::Propagator::Splat,
|
|
80
|
+
SPLIT_ACTION => Contrast::Agent::Assess::Policy::Propagator::Split
|
|
81
|
+
}.cs__freeze
|
|
82
|
+
|
|
83
|
+
# I lied above. We had to figure out what the target of the propagation was.
|
|
84
|
+
# Now that we know, we'll actually do things to it.
|
|
85
|
+
def apply_propagator propagation_node, preshift, target, object, ret, invoked, args, block
|
|
86
|
+
context = Contrast::Agent::REQUEST_TRACKER.current
|
|
87
|
+
return unless context && propagation_node && valid_target?(target, propagation_node)
|
|
88
|
+
return unless valid_length?(target, propagation_node.action)
|
|
89
|
+
|
|
90
|
+
if propagation_node.action == DB_WRITE_ACTION
|
|
91
|
+
Contrast::Agent::Assess::Policy::Propagator::DatabaseWrite.propagate(propagation_node, preshift, ret)
|
|
92
|
+
elsif propagation_node.action == CUSTOM_ACTION
|
|
93
|
+
Contrast::Agent::Assess::Policy::Propagator::Custom.propagate(propagation_node, preshift, ret, block)
|
|
94
|
+
elsif propagation_node.action == SPLIT_ACTION
|
|
95
|
+
Contrast::Agent::Assess::Policy::Propagator::Split.propagate(propagation_node, preshift, target)
|
|
96
|
+
logger.debug(
|
|
97
|
+
nil,
|
|
98
|
+
"Propagator #{ propagation_node.id } detected: propagated to #{ target.__id__ }")
|
|
99
|
+
elsif Contrast::Utils::DuckUtils.quacks_to?(target, :cs__properties)
|
|
100
|
+
handle_cs_properties_propagation(propagation_node, preshift, target, object, ret, invoked, args, block)
|
|
101
|
+
elsif Contrast::Utils::DuckUtils.quacks_like_tracked_hash?(target)
|
|
102
|
+
handle_hash_propagation(propagation_node, preshift, target, object, ret, invoked, args, block)
|
|
103
|
+
elsif Contrast::Utils::DuckUtils.quacks_like_tracked_enumerable?(target)
|
|
104
|
+
handle_enumerable_propagation(propagation_node, preshift, target, object, ret, invoked, args, block)
|
|
105
|
+
end
|
|
106
|
+
rescue StandardError => e
|
|
107
|
+
logger.warn(e, "Unable to apply propagator #{ propagation_node.id }")
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Custom actions tend to be the more complex of our propagations.
|
|
111
|
+
# Often, the method has to make decisions about the target based on
|
|
112
|
+
# the context with which the method was called. As such, defer
|
|
113
|
+
# determining if the target is valid to that method.
|
|
114
|
+
#
|
|
115
|
+
# In all other cases, a target is valid for propagation if it is not
|
|
116
|
+
# nil
|
|
117
|
+
def valid_target? target, propagation_node
|
|
118
|
+
return true if propagation_node.action == CUSTOM_ACTION
|
|
119
|
+
|
|
120
|
+
!!target
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
ZERO_LENGTH_ACTIONS = [
|
|
124
|
+
DB_WRITE_ACTION,
|
|
125
|
+
CUSTOM_ACTION,
|
|
126
|
+
KEEP_ACTION,
|
|
127
|
+
REPLACE_ACTION,
|
|
128
|
+
SPLAT_ACTION
|
|
129
|
+
].cs__freeze
|
|
130
|
+
# If the action required needs a length and the target does not have
|
|
131
|
+
# one, the length is not valid
|
|
132
|
+
def valid_length? target, action
|
|
133
|
+
return true if ZERO_LENGTH_ACTIONS.include?(action)
|
|
134
|
+
|
|
135
|
+
if Contrast::Utils::DuckUtils.quacks_to?(target, :length)
|
|
136
|
+
target.length != 0 # rubocop:disable Style/ZeroLengthPredicate
|
|
137
|
+
else
|
|
138
|
+
!target.to_s.empty?
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Before we do any work, we should check if we even need to.
|
|
143
|
+
# If the source of this patcher is not tracked, there's no need to do
|
|
144
|
+
# anything. A copy of nothing is still nothing.
|
|
145
|
+
def can_propagate? propagation_node, preshift, target
|
|
146
|
+
# We cannot propagate to things that do not have cs__properties.
|
|
147
|
+
return false unless Contrast::Utils::DuckUtils.quacks_to?(target, :cs__properties)
|
|
148
|
+
|
|
149
|
+
# We cannot propagate to frozen things that have not been
|
|
150
|
+
# previously tracked. We probably shouldn't propagate to frozen
|
|
151
|
+
# things at all, as they're supposed to be immutable, but third
|
|
152
|
+
# parties do jenky things, so allow it as long as it is safe to do.
|
|
153
|
+
return false if target.cs__properties == Contrast::Agent::Assess::Insulator.generate_frozen.properties &&
|
|
154
|
+
propagation_node.targets[0] != Contrast::Utils::ObjectShare::RETURN_KEY
|
|
155
|
+
return true if Contrast::Utils::Assess::TrackingUtil.tracked?(target)
|
|
156
|
+
return false unless preshift
|
|
157
|
+
|
|
158
|
+
propagation_node.sources.each do |source|
|
|
159
|
+
case source
|
|
160
|
+
when Contrast::Utils::ObjectShare::OBJECT_KEY
|
|
161
|
+
return true if Contrast::Utils::Assess::TrackingUtil.tracked?(preshift.object)
|
|
162
|
+
else # has to be P, there's no ret source type (yet? ever?)
|
|
163
|
+
return true if preshift.args && Contrast::Utils::Assess::TrackingUtil.tracked?(preshift.args[source])
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
false
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# If this patcher has tags, apply them to the entire target
|
|
170
|
+
def apply_tags propagation_node, target
|
|
171
|
+
return unless propagation_node.tags
|
|
172
|
+
|
|
173
|
+
length = Contrast::Utils::StringUtils.ret_length(target)
|
|
174
|
+
propagation_node.tags.each do |tag|
|
|
175
|
+
span = Contrast::Agent::Assess::AdjustedSpan.new(0, length)
|
|
176
|
+
target.cs__properties.add_tag(tag, span)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# If this patcher has tags, remove them from the entire target
|
|
181
|
+
def apply_untags propagation_node, target
|
|
182
|
+
return unless propagation_node.untags
|
|
183
|
+
|
|
184
|
+
propagation_node.untags.each do |tag|
|
|
185
|
+
target.cs__properties.delete_tags(tag)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
private
|
|
190
|
+
|
|
191
|
+
def handle_hash_propagation propagation_node, preshift, target, object, ret, invoked, args, block
|
|
192
|
+
invoked += 2
|
|
193
|
+
target.each_pair do |key, value|
|
|
194
|
+
apply_propagator(propagation_node, preshift, key, object, ret, invoked, args, block)
|
|
195
|
+
apply_propagator(propagation_node, preshift, value, object, ret, invoked, args, block)
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def handle_enumerable_propagation propagation_node, preshift, target, object, ret, invoked, args, block
|
|
200
|
+
invoked += 2
|
|
201
|
+
target.each do |value|
|
|
202
|
+
next if target == value # Some Enumerable#each are overriden to return self the first time which leads to infinite propagation
|
|
203
|
+
|
|
204
|
+
apply_propagator(propagation_node, preshift, value, object, ret, invoked, args, block)
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def handle_cs_properties_propagation propagation_node, preshift, target, object, ret, invoked, args, _block
|
|
209
|
+
invoked += 1
|
|
210
|
+
return unless can_propagate?(propagation_node, preshift, target)
|
|
211
|
+
|
|
212
|
+
# propagate all the tags from the sources to the target
|
|
213
|
+
propagation_class = PROPAGATION_ACTIONS.fetch(propagation_node.action, nil)
|
|
214
|
+
unless propagation_class
|
|
215
|
+
logger.warn(
|
|
216
|
+
nil,
|
|
217
|
+
"Unknown action type #{ propagation_node.action }. Unable to "\
|
|
218
|
+
"propagate for #{ propagation_node.id }.")
|
|
219
|
+
return ret
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
restore_frozen_state = false
|
|
223
|
+
if target.cs__frozen?
|
|
224
|
+
return ret unless propagation_node.targets[0] == Contrast::Utils::ObjectShare::RETURN_KEY
|
|
225
|
+
|
|
226
|
+
restore_frozen_state = true
|
|
227
|
+
ret = Contrast::Utils::FreezeUtil.unfreeze_dup(target)
|
|
228
|
+
target = ret
|
|
229
|
+
end
|
|
230
|
+
propagation_class.propagate(propagation_node, preshift, target)
|
|
231
|
+
|
|
232
|
+
# Once we've propagated, attempt to tag the target if there is a tag(s) to be applied
|
|
233
|
+
apply_tags(propagation_node, target)
|
|
234
|
+
|
|
235
|
+
# Even though we skipped propagating tags from the source if they
|
|
236
|
+
# were included in untags, the target may have already had some on
|
|
237
|
+
# it. Let's go ahead and remove them.
|
|
238
|
+
# In this order, untags takes precedent over tags; but we control
|
|
239
|
+
# both and there should never be a propagator that has a tag in
|
|
240
|
+
# its untag.
|
|
241
|
+
apply_untags(propagation_node, target)
|
|
242
|
+
|
|
243
|
+
target.cs__properties.add_properties(propagation_node.properties)
|
|
244
|
+
|
|
245
|
+
target.cs__properties.build_event(propagation_node, target, object, ret, args, invoked)
|
|
246
|
+
|
|
247
|
+
logger.debug(
|
|
248
|
+
nil,
|
|
249
|
+
"Propagator #{ propagation_node.id } detected: propagated to "\
|
|
250
|
+
"#{ target.__id__ }")
|
|
251
|
+
|
|
252
|
+
ret.cs__freeze if restore_frozen_state
|
|
253
|
+
ret
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
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_node'
|
|
5
|
+
module Contrast
|
|
6
|
+
module Agent
|
|
7
|
+
module Assess
|
|
8
|
+
module Policy
|
|
9
|
+
# This class functions to translate our policy.json into an actionable
|
|
10
|
+
# Ruby object, allowing for dynamic patching over hardcoded patching,
|
|
11
|
+
# specifically for those methods which result in the transformation of
|
|
12
|
+
# untrusted data (indicate points in the application where user
|
|
13
|
+
# controlled input is modified).
|
|
14
|
+
class PropagationNode < PolicyNode
|
|
15
|
+
JSON_ACTION = 'action'
|
|
16
|
+
JSON_UNTAGS = 'untags'
|
|
17
|
+
JSON_PATCH_CLASS = 'patch_class'
|
|
18
|
+
JSON_PATCH_METHOD = 'patch_method'
|
|
19
|
+
|
|
20
|
+
attr_accessor :action, :untags, :patch_class, :patch_method
|
|
21
|
+
|
|
22
|
+
# Most things here carry over from PolicyNode.
|
|
23
|
+
# A couple things are new / have new rules
|
|
24
|
+
#
|
|
25
|
+
# Source - from where the tainted data flows, cannot be nil
|
|
26
|
+
# Target - to where the tainted data flows, cannot be nil
|
|
27
|
+
# Action - how the tainted data flows from source to target, should not be nil
|
|
28
|
+
# Tags - array of tags to apply to the target, can be nil if no tags are added
|
|
29
|
+
# Untags - array of tags to remove from the target, can be nil if not tags are removed
|
|
30
|
+
# id, class_name, instance_method, method_name, source, target, action, tags = nil, untags = nil
|
|
31
|
+
def initialize propagation_hash = {}
|
|
32
|
+
super(propagation_hash)
|
|
33
|
+
@action = propagation_hash[JSON_ACTION]
|
|
34
|
+
@untags = Set.new(propagation_hash[JSON_UNTAGS])
|
|
35
|
+
@patch_class = propagation_hash[JSON_PATCH_CLASS]
|
|
36
|
+
@patch_method = propagation_hash[JSON_PATCH_METHOD]
|
|
37
|
+
@patch_method = @patch_method.to_sym if @patch_method
|
|
38
|
+
validate
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
TAGGER = 'Tagger'
|
|
42
|
+
PROPAGATOR = 'Propagator'
|
|
43
|
+
|
|
44
|
+
def node_class
|
|
45
|
+
@_node_class ||= tagger? ? TAGGER : PROPAGATOR
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Unlike the other agents, we don't have separate tag & propagation
|
|
49
|
+
# events. To make TS happy, we need to have different types though.
|
|
50
|
+
# Pretty straight forward: if there's a tag, this is a tagger
|
|
51
|
+
def node_type
|
|
52
|
+
tagger? ? :TYPE_TAG : :TYPE_PROPAGATION
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Standard validation + TS trace version two rules:
|
|
56
|
+
# Must have source, target, and action
|
|
57
|
+
def validate
|
|
58
|
+
super
|
|
59
|
+
raise(ArgumentError, "Propagator #{ id } did not have a proper action. Unable to create.") unless action
|
|
60
|
+
|
|
61
|
+
if @action == 'CUSTOM'
|
|
62
|
+
raise(ArgumentError, "Propagator #{ id } did not have a proper patch_class. Unable to create.") unless patch_class
|
|
63
|
+
raise(ArgumentError, "Propagator #{ id } did not have a proper patch_method. Unable to create.") unless patch_method.is_a?(Symbol)
|
|
64
|
+
else
|
|
65
|
+
raise(ArgumentError, "Propagator #{ id } did not have a proper target. Unable to create.") unless targets&.any?
|
|
66
|
+
raise(ArgumentError, "Propagator #{ id } did not have a proper source. Unable to create.") unless sources&.any?
|
|
67
|
+
end
|
|
68
|
+
validate_untags
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def validate_untags
|
|
72
|
+
return unless untags
|
|
73
|
+
|
|
74
|
+
untags.each do |tag|
|
|
75
|
+
raise(ArgumentError, "#{ node_type } #{ id } did not have a valid untag. #{ tag } is not a known value.") unless VALID_TAGS.include?(tag)
|
|
76
|
+
raise(ArgumentError, "#{ node_type } #{ id } had the same tag and untag, #{ tag }.") if tags&.include?(tag)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def needs_object?
|
|
81
|
+
@_needs_object ||= begin
|
|
82
|
+
if action == Contrast::Agent::Assess::Policy::PropagationMethod::CUSTOM_ACTION
|
|
83
|
+
true
|
|
84
|
+
elsif action == Contrast::Agent::Assess::Policy::PropagationMethod::DB_WRITE_ACTION
|
|
85
|
+
true
|
|
86
|
+
elsif sources.any? { |source| source == Contrast::Utils::ObjectShare::OBJECT_KEY }
|
|
87
|
+
true
|
|
88
|
+
elsif targets.any? { |target| target == Contrast::Utils::ObjectShare::OBJECT_KEY }
|
|
89
|
+
true
|
|
90
|
+
else
|
|
91
|
+
false
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def needs_args?
|
|
97
|
+
@_needs_args ||= begin
|
|
98
|
+
if action == Contrast::Agent::Assess::Policy::PropagationMethod::CUSTOM_ACTION
|
|
99
|
+
true
|
|
100
|
+
elsif action == Contrast::Agent::Assess::Policy::PropagationMethod::DB_WRITE_ACTION
|
|
101
|
+
true
|
|
102
|
+
elsif sources.any? { |source| source.is_a?(Integer) || source.is_a?(Symbol) }
|
|
103
|
+
true
|
|
104
|
+
elsif targets.any? { |target| target.is_a?(Integer) || target.is_a?(Symbol) }
|
|
105
|
+
true
|
|
106
|
+
else
|
|
107
|
+
false
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# This is a tagger if it has a tag or an untag.
|
|
113
|
+
# It indicates this method is more than just a transformation,
|
|
114
|
+
# it is an interesting security event that has a meaningful
|
|
115
|
+
# change.
|
|
116
|
+
def tagger?
|
|
117
|
+
@_tagger ||= begin
|
|
118
|
+
has_tags = tags&.any?
|
|
119
|
+
has_untags = untags&.any?
|
|
120
|
+
has_tags || has_untags
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|