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,81 @@
|
|
|
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 Protect
|
|
9
|
+
# This Module is how we apply the NoSQL Injection rule. It is called from
|
|
10
|
+
# our patches of the targeted methods in which the execution of String
|
|
11
|
+
# based NoSQL queries occur. It is responsible for deciding if the
|
|
12
|
+
# infilter methods of the rule should be invoked.
|
|
13
|
+
module AppliesNoSqliRule
|
|
14
|
+
DATABASE_MONGO = 'MongoDB'
|
|
15
|
+
ACTION_DISPATCH = 'dispatch'
|
|
16
|
+
ACTION_READ = 'read'
|
|
17
|
+
ACTION_WRITE = 'write'
|
|
18
|
+
ACTION_PROCESS = 'process'
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
include Contrast::Components::Interface
|
|
22
|
+
access_component :logging, :analysis
|
|
23
|
+
|
|
24
|
+
def cs__patched_apply_nosql_rule method, _exception, properties, _object, args
|
|
25
|
+
return unless valid_input?(args)
|
|
26
|
+
return if cs__skip_analysis?
|
|
27
|
+
|
|
28
|
+
database = properties['database']
|
|
29
|
+
operations = args[0]
|
|
30
|
+
context = Contrast::Agent::REQUEST_TRACKER.current
|
|
31
|
+
if operations.is_a?(Array)
|
|
32
|
+
operations.each do |m|
|
|
33
|
+
handle_operation(context, database, method, m)
|
|
34
|
+
end
|
|
35
|
+
else
|
|
36
|
+
handle_operation(context, database, method, operations)
|
|
37
|
+
end
|
|
38
|
+
rescue Contrast::SecurityException => e
|
|
39
|
+
raise e
|
|
40
|
+
rescue StandardError => e
|
|
41
|
+
logger.error(e, "Error running NoSQLi rule in #{ properties['database'] }")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def rule
|
|
45
|
+
PROTECT.rule Contrast::Agent::Protect::Rule::NoSqli::NAME
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def valid_input? args
|
|
49
|
+
return false unless args&.any?
|
|
50
|
+
|
|
51
|
+
args[0]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def cs__skip_analysis?
|
|
55
|
+
context = Contrast::Agent::REQUEST_TRACKER.current
|
|
56
|
+
return true unless context&.app_loaded?
|
|
57
|
+
return true unless rule&.enabled?
|
|
58
|
+
|
|
59
|
+
false
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def handle_operation context, database, action, operation
|
|
63
|
+
data = extract_mongo_data(operation)
|
|
64
|
+
return unless data && !data.empty?
|
|
65
|
+
|
|
66
|
+
logger.debug(nil, "applying nosqli rule #{ database }##{ action }")
|
|
67
|
+
rule.infilter(context, database, data)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def extract_mongo_data operation
|
|
71
|
+
if operation.cs__respond_to? :selector
|
|
72
|
+
operation.selector
|
|
73
|
+
elsif operation.cs__respond_to? :documents
|
|
74
|
+
operation.documents
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
cs__scoped_require 'contrast/utils/object_share'
|
|
5
|
+
cs__scoped_require 'contrast/components/interface'
|
|
6
|
+
|
|
7
|
+
module Contrast
|
|
8
|
+
module CoreExtensions
|
|
9
|
+
module Protect
|
|
10
|
+
# This Module is how we apply the Path Traversal rule. It is called from
|
|
11
|
+
# our patches of the targeted methods in which File or IO access occur.
|
|
12
|
+
# It is responsible for deciding if the infilter methods of the rule
|
|
13
|
+
# should be invoked.
|
|
14
|
+
module AppliesPathTraversalRule
|
|
15
|
+
include Contrast::Components::Interface
|
|
16
|
+
|
|
17
|
+
access_component :logging, :analysis
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
def cs__possible_write input
|
|
21
|
+
input.cs__respond_to?(:to_s) &&
|
|
22
|
+
input.to_s.include?(Contrast::Utils::ObjectShare::WRITE_FLAG)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def rule
|
|
26
|
+
PROTECT.rule Contrast::Agent::Protect::Rule::PathTraversal::NAME
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def cs__skip_analysis?
|
|
30
|
+
context = Contrast::Agent::REQUEST_TRACKER.current
|
|
31
|
+
return true unless context&.app_loaded?
|
|
32
|
+
return true unless rule&.enabled?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def cs__patched_apply_path_traversal_rule method, _exception, properties, _object, args
|
|
36
|
+
return unless args&.any?
|
|
37
|
+
|
|
38
|
+
path = args[0]
|
|
39
|
+
return unless path.is_a?(String)
|
|
40
|
+
return if cs__skip_analysis?
|
|
41
|
+
|
|
42
|
+
action = properties['action']
|
|
43
|
+
write_marker = write?(action, *args)
|
|
44
|
+
possible_write = write_marker && cs__possible_write(write_marker)
|
|
45
|
+
cs__patched_path_traversal_rule(path, possible_write, method)
|
|
46
|
+
|
|
47
|
+
# If the action was copy, we need to handle the write half of it.
|
|
48
|
+
# We handled read in line above.
|
|
49
|
+
return unless action == COPY
|
|
50
|
+
return unless args.length > 1
|
|
51
|
+
|
|
52
|
+
dst = args[1]
|
|
53
|
+
return unless dst.is_a?(String)
|
|
54
|
+
|
|
55
|
+
cs__patched_path_traversal_rule(dst, true, method)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
READ = 'read'
|
|
59
|
+
WRITE = 'write'
|
|
60
|
+
COPY = 'copy'
|
|
61
|
+
def write? action, *args
|
|
62
|
+
return false if action == READ
|
|
63
|
+
return false if action == COPY
|
|
64
|
+
return true if action == WRITE
|
|
65
|
+
|
|
66
|
+
write_marker = args.length > 1 ? args[1] : nil
|
|
67
|
+
write_marker && cs__possible_write(write_marker)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def cs__patched_path_traversal_rule path, possible_write, method
|
|
71
|
+
return unless cs__patched_applies_to?(path, possible_write)
|
|
72
|
+
|
|
73
|
+
logger.debug(nil, "checking path traversal: write=true path=#{ path }")
|
|
74
|
+
rule.infilter(Contrast::Agent::REQUEST_TRACKER.current, method, path)
|
|
75
|
+
rescue Contrast::SecurityException => e
|
|
76
|
+
raise e
|
|
77
|
+
rescue StandardError => e
|
|
78
|
+
logger.error(e, 'path traversal')
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
CS__SAFER_REL_PATHS = %w[public app log tmp].cs__freeze
|
|
82
|
+
def cs__patched_safer_abs_paths
|
|
83
|
+
@_cs__patched_safer_abs_paths ||= begin
|
|
84
|
+
pwd = ENV['PWD']
|
|
85
|
+
if pwd
|
|
86
|
+
tmp = CS__SAFER_REL_PATHS.map { |r| "#{ pwd }/#{ r }" }
|
|
87
|
+
gems = ENV['GEM_PATH']
|
|
88
|
+
tmp += gems.split(Contrast::Utils::ObjectShare::COLON) if gems
|
|
89
|
+
tmp
|
|
90
|
+
else
|
|
91
|
+
[]
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def cs__patched_applies_to? path, possible_write = false
|
|
97
|
+
# any possible write is a potential risk
|
|
98
|
+
return true if possible_write
|
|
99
|
+
|
|
100
|
+
# any path that moves 'up' is a potential risk
|
|
101
|
+
return true if path.index(Contrast::Utils::ObjectShare::PARENT_PATH)
|
|
102
|
+
|
|
103
|
+
path = path.downcase
|
|
104
|
+
if path.start_with?(Contrast::Utils::ObjectShare::SLASH)
|
|
105
|
+
cs__patched_safer_abs_paths.each do |prefix|
|
|
106
|
+
return false if path.start_with?(prefix)
|
|
107
|
+
end
|
|
108
|
+
else
|
|
109
|
+
CS__SAFER_REL_PATHS.each do |prefix|
|
|
110
|
+
return false if path.start_with?(prefix)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
true
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
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/utils/data_store_util'
|
|
6
|
+
|
|
7
|
+
module Contrast
|
|
8
|
+
module CoreExtensions
|
|
9
|
+
module Protect
|
|
10
|
+
# This Module is how we apply the SQL Injection rule. It is called from
|
|
11
|
+
# our patches of the targeted methods in which the execution of String
|
|
12
|
+
# based SQL queries occur. It is responsible for deciding if the infilter
|
|
13
|
+
# methods of the rule should be invoked.
|
|
14
|
+
module AppliesSqliRule
|
|
15
|
+
DATABASE_MYSQL = 'MySQL'
|
|
16
|
+
DATABASE_SQLITE = 'SQLite3'
|
|
17
|
+
DATABASE_PG = 'PostgreSQL'
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
include Contrast::Components::Interface
|
|
21
|
+
|
|
22
|
+
access_component :logging, :analysis
|
|
23
|
+
|
|
24
|
+
def cs__patched_apply_sql_rule method, _exception, properties, object, args
|
|
25
|
+
database = properties['database']
|
|
26
|
+
return unless database
|
|
27
|
+
|
|
28
|
+
index = properties[Contrast::Utils::ObjectShare::INDEX]
|
|
29
|
+
return unless valid_input?(index, args)
|
|
30
|
+
return if cs__skip_analysis?
|
|
31
|
+
|
|
32
|
+
sql = args[index]
|
|
33
|
+
logger.debug(nil, "applying sqli rule on #{ object } for #{ method }")
|
|
34
|
+
rule.infilter(Contrast::Agent::REQUEST_TRACKER.current, database, sql)
|
|
35
|
+
rescue Contrast::SecurityException => e
|
|
36
|
+
raise e
|
|
37
|
+
rescue StandardError => e
|
|
38
|
+
logger.error(e, "Error running SQLi rule in #{ object }")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def rule
|
|
42
|
+
PROTECT.rule Contrast::Agent::Protect::Rule::Sqli::NAME
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def valid_input? index, args
|
|
46
|
+
return false unless args && args.length > index
|
|
47
|
+
|
|
48
|
+
sql = args[index]
|
|
49
|
+
sql && !sql.empty?
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def cs__skip_analysis?
|
|
53
|
+
context = Contrast::Agent::REQUEST_TRACKER.current
|
|
54
|
+
return true unless context&.app_loaded?
|
|
55
|
+
return true unless rule&.enabled?
|
|
56
|
+
|
|
57
|
+
false
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,141 @@
|
|
|
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/utils/object_share'
|
|
6
|
+
|
|
7
|
+
module Contrast
|
|
8
|
+
module CoreExtensions
|
|
9
|
+
module Protect
|
|
10
|
+
# This Module is how we apply the XXE rule. It is called from our patches
|
|
11
|
+
# of the targeted methods in which XML parsing and entity resolution
|
|
12
|
+
# occurs. It is responsible for deciding if the infilter methods of the
|
|
13
|
+
# rule should be invoked.
|
|
14
|
+
module AppliesXxeRule
|
|
15
|
+
include Contrast::Components::Interface
|
|
16
|
+
access_component :logging, :analysis
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
def cs__patched_apply_xxe_rule _method, _exception, _properties, object, args
|
|
20
|
+
return unless valid_input?(args)
|
|
21
|
+
return if cs__skip_analysis?
|
|
22
|
+
|
|
23
|
+
xml = args.first
|
|
24
|
+
parser = determine_parser(object)
|
|
25
|
+
return unless parser
|
|
26
|
+
|
|
27
|
+
rule.infilter(Contrast::Agent::REQUEST_TRACKER.current, parser, xml)
|
|
28
|
+
rescue Contrast::SecurityException => e
|
|
29
|
+
raise e
|
|
30
|
+
rescue StandardError => e
|
|
31
|
+
parser ||= Contrast::Utils::ObjectShare::UNKNOWN
|
|
32
|
+
logger.error(e, "Error running XXE rule in #{ parser }")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# IO is tricky. If we can't rewind it, we can't fix it back to the
|
|
36
|
+
# original state. To be safe, we'll skip non-rewindable IO objects.
|
|
37
|
+
def cs__patched_apply_xxe_rule__io _method, _exception, _properties, object, args
|
|
38
|
+
need_rewind = false
|
|
39
|
+
return unless valid_io_input?(args)
|
|
40
|
+
return if cs__skip_analysis?
|
|
41
|
+
|
|
42
|
+
need_rewind = true
|
|
43
|
+
xml = args.first.read
|
|
44
|
+
parser = determine_parser(object)
|
|
45
|
+
return unless parser
|
|
46
|
+
|
|
47
|
+
rule.infilter(Contrast::Agent::REQUEST_TRACKER.current, parser, xml)
|
|
48
|
+
rescue Contrast::SecurityException => e
|
|
49
|
+
raise e
|
|
50
|
+
rescue StandardError => e
|
|
51
|
+
parser ||= Contrast::Utils::ObjectShare::UNKNOWN
|
|
52
|
+
logger.error(e, "Error running XXE rule in #{ parser }")
|
|
53
|
+
ensure
|
|
54
|
+
args.first.rewind if need_rewind
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Oga's Lexer is a special case b/c the information we need is on the
|
|
58
|
+
# object itself -- specifically in the @data instance variable
|
|
59
|
+
def cs__patched_apply_xxe_rule__lexer _method, _exception, _properties, object, _args
|
|
60
|
+
return unless valid_data_input?(object)
|
|
61
|
+
return if cs__skip_analysis?
|
|
62
|
+
|
|
63
|
+
parser = determine_parser(object)
|
|
64
|
+
return unless parser
|
|
65
|
+
|
|
66
|
+
data = object.instance_variable_get(DATA_KEY)
|
|
67
|
+
|
|
68
|
+
if data.cs__is_a?(String)
|
|
69
|
+
rule.infilter(Contrast::Agent::REQUEST_TRACKER.current, parser, data)
|
|
70
|
+
elsif data.cs__respond_to?(:each_line)
|
|
71
|
+
data.each_line do |line|
|
|
72
|
+
rule.infilter(Contrast::Agent::REQUEST_TRACKER.current, parser, line)
|
|
73
|
+
end
|
|
74
|
+
data.rewind if data.cs__respond_to?(:rewind)
|
|
75
|
+
elsif data.cs__respond_to?(:each)
|
|
76
|
+
data.each do |chunk|
|
|
77
|
+
rule.infilter(Contrast::Agent::REQUEST_TRACKER.current, parser, chunk)
|
|
78
|
+
end
|
|
79
|
+
data.rewind if data.cs__respond_to?(:rewind)
|
|
80
|
+
end
|
|
81
|
+
rescue Contrast::SecurityException => e
|
|
82
|
+
raise e
|
|
83
|
+
rescue StandardError => e
|
|
84
|
+
parser ||= Contrast::Utils::ObjectShare::UNKNOWN
|
|
85
|
+
logger.error(e, "Error running XXE rule in #{ parser }")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def rule
|
|
89
|
+
PROTECT.rule Contrast::Agent::Protect::Rule::Xxe::NAME
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def valid_input? args
|
|
93
|
+
return false unless args&.any?
|
|
94
|
+
|
|
95
|
+
args.first
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def valid_io_input? args
|
|
99
|
+
return false unless valid_input?(args)
|
|
100
|
+
|
|
101
|
+
io = args.first
|
|
102
|
+
io&.respond_to?(:rewind)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
DATA_KEY = '@data'.to_sym
|
|
106
|
+
def valid_data_input? object
|
|
107
|
+
object.instance_variable_defined?(DATA_KEY) &&
|
|
108
|
+
object.instance_variable_get(DATA_KEY)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def cs__skip_analysis?
|
|
112
|
+
context = Contrast::Agent::REQUEST_TRACKER.current
|
|
113
|
+
return true unless context&.app_loaded?
|
|
114
|
+
return true unless rule&.enabled?
|
|
115
|
+
|
|
116
|
+
false
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
NOKOGIRI_MARKER = 'Nokogiri::'
|
|
120
|
+
PARSER_NOKOGIRI = 'Nokogiri'
|
|
121
|
+
OX_MARKER = 'Ox' # breaks marker pattern b/c Ox is entire classname
|
|
122
|
+
PARSER_OX = 'Ox'
|
|
123
|
+
OGA_MARKER = 'Oga::'
|
|
124
|
+
PARSER_OGA = 'Oga'
|
|
125
|
+
def determine_parser object
|
|
126
|
+
clazz = object.is_a?(Module) ? object : object.cs__class
|
|
127
|
+
name = clazz.cs__name
|
|
128
|
+
|
|
129
|
+
if name.start_with?(NOKOGIRI_MARKER)
|
|
130
|
+
PARSER_NOKOGIRI
|
|
131
|
+
elsif name.start_with?(OX_MARKER)
|
|
132
|
+
PARSER_OX
|
|
133
|
+
elsif name.start_with?(OGA_MARKER)
|
|
134
|
+
PARSER_OGA
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
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 functions as our patch into the Kernel class for Protect,
|
|
7
|
+
# allowing us to track activity as it crosses spawned processes.
|
|
8
|
+
module Kernel
|
|
9
|
+
class << self
|
|
10
|
+
include Contrast::Components::Interface
|
|
11
|
+
access_component :contrast_service
|
|
12
|
+
|
|
13
|
+
def cs__protect_build_wrapper
|
|
14
|
+
lambda {
|
|
15
|
+
Kernel.cs__protect_proc_start
|
|
16
|
+
yield
|
|
17
|
+
# AtExitHook handles sending any messages generated in the new forked process
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def cs__protect_proc_start
|
|
22
|
+
context = Contrast::Agent::REQUEST_TRACKER.current
|
|
23
|
+
return unless context
|
|
24
|
+
|
|
25
|
+
context.reset_activity
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
cs__scoped_require 'cs__protect_kernel/cs__protect_kernel'
|
|
@@ -0,0 +1,7 @@
|
|
|
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
|
+
if defined?(Psych)
|
|
5
|
+
cs__scoped_require 'contrast/core_extensions/protect/applies_deserialization_rule'
|
|
6
|
+
cs__scoped_require 'cs__patched_psych/cs__patched_psych'
|
|
7
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
# ensure that we're being loaded with an agent
|
|
5
|
+
# NOTE: THIS CLASS WILL NOT BE RELOADED B/C WE CANNOT RELOAD THE STANDARD
|
|
6
|
+
# thread file
|
|
7
|
+
|
|
8
|
+
# Request context is still tracked per-thread. There isn't anything
|
|
9
|
+
# particularly order-dependent or stateful about request contexts. It
|
|
10
|
+
# exists mostly for reference.
|
|
11
|
+
#
|
|
12
|
+
# Scope HAS to exist per-fiber.
|
|
13
|
+
|
|
14
|
+
# Monkey-patching Thread#initialize.
|
|
15
|
+
class Thread
|
|
16
|
+
alias_method :cs__initialize, :initialize
|
|
17
|
+
|
|
18
|
+
def initialize *args, &block
|
|
19
|
+
# Thread.current still references the original(callee) thread that is
|
|
20
|
+
# instantiating this new fiber during initialization
|
|
21
|
+
Contrast::Components::Scope::MONITOR.synchronize do
|
|
22
|
+
if (current_context = Thread.current[:current_context])
|
|
23
|
+
self[:current_context] = current_context.dup
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
Contrast::Components::Scope.sweep_dead_ecs
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
cs__initialize(*args, &block)
|
|
30
|
+
end
|
|
31
|
+
end
|