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,15 @@
|
|
|
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/core_extensions/eval_trigger'
|
|
5
|
+
cs__scoped_require 'contrast/agent/patching/policy/patcher'
|
|
6
|
+
|
|
7
|
+
# Our patch into the BasicObject class, allowing us to track calls to the eval
|
|
8
|
+
# method
|
|
9
|
+
class BasicObject
|
|
10
|
+
class << self
|
|
11
|
+
include Contrast::CoreExtensions::Assess::EvalTrigger
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
cs__scoped_require 'cs__assess_basic_object/cs__assess_basic_object'
|
|
@@ -0,0 +1,42 @@
|
|
|
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
|
+
# This module is used to track propagation through ERB template rendering
|
|
7
|
+
module ERBPropagator
|
|
8
|
+
class << self
|
|
9
|
+
include Contrast::Components::Interface
|
|
10
|
+
access_component :logging
|
|
11
|
+
|
|
12
|
+
def result_tagger patcher, preshift, ret, _block
|
|
13
|
+
return unless preshift.args.length >= 1
|
|
14
|
+
|
|
15
|
+
logger.debug('ERBPropagator - running propagation')
|
|
16
|
+
used_binding = preshift.args[0]
|
|
17
|
+
binding_variable_set = used_binding.local_variables
|
|
18
|
+
|
|
19
|
+
erb_pre_result = preshift.object.src
|
|
20
|
+
binding_variable_set.each do |bound_var_symbol|
|
|
21
|
+
bound_variable_value = used_binding.local_variable_get(bound_var_symbol)
|
|
22
|
+
next unless bound_variable_value.cs__respond_to?(:cs__tracked?) && bound_variable_value.cs__tracked?
|
|
23
|
+
next unless erb_pre_result.include?(bound_var_symbol.to_s)
|
|
24
|
+
|
|
25
|
+
start_index = ret.index(bound_variable_value)
|
|
26
|
+
next if start_index.nil?
|
|
27
|
+
|
|
28
|
+
logger.debug('ERBPropagator - found bound_variable in erb template result')
|
|
29
|
+
ret.cs__copy_from(bound_variable_value, start_index)
|
|
30
|
+
end
|
|
31
|
+
ret.cs__properties.build_event(
|
|
32
|
+
patcher,
|
|
33
|
+
ret,
|
|
34
|
+
preshift.object,
|
|
35
|
+
ret,
|
|
36
|
+
preshift.args,
|
|
37
|
+
1)
|
|
38
|
+
logger.debug('ERBPropgator - Finished erb result propagation')
|
|
39
|
+
ret
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
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 CoreExtensions
|
|
8
|
+
module Assess
|
|
9
|
+
# This Module allows us to track calls to the Kernel#exec method, which
|
|
10
|
+
# violates the design of most methods we track in that we have to apply
|
|
11
|
+
# the trigger at the start in order to account for the process hand off.
|
|
12
|
+
module ExecTrigger
|
|
13
|
+
include Contrast::Components::Interface
|
|
14
|
+
access_component :contrast_service
|
|
15
|
+
def apply_trigger source
|
|
16
|
+
current_context = Contrast::Agent::REQUEST_TRACKER.current
|
|
17
|
+
return unless current_context
|
|
18
|
+
|
|
19
|
+
# Since we know this is the source of the trigger, we can do some
|
|
20
|
+
# optimization here and return when it is not tracked
|
|
21
|
+
return unless Contrast::Utils::Assess::TrackingUtil.tracked?(source)
|
|
22
|
+
|
|
23
|
+
# source might not be all the args passed in, but it is the one we care
|
|
24
|
+
# about. we could pass in all the args in the last param here if it
|
|
25
|
+
# becomes an issue in rendering on TS
|
|
26
|
+
Contrast::Agent::Assess::Policy::TriggerMethod.build_finding(
|
|
27
|
+
current_context,
|
|
28
|
+
trigger_node,
|
|
29
|
+
source,
|
|
30
|
+
self,
|
|
31
|
+
'',
|
|
32
|
+
1,
|
|
33
|
+
source)
|
|
34
|
+
# Exec replaces the current process, if we occur in a forked process our appendage of this finding will not make it to TS
|
|
35
|
+
CONTRAST_SERVICE.send_message(current_context.activity)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def trigger_node
|
|
41
|
+
@_trigger_node ||= begin
|
|
42
|
+
Contrast::Agent::Assess::Policy::Policy.instance.find_node('cmd-injection', 'Kernel', :exec, false)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
cs__scoped_require 'contrast/components/interface'
|
|
5
|
+
|
|
6
|
+
cs__scoped_require 'fiber'
|
|
7
|
+
|
|
8
|
+
# In order to instrument some difficult methods like String#gsub, as it
|
|
9
|
+
# returns an enumerator, we need to instrument methods on Fiber.
|
|
10
|
+
# Specifically, we instrument 'rb_fiber_yield' and 'rb_fiber_new' in
|
|
11
|
+
# order to track what happens within Enumerator#next.
|
|
12
|
+
# TODO: RUBY-531 move these out of Fiber class
|
|
13
|
+
class Fiber
|
|
14
|
+
include Contrast::CoreExtensions::Assess::AssessExtension
|
|
15
|
+
include Contrast::Components::Interface
|
|
16
|
+
|
|
17
|
+
access_component :analysis, :scope
|
|
18
|
+
|
|
19
|
+
FIBER_NEW_NODE_HASH = {
|
|
20
|
+
'class_name' => 'Fiber',
|
|
21
|
+
'instance_method' => true,
|
|
22
|
+
'method_visibility' => 'public',
|
|
23
|
+
'method_name' => 'c_new', # TODO: Why do we patch new here and not initalize? Historically, new has been problematic.
|
|
24
|
+
'action' => 'CUSTOM',
|
|
25
|
+
'source' => 'O',
|
|
26
|
+
'target' => 'R',
|
|
27
|
+
'patch_class' => 'NOOP',
|
|
28
|
+
'patch_method' => 'track_rb_fiber_new'
|
|
29
|
+
}.cs__freeze
|
|
30
|
+
FIBER_NEW_NODE = Contrast::Agent::Assess::Policy::PropagationNode.new(FIBER_NEW_NODE_HASH)
|
|
31
|
+
private_constant :FIBER_NEW_NODE_HASH
|
|
32
|
+
private_constant :FIBER_NEW_NODE
|
|
33
|
+
|
|
34
|
+
FIBER_YIELD_NODE_HASH = {
|
|
35
|
+
'class_name' => 'Fiber',
|
|
36
|
+
'instance_method' => true,
|
|
37
|
+
'method_visibility' => 'public',
|
|
38
|
+
'method_name' => 'c_yield',
|
|
39
|
+
'action' => 'CUSTOM',
|
|
40
|
+
'source' => 'O',
|
|
41
|
+
'target' => 'R',
|
|
42
|
+
'patch_class' => 'NOOP',
|
|
43
|
+
'patch_method' => 'track_rb_fiber_yield'
|
|
44
|
+
}.cs__freeze
|
|
45
|
+
FIBER_YIELD_NODE = Contrast::Agent::Assess::Policy::PropagationNode.new(FIBER_YIELD_NODE_HASH)
|
|
46
|
+
private_constant :FIBER_YIELD_NODE_HASH
|
|
47
|
+
private_constant :FIBER_YIELD_NODE
|
|
48
|
+
|
|
49
|
+
class << self
|
|
50
|
+
def track_rb_fiber_yield fiber, _method, results
|
|
51
|
+
# results will be nil if StopIteration was raised,
|
|
52
|
+
# otherwise an Array of the yielded arguments
|
|
53
|
+
return if results.nil?
|
|
54
|
+
|
|
55
|
+
return unless ASSESS.enabled?
|
|
56
|
+
|
|
57
|
+
with_contrast_scope do
|
|
58
|
+
results.each do |result|
|
|
59
|
+
next unless Contrast::Utils::DuckUtils.quacks_like_cs_patched?(result)
|
|
60
|
+
next if result.cs__frozen?
|
|
61
|
+
|
|
62
|
+
cs__splat_tags(result, fiber)
|
|
63
|
+
result.cs__properties.build_event(
|
|
64
|
+
FIBER_YIELD_NODE,
|
|
65
|
+
result,
|
|
66
|
+
fiber,
|
|
67
|
+
result,
|
|
68
|
+
[])
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def track_rb_fiber_new fiber, _enum, _enum_method, underlying, _underlying_method
|
|
74
|
+
return unless Contrast::Utils::DuckUtils.quacks_like_cs_patched?(underlying)
|
|
75
|
+
return unless underlying.is_a?(String) && !underlying.empty?
|
|
76
|
+
|
|
77
|
+
return unless ASSESS.enabled?
|
|
78
|
+
|
|
79
|
+
with_contrast_scope do
|
|
80
|
+
cs__splat_tags(fiber, underlying)
|
|
81
|
+
fiber.cs__properties.build_event(
|
|
82
|
+
FIBER_NEW_NODE,
|
|
83
|
+
fiber,
|
|
84
|
+
underlying,
|
|
85
|
+
fiber,
|
|
86
|
+
[])
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def instrument_fiber_track
|
|
91
|
+
@_instrument_fiber_variables ||= begin
|
|
92
|
+
cs__scoped_require 'cs__assess_fiber_track/cs__assess_fiber_track'
|
|
93
|
+
true
|
|
94
|
+
end
|
|
95
|
+
rescue StandardError => e
|
|
96
|
+
logger.error(e, 'Error loading fiber track patch')
|
|
97
|
+
false
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Some propagation occurred, but we're not sure what the
|
|
101
|
+
# exact transformation was. To be safe, we just explode
|
|
102
|
+
# all the tags from the source to the return.
|
|
103
|
+
#
|
|
104
|
+
# If the return already had that tag, the existing tag
|
|
105
|
+
# range is recycled to save us an object.
|
|
106
|
+
def cs__splat_tags ret, source = self
|
|
107
|
+
source.cs__properties.tag_keys.each do |key|
|
|
108
|
+
length = Contrast::Utils::StringUtils.ret_length(ret)
|
|
109
|
+
existing = ret.cs__properties.fetch_tag(key)
|
|
110
|
+
# if the tag already exists, drop all but the first range
|
|
111
|
+
# then change that range to cover the entire return
|
|
112
|
+
if existing&.any?
|
|
113
|
+
existing.drop(existing.length - 1)
|
|
114
|
+
range = existing[0]
|
|
115
|
+
range.repurpose(0, length)
|
|
116
|
+
else
|
|
117
|
+
span = Contrast::Agent::Assess::AdjustedSpan.new(0, length)
|
|
118
|
+
ret.cs__properties.add_tag(key, span)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
Fiber.instrument_fiber_track
|
|
@@ -0,0 +1,22 @@
|
|
|
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 provides us with a way to invoke Hash propagation for those
|
|
5
|
+
# methods which are too complex to fit into one of the standard
|
|
6
|
+
# Contrast::Agent::Assess::Policy::Propagator molds.
|
|
7
|
+
class Hash
|
|
8
|
+
def self.cs__duplicate_and_freeze object
|
|
9
|
+
return object unless object.is_a?(String) && !object.cs__frozen?
|
|
10
|
+
return object unless object.cs__tracked?
|
|
11
|
+
|
|
12
|
+
object.dup.cs__freeze
|
|
13
|
+
rescue StandardError
|
|
14
|
+
logger.error("Unable to track dataflow through array for #{ object }")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def cs__bracket_set *args
|
|
18
|
+
Hash.cs__duplicate_and_freeze(args[0])
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
cs__scoped_require 'cs__assess_hash/cs__assess_hash'
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
cs__scoped_require 'contrast/components/interface'
|
|
5
|
+
cs__scoped_require 'contrast/core_extensions/assess/exec_trigger'
|
|
6
|
+
|
|
7
|
+
# This module provides us with a way to invoke Kernel propagation for those
|
|
8
|
+
# methods which are too complex to fit into one of the standard
|
|
9
|
+
# Contrast::Agent::Assess::Policy::Propagator molds without cluttering up the
|
|
10
|
+
# Kernel Module or exposing our methods there.
|
|
11
|
+
module KernelPropagator
|
|
12
|
+
class << self
|
|
13
|
+
include Contrast::Components::Interface
|
|
14
|
+
include Contrast::CoreExtensions::Assess::ExecTrigger
|
|
15
|
+
|
|
16
|
+
access_component :logging
|
|
17
|
+
|
|
18
|
+
# We're 'tracking' sprintf now, meaning if anything is tracked on the way
|
|
19
|
+
# in, the entire result will be tracked out. We're going to take this
|
|
20
|
+
# approach for now b/c it's fast and easy. I don't super love it, and by
|
|
21
|
+
# that I mean I hate it.
|
|
22
|
+
#
|
|
23
|
+
# To actually track this, we'd have to find the index of the new things
|
|
24
|
+
# being added, then remove the tags at the range of the format marker,
|
|
25
|
+
# which is some arbitrary length thing, and add the new tags from the
|
|
26
|
+
# inserted string, shifted down by the length of the aforementioned
|
|
27
|
+
# marker.
|
|
28
|
+
#
|
|
29
|
+
# marker is in the format %[flags][width][.precision]type, type being a
|
|
30
|
+
# single character. We could regexp this with %.+[bBdiouxXeEfgGaAcps%]
|
|
31
|
+
#
|
|
32
|
+
# also, b/c Ruby hates us, there are things called absolute markers,
|
|
33
|
+
# (digit)$, that go in the flags section. These cannot be mixed w/ the
|
|
34
|
+
# order assumed type
|
|
35
|
+
#
|
|
36
|
+
# oh, and there's also %<name>type and %{name}... b/c of course there is
|
|
37
|
+
# -HM
|
|
38
|
+
def sprintf_tagger patcher, preshift, ret, _block
|
|
39
|
+
format_string = preshift.args[0]
|
|
40
|
+
args = preshift.args[1]
|
|
41
|
+
|
|
42
|
+
track_sprintf(ret, format_string, args)
|
|
43
|
+
|
|
44
|
+
ret.cs__properties.build_event(
|
|
45
|
+
patcher,
|
|
46
|
+
ret,
|
|
47
|
+
preshift.object,
|
|
48
|
+
ret,
|
|
49
|
+
preshift.args,
|
|
50
|
+
1)
|
|
51
|
+
ret
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def track_sprintf result, format_string, args
|
|
55
|
+
tracked_inputs = []
|
|
56
|
+
tracked_inputs << format_string if format_string.cs__tracked?
|
|
57
|
+
if args.is_a?(String)
|
|
58
|
+
tracked_inputs << args if args.cs__tracked?
|
|
59
|
+
elsif args.is_a?(Hash)
|
|
60
|
+
args.each_value do |value|
|
|
61
|
+
next unless Contrast::Utils::DuckUtils.quacks_to?(
|
|
62
|
+
value,
|
|
63
|
+
:cs__tracked?)
|
|
64
|
+
next unless value.cs__tracked?
|
|
65
|
+
|
|
66
|
+
tracked_inputs << value
|
|
67
|
+
end
|
|
68
|
+
elsif args.is_a?(Array)
|
|
69
|
+
args.each do |value|
|
|
70
|
+
next unless Contrast::Utils::DuckUtils.quacks_to?(value, :cs__tracked?)
|
|
71
|
+
next unless value.cs__tracked?
|
|
72
|
+
|
|
73
|
+
tracked_inputs << value
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
return result if tracked_inputs.empty?
|
|
77
|
+
|
|
78
|
+
tracked_inputs.each do |input|
|
|
79
|
+
input.cs__properties.events.each do |event|
|
|
80
|
+
result.cs__properties.events << event
|
|
81
|
+
end
|
|
82
|
+
input.cs__splat_tags(result)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
result
|
|
86
|
+
rescue StandardError => e
|
|
87
|
+
logger.error(
|
|
88
|
+
e,
|
|
89
|
+
'Unable to track dataflow through sprintf')
|
|
90
|
+
result
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
cs__scoped_require 'cs__assess_kernel/cs__assess_kernel'
|
|
@@ -0,0 +1,14 @@
|
|
|
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/core_extensions/eval_trigger'
|
|
5
|
+
|
|
6
|
+
# Our patch into the Module class, allowing us to track calls to the eval
|
|
7
|
+
# method
|
|
8
|
+
class Module
|
|
9
|
+
class << self
|
|
10
|
+
include Contrast::CoreExtensions::Assess::EvalTrigger
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
cs__scoped_require 'cs__assess_module/cs__assess_module'
|
|
@@ -0,0 +1,206 @@
|
|
|
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
|
+
# Monkeypatch Ruby Regexp with Contrast Security tagging support
|
|
7
|
+
class Regexp
|
|
8
|
+
include Contrast::Components::Interface
|
|
9
|
+
include Contrast::CoreExtensions::Assess::AssessExtension
|
|
10
|
+
|
|
11
|
+
access_component :analysis, :logging, :scope
|
|
12
|
+
|
|
13
|
+
def cs__regexp_tagger info_hash
|
|
14
|
+
return unless ASSESS.enabled?
|
|
15
|
+
|
|
16
|
+
# Because we have a special case for this propagation,
|
|
17
|
+
# it falls out of regular scoping. As such, any patch to the `=~` method
|
|
18
|
+
# that goes through normal channels, like that for the redos rule,
|
|
19
|
+
# will force this to be in a scope of 1 (instead of the normal 0).
|
|
20
|
+
# As such, a scope of 1 here indicates that,
|
|
21
|
+
# so we know that we're in the top level call for this method.
|
|
22
|
+
# normal patch [-alias-]> special case patch [-alias-]> original method
|
|
23
|
+
# TODO: RUBY-686
|
|
24
|
+
return if scope_for_current_ec.instance_variable_get(:@contrast_scope) > 1
|
|
25
|
+
|
|
26
|
+
with_contrast_scope do
|
|
27
|
+
result = info_hash[:result]
|
|
28
|
+
return unless result
|
|
29
|
+
|
|
30
|
+
string = info_hash[:string] || nil
|
|
31
|
+
return unless string
|
|
32
|
+
|
|
33
|
+
regexp = info_hash[:regexp]
|
|
34
|
+
return unless (Contrast::Utils::DuckUtils.quacks_to?(string, :cs__tracked?) && string.cs__tracked?) ||
|
|
35
|
+
(Contrast::Utils::DuckUtils.quacks_to?(regexp, :cs__tracked?) && regexp.cs__tracked?)
|
|
36
|
+
|
|
37
|
+
Regexp.cs__splat_tags(info_hash[:back_ref], string)
|
|
38
|
+
Regexp.cs__build_event(ARRAY_NODE, info_hash[:back_ref], result, [string])
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
REGEXP_EQUAL_SQUIGGLE_HASH = {
|
|
43
|
+
'id' => 'regexp_100',
|
|
44
|
+
'class_name' => 'Regexp',
|
|
45
|
+
'instance_method' => true,
|
|
46
|
+
'method_visibility' => 'public',
|
|
47
|
+
'method_name' => '=~',
|
|
48
|
+
'source' => 'P0',
|
|
49
|
+
'target' => 'R',
|
|
50
|
+
'action' => 'KEEP'
|
|
51
|
+
}.cs__freeze
|
|
52
|
+
ARRAY_NODE = Contrast::Agent::Assess::Policy::PropagationNode.new(REGEXP_EQUAL_SQUIGGLE_HASH)
|
|
53
|
+
private_constant :REGEXP_EQUAL_SQUIGGLE_HASH
|
|
54
|
+
private_constant :ARRAY_NODE
|
|
55
|
+
|
|
56
|
+
REGEXP_MATCH_HASH = {
|
|
57
|
+
'id' => 'regexp_101',
|
|
58
|
+
'class_name' => 'Regexp',
|
|
59
|
+
'instance_method' => true,
|
|
60
|
+
'method_visibility' => 'public',
|
|
61
|
+
'method_name' => 'match',
|
|
62
|
+
'source' => 'P0',
|
|
63
|
+
'target' => 'R',
|
|
64
|
+
'action' => 'SPLAT'
|
|
65
|
+
}.cs__freeze
|
|
66
|
+
MATCH_NODE = Contrast::Agent::Assess::Policy::PropagationNode.new(REGEXP_MATCH_HASH)
|
|
67
|
+
private_constant :REGEXP_MATCH_HASH
|
|
68
|
+
private_constant :MATCH_NODE
|
|
69
|
+
|
|
70
|
+
POST_HASH = {
|
|
71
|
+
'class_name' => 'MatchData',
|
|
72
|
+
'instance_method' => true,
|
|
73
|
+
'method_visibility' => 'public',
|
|
74
|
+
'method_name' => 'post_match',
|
|
75
|
+
'source' => 'O',
|
|
76
|
+
'target' => 'R',
|
|
77
|
+
'action' => 'REMOVE'
|
|
78
|
+
}.cs__freeze
|
|
79
|
+
POST_WEAVER = Contrast::Agent::Assess::Policy::PropagationNode.new(POST_HASH)
|
|
80
|
+
private_constant :POST_HASH
|
|
81
|
+
private_constant :POST_WEAVER
|
|
82
|
+
|
|
83
|
+
PRE_HASH = {
|
|
84
|
+
'class_name' => 'MatchData',
|
|
85
|
+
'instance_method' => true,
|
|
86
|
+
'method_visibility' => 'public',
|
|
87
|
+
'method_name' => 'pre_match',
|
|
88
|
+
'source' => 'O',
|
|
89
|
+
'target' => 'R',
|
|
90
|
+
'action' => 'SPLAT'
|
|
91
|
+
}.cs__freeze
|
|
92
|
+
PRE_WEAVER = Contrast::Agent::Assess::Policy::PropagationNode.new(PRE_HASH)
|
|
93
|
+
private_constant :PRE_HASH
|
|
94
|
+
private_constant :PRE_WEAVER
|
|
95
|
+
|
|
96
|
+
LAST_PAREN_HASH = {
|
|
97
|
+
'class_name' => 'MatchData',
|
|
98
|
+
'instance_method' => true,
|
|
99
|
+
'method_visibility' => 'public',
|
|
100
|
+
'method_name' => 'last_paren',
|
|
101
|
+
'source' => 'O',
|
|
102
|
+
'target' => 'R',
|
|
103
|
+
'action' => 'SPLAT'
|
|
104
|
+
}.cs__freeze
|
|
105
|
+
LAST_PAREN_WEAVER = Contrast::Agent::Assess::Policy::PropagationNode.new(LAST_PAREN_HASH)
|
|
106
|
+
private_constant :LAST_PAREN_HASH
|
|
107
|
+
private_constant :LAST_PAREN_WEAVER
|
|
108
|
+
|
|
109
|
+
NTH_HASH = {
|
|
110
|
+
'class_name' => 'MatchData',
|
|
111
|
+
'instance_method' => true,
|
|
112
|
+
'method_visibility' => 'public',
|
|
113
|
+
'method_name' => 'nth_match',
|
|
114
|
+
'source' => 'O',
|
|
115
|
+
'target' => 'R',
|
|
116
|
+
'action' => 'SPLAT'
|
|
117
|
+
}.cs__freeze
|
|
118
|
+
NTH_WEAVER = Contrast::Agent::Assess::Policy::PropagationNode.new(NTH_HASH)
|
|
119
|
+
private_constant :NTH_HASH
|
|
120
|
+
private_constant :NTH_WEAVER
|
|
121
|
+
|
|
122
|
+
class << self
|
|
123
|
+
def track_rb_pre_match backref, target
|
|
124
|
+
track_rb_c(PRE_WEAVER, backref, target)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def track_rb_post_match backref, target
|
|
128
|
+
track_rb_c(POST_WEAVER, backref, target)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def track_rb_reg_match_last backref, target
|
|
132
|
+
track_rb_c(LAST_PAREN_WEAVER, backref, target)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def track_rb_n_match backref, target
|
|
136
|
+
track_rb_c(NTH_WEAVER, backref, target)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Some propagation occurred, but we're not sure what the
|
|
140
|
+
# exact transformation was. To be safe, we just explode
|
|
141
|
+
# all the tags from the source to the return.
|
|
142
|
+
#
|
|
143
|
+
# If the return already had that tag, the existing tag
|
|
144
|
+
# range is recycled to save us an object.
|
|
145
|
+
def cs__splat_tags ret, source = self
|
|
146
|
+
source.cs__properties.tag_keys.each do |key|
|
|
147
|
+
length = Contrast::Utils::StringUtils.ret_length(ret)
|
|
148
|
+
existing = ret.cs__properties.fetch_tag(key)
|
|
149
|
+
# if the tag already exists, drop all but the first range
|
|
150
|
+
# then change that range to cover the entire return
|
|
151
|
+
if existing&.any?
|
|
152
|
+
existing.drop(existing.length - 1)
|
|
153
|
+
range = existing[0]
|
|
154
|
+
range.repurpose(0, length)
|
|
155
|
+
else
|
|
156
|
+
span = Contrast::Agent::Assess::AdjustedSpan.new(0, length)
|
|
157
|
+
ret.cs__properties.add_tag(key, span)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def cs__build_event node, target, ret, args
|
|
163
|
+
return unless Contrast::Utils::DuckUtils.quacks_to?(target, :cs__tracked?)
|
|
164
|
+
return unless target.cs__tracked?
|
|
165
|
+
|
|
166
|
+
target.cs__properties.build_event(
|
|
167
|
+
node,
|
|
168
|
+
target,
|
|
169
|
+
self,
|
|
170
|
+
ret,
|
|
171
|
+
args)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def instrument_regexp_track
|
|
175
|
+
@_instrument_regexp_variables ||= begin
|
|
176
|
+
cs__scoped_require 'cs__assess_regexp_track/cs__assess_regexp_track'
|
|
177
|
+
true
|
|
178
|
+
end
|
|
179
|
+
rescue StandardError => e
|
|
180
|
+
logger.error(e, 'Error loading regexp track patch')
|
|
181
|
+
false
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
private
|
|
185
|
+
|
|
186
|
+
def track_rb_c weaver, backref, target
|
|
187
|
+
return target unless ASSESS.enabled?
|
|
188
|
+
return target unless backref&.respond_to?(:cs__properties)
|
|
189
|
+
return target unless target.is_a?(String) && !target.empty?
|
|
190
|
+
|
|
191
|
+
with_contrast_scope do
|
|
192
|
+
cs__splat_tags(target, backref)
|
|
193
|
+
target.cs__properties.build_event(
|
|
194
|
+
weaver,
|
|
195
|
+
target,
|
|
196
|
+
self,
|
|
197
|
+
target,
|
|
198
|
+
[])
|
|
199
|
+
target
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
cs__scoped_require 'cs__assess_regexp/cs__assess_regexp'
|
|
206
|
+
Regexp.instrument_regexp_track
|