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,73 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Contrast
|
|
5
|
+
module Agent
|
|
6
|
+
module Assess
|
|
7
|
+
module Rule
|
|
8
|
+
module Provider
|
|
9
|
+
# Determine if there are any passwords hardcoded into the sourcecode
|
|
10
|
+
# of the application. A constant is a password if:
|
|
11
|
+
# 1) the name contains a PASSWORD_FIELD_NAMES value
|
|
12
|
+
# 2) the name does not contain a NON_PASSWORD_PARTIAL_NAMES value
|
|
13
|
+
# 3) the value is a String
|
|
14
|
+
# 4) the value is not solely alphanumeric and '.' or '_' * note that
|
|
15
|
+
# mixing the characters counts as a violation of this rule
|
|
16
|
+
class HardcodedPassword
|
|
17
|
+
include Contrast::Agent::Assess::Rule::Provider::HardcodedValueRule
|
|
18
|
+
|
|
19
|
+
NAME = 'hardcoded-password'
|
|
20
|
+
def rule_id
|
|
21
|
+
NAME
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# These are names, determined by the security team (Matt & Ar), that
|
|
25
|
+
# indicate a field is likely to be a password or secret token of some
|
|
26
|
+
# sort.
|
|
27
|
+
PASSWORD_FIELD_NAMES = %w[PASSWORD PASSKEY PASSPHRASE SECRET].cs__freeze
|
|
28
|
+
|
|
29
|
+
# These are markers whose presence indicates that a field is more
|
|
30
|
+
# likely to be a descriptor or requirement than an actual password.
|
|
31
|
+
# We should ignore fields that contain them.
|
|
32
|
+
NON_PASSWORD_PARTIAL_NAMES = %w[DATE FORGOT FORM ENCODE PATTERN PREFIX PROP SUFFIX URL BASE FILE URI].cs__freeze
|
|
33
|
+
|
|
34
|
+
# If the constant looks like a password and it doesn't look like a
|
|
35
|
+
# password descriptor, it passes for this rule
|
|
36
|
+
def name_passes? constant_string
|
|
37
|
+
PASSWORD_FIELD_NAMES.any? { |name| constant_string.index(name) } &&
|
|
38
|
+
NON_PASSWORD_PARTIAL_NAMES.none? { |name| constant_string.index(name) }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# If the value is a string, it passes for this rule
|
|
42
|
+
def value_type_passes? value
|
|
43
|
+
value.is_a?(String)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# If the value probably isn't a property name, it passes for this
|
|
47
|
+
# rule
|
|
48
|
+
def value_passes? value
|
|
49
|
+
!probably_property_name?(value)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# If a field name matches an expected password field, we'll check it's
|
|
53
|
+
# value to see if it looks like a placeholder. For our purposes,
|
|
54
|
+
# placeholders will be any non-empty String conforming to the patterns
|
|
55
|
+
# below. We do combine the patterns with [\._] as in Ruby these two
|
|
56
|
+
# characters are probably more likely to appear together in a
|
|
57
|
+
# default placeholder than in a password. Note this is opposite of
|
|
58
|
+
# the behavior in Java
|
|
59
|
+
PROPERTY_NAME_PATTERN = /^[a-z]+[\.\_][\.\_a-z]*[a-z]+$/.cs__freeze
|
|
60
|
+
def probably_property_name? value
|
|
61
|
+
value.match?(PROPERTY_NAME_PATTERN)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
REDACTED_MARKER = ' = "**REDACTED**"'
|
|
65
|
+
def redacted_marker
|
|
66
|
+
REDACTED_MARKER
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
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/module'
|
|
6
|
+
|
|
7
|
+
module Contrast
|
|
8
|
+
module Agent
|
|
9
|
+
module Assess
|
|
10
|
+
module Rule
|
|
11
|
+
module Provider
|
|
12
|
+
# Hardcoded rules detect if any secret value has been written directly into the
|
|
13
|
+
# sourcecode of the application. To use this base class, a provider must
|
|
14
|
+
# implement four methods
|
|
15
|
+
# 1) name_passes? : does the constant name match a given value set
|
|
16
|
+
# 2) value_type_passes? : does the type of the value of the constant match the
|
|
17
|
+
# type given
|
|
18
|
+
# 3) value_passes? : does the value of the constant match a given value set
|
|
19
|
+
# 4) redacted_marker : the value to plug in for the obfuscated value
|
|
20
|
+
module HardcodedValueRule
|
|
21
|
+
include Contrast::Components::Interface
|
|
22
|
+
access_component :contrast_service, :logging, :analysis
|
|
23
|
+
|
|
24
|
+
def disabled?
|
|
25
|
+
!ASSESS.enabled? || ASSESS.rule_disabled?(rule_id)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
COMMON_CONSTANTS = %i[
|
|
29
|
+
CONTRAST_ASSESS_POLICY_STATUS
|
|
30
|
+
VERSION
|
|
31
|
+
].cs__freeze
|
|
32
|
+
def analyze clazz
|
|
33
|
+
return if disabled?
|
|
34
|
+
|
|
35
|
+
# we only want the constants explicitly defined in this class, not
|
|
36
|
+
# those of its ancestor(s)
|
|
37
|
+
constants = clazz.cs__constants(false)
|
|
38
|
+
|
|
39
|
+
# if there are no constants, let's just leave
|
|
40
|
+
return unless constants&.any?
|
|
41
|
+
|
|
42
|
+
constants.each do |constant|
|
|
43
|
+
next if COMMON_CONSTANTS.include?(constant)
|
|
44
|
+
|
|
45
|
+
# if this class autoloads its constant, get the hell away from it
|
|
46
|
+
# I mean it! Don't even think about it.
|
|
47
|
+
#
|
|
48
|
+
# Autoload means this constant (usually [always?] a class or
|
|
49
|
+
# module) won't be required until something in the application
|
|
50
|
+
# tries to load it. We CANNOT be that thing. We'll just have to
|
|
51
|
+
# wait until it's loaded, at which point we'll be handed it
|
|
52
|
+
# again.
|
|
53
|
+
next if clazz.cs__autoload?(constant)
|
|
54
|
+
|
|
55
|
+
# constant comes to us as a symbol. that sucks. we need to do
|
|
56
|
+
# some string methods on it, so stringify it.
|
|
57
|
+
constant_string = constant.to_s
|
|
58
|
+
|
|
59
|
+
# if this is another class or a module, move on
|
|
60
|
+
next unless constant_name?(constant_string)
|
|
61
|
+
|
|
62
|
+
next unless name_passes?(constant_string)
|
|
63
|
+
|
|
64
|
+
value = clazz.cs__const_get(constant, false)
|
|
65
|
+
|
|
66
|
+
# if the constant isn't holding a string, skip it
|
|
67
|
+
next unless value_type_passes?(value)
|
|
68
|
+
|
|
69
|
+
# if it looks like a placeholder / pointer to a config, skip it
|
|
70
|
+
next unless value_passes?(value)
|
|
71
|
+
|
|
72
|
+
report_finding(clazz, constant_string)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Constants can be variable or classes defined in the given
|
|
77
|
+
# class. We ONLY want the variables, which should be defined in
|
|
78
|
+
# the MACRO_CASE (upper case & underscore format)
|
|
79
|
+
CONSTANT_NAME_PATTERN = /^[A-Z_]+$/.cs__freeze
|
|
80
|
+
def constant_name? constant
|
|
81
|
+
constant.match?(CONSTANT_NAME_PATTERN)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# The name of the field
|
|
85
|
+
CONSTANT_NAME_KEY = 'name'
|
|
86
|
+
# The code line, recreated, with the password obfuscated
|
|
87
|
+
CODE_SOURCE_KEY = 'codeSource'
|
|
88
|
+
# The constant name
|
|
89
|
+
SOURCE_KEY = 'source'
|
|
90
|
+
|
|
91
|
+
def report_finding clazz, constant_string
|
|
92
|
+
class_name = clazz.cs__name
|
|
93
|
+
|
|
94
|
+
finding = Contrast::Api::Dtm::Finding.new
|
|
95
|
+
finding.rule_id = Contrast::Utils::StringUtils.protobuf_safe_string(rule_id)
|
|
96
|
+
finding.session_id = Contrast::Agent::FeatureState.instance.current_session_id
|
|
97
|
+
|
|
98
|
+
finding.version = Contrast::Agent::Assess::Policy::TriggerMethod::CURRENT_FINDING_VERSION
|
|
99
|
+
|
|
100
|
+
finding.properties[SOURCE_KEY] = Contrast::Utils::StringUtils.protobuf_safe_string(class_name)
|
|
101
|
+
finding.properties[CONSTANT_NAME_KEY] = Contrast::Utils::StringUtils.protobuf_safe_string(constant_string)
|
|
102
|
+
finding.properties[CODE_SOURCE_KEY] = Contrast::Utils::StringUtils.protobuf_safe_string(constant_string + redacted_marker)
|
|
103
|
+
|
|
104
|
+
hash = Contrast::Utils::HashDigest.generate_class_scanning_hash(finding)
|
|
105
|
+
finding.hash_code = Contrast::Utils::StringUtils.protobuf_safe_string(hash)
|
|
106
|
+
finding.preflight = Contrast::Utils::PreflightUtil.create_preflight(finding)
|
|
107
|
+
|
|
108
|
+
activity = Contrast::Api::Dtm::Activity.new
|
|
109
|
+
activity.finding_tags = Contrast::Utils::StringUtils.protobuf_safe_string(ASSESS.tags)
|
|
110
|
+
activity.findings << finding
|
|
111
|
+
|
|
112
|
+
CONTRAST_SERVICE.queue_message activity
|
|
113
|
+
rescue StandardError => e
|
|
114
|
+
logger.error(e, 'Unable to build a finding for Hardcoded Rule')
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Contrast
|
|
5
|
+
module Agent
|
|
6
|
+
module Assess
|
|
7
|
+
module Rule
|
|
8
|
+
# A regexp is only vulnerable to REDOS if it's going to run
|
|
9
|
+
# with pathologically bad performance.
|
|
10
|
+
# We report a vulnerability if the regexp is liable to run
|
|
11
|
+
# with quadratic time for some input.
|
|
12
|
+
# This vastly errs on the side of false positives.
|
|
13
|
+
class Redos < Contrast::Agent::Assess::Rule::Base
|
|
14
|
+
class << self
|
|
15
|
+
NAME = 'redos'
|
|
16
|
+
def name
|
|
17
|
+
NAME
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def regexp_complexity_check context, trigger_node, source, object, ret, invoked, *args
|
|
21
|
+
# we can arrive here either from:
|
|
22
|
+
# regexp =~ string
|
|
23
|
+
# string =~ regexp
|
|
24
|
+
# regexp.match string
|
|
25
|
+
#
|
|
26
|
+
# so object/args[0] can be string/regexp or regexp/string.
|
|
27
|
+
regexp = object.is_a?(Regexp) ? object : args[0]
|
|
28
|
+
string = object.is_a?(String) ? object : args[0]
|
|
29
|
+
|
|
30
|
+
# (1) regexp must be exploitable
|
|
31
|
+
return unless regexp_vulnerable?(regexp)
|
|
32
|
+
|
|
33
|
+
# (2) regexp must evaluate against user input
|
|
34
|
+
if trigger_node.violated?(string) # rubocop:disable Style/GuardClause
|
|
35
|
+
Contrast::Agent::Assess::Policy::TriggerMethod.build_finding(context, trigger_node, source, object, ret, invoked + 1, args)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
protected
|
|
40
|
+
|
|
41
|
+
VULNERABLE_PATTERN = /[\[(].*?[\[(].*?[\])][*+?].*?[\])][*+?]/.cs__freeze
|
|
42
|
+
|
|
43
|
+
# Does the regexp
|
|
44
|
+
# https://bitbucket.org/contrastsecurity/assess-specifications/src/master/rules/dataflow/redos.md
|
|
45
|
+
def regexp_vulnerable? regexp
|
|
46
|
+
# A pattern is considered vulnerable if it has 2 or more levels of nested multi-matching.
|
|
47
|
+
# A level is defined as any set of opening and closing control characters immediately followed by a multi match control character.
|
|
48
|
+
# A control character is defined as one of the OPENING_CHARS, CLOSING_CHARS,
|
|
49
|
+
# or MULTI_MATCH_CHARS that is not immediately preceded by an escaping \ character.
|
|
50
|
+
# OPENING_CHARS are ( and [ CLOSING_CHARS are ) and ] MULTI_MATCH_CHARS are +, *, and ?
|
|
51
|
+
|
|
52
|
+
# Nota bene about Regexp#to_s: it doesn't necessarily give you the original Regexp back
|
|
53
|
+
# (in the sense of `my_str == Regexp.new(my_str).to_s`), it gives you a Regexp that
|
|
54
|
+
# will have the same functional characteristics as the original.
|
|
55
|
+
# Regexp#inspect gives you a "more nicely formatted" version than #to_s.
|
|
56
|
+
# Regexp#source will give you the original source.
|
|
57
|
+
# TODO RUBY-683, would we ever get a hit on one but not the other?
|
|
58
|
+
|
|
59
|
+
# Use #match? because it doesn't fill out global variables
|
|
60
|
+
# in the way match or =~ do.
|
|
61
|
+
VULNERABLE_PATTERN.match? regexp.source
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Contrast
|
|
5
|
+
module Agent
|
|
6
|
+
module Assess
|
|
7
|
+
module Rule
|
|
8
|
+
# Those rules which function by scanning the Response body in order to
|
|
9
|
+
# detect vulnerabilities. These rules should each have their own
|
|
10
|
+
# Contrast::Agent::Assess::RuleResponseWatcher.
|
|
11
|
+
#
|
|
12
|
+
# Note: Most have been moved to the Service, as they typically watch
|
|
13
|
+
# the Request or Response bodies, parsing out vulnerabilities
|
|
14
|
+
# therein. CSRF is an exception to this as the rule requires a change
|
|
15
|
+
# to the Response body to function.
|
|
16
|
+
class ResponseScanningRule < Contrast::Agent::Assess::Rule::Base
|
|
17
|
+
def watcher
|
|
18
|
+
# raise(
|
|
19
|
+
# NotImplementedError,
|
|
20
|
+
# 'A child rule should have overridden the watcher method')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def stream_safe?
|
|
24
|
+
false
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def generate_hash finding
|
|
28
|
+
Contrast::Utils::HashDigest.generate_response_hash(finding)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def postfilter context
|
|
32
|
+
findings = watcher.postfilter(context) if watcher && context
|
|
33
|
+
return unless findings
|
|
34
|
+
|
|
35
|
+
if findings.is_a?(Array)
|
|
36
|
+
findings.each do |finding|
|
|
37
|
+
send_report(finding) if finding
|
|
38
|
+
end
|
|
39
|
+
else
|
|
40
|
+
send_report(findings)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Contrast
|
|
5
|
+
module Agent
|
|
6
|
+
module Assess
|
|
7
|
+
module Rule
|
|
8
|
+
# A watcher focused on the Response body, parsing out vulnerabilities
|
|
9
|
+
# therein.
|
|
10
|
+
#
|
|
11
|
+
# Note: Most have been moved to the Service, as they typically watch
|
|
12
|
+
# the Request or Response bodies, parsing out vulnerabilities
|
|
13
|
+
# therein. CSRF is an exception to this as the rule requires a change
|
|
14
|
+
# to the Response body to function.
|
|
15
|
+
class ResponseWatcher < Contrast::Agent::Assess::Rule::Watcher
|
|
16
|
+
def postfilter context
|
|
17
|
+
return unless supports?(context)
|
|
18
|
+
return unless vulnerable?(context)
|
|
19
|
+
|
|
20
|
+
build_finding(context)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def vulnerable? _context
|
|
24
|
+
raise(
|
|
25
|
+
NotImplementedError,
|
|
26
|
+
'A child rule should have overridden the vulnerable? method')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def build_finding _context
|
|
30
|
+
Contrast::Api::Dtm::Finding.new
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Contrast
|
|
5
|
+
module Agent
|
|
6
|
+
module Assess
|
|
7
|
+
module Rule
|
|
8
|
+
# Watchers are how those Rules which do not act on dataflow function.
|
|
9
|
+
#
|
|
10
|
+
# Note: Most have been moved to the Service, as they typically watch
|
|
11
|
+
# the Request or Response bodies, parsing out vulnerabilities
|
|
12
|
+
# therein. CSRF is an exception to this as the rule requires a change
|
|
13
|
+
# to the Response body to function.
|
|
14
|
+
class Watcher
|
|
15
|
+
def supports? context
|
|
16
|
+
return false if context.request.static_request?
|
|
17
|
+
return false unless context.response
|
|
18
|
+
return false if undesired_response_code? context.response.response_code
|
|
19
|
+
return false if undesired_response_type? context.response.content_type
|
|
20
|
+
|
|
21
|
+
true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
UNDESIRED_RESPONSE_CODES = [301, 302, 307, 404, 410, 500].cs__freeze
|
|
25
|
+
def undesired_response_code? code
|
|
26
|
+
UNDESIRED_RESPONSE_CODES.include?(code)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def undesired_response_type? _type
|
|
30
|
+
false
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Contrast
|
|
5
|
+
module Agent
|
|
6
|
+
module Assess
|
|
7
|
+
# A Tag represents a range in a given piece of data. It is used by the
|
|
8
|
+
# Agent to determine if a vulnerable dataflow has occurred.
|
|
9
|
+
class Tag
|
|
10
|
+
attr_reader :length, # length of tagged text within string
|
|
11
|
+
:start_idx, # start of range
|
|
12
|
+
:end_idx # end of range (calculated from start + length)
|
|
13
|
+
|
|
14
|
+
# Initialize a new tag
|
|
15
|
+
# length : the length of the string described with this tag
|
|
16
|
+
# start_idx : (default: 0) the starting position in the string for this tag
|
|
17
|
+
def initialize length, start_idx = 0
|
|
18
|
+
update_range(start_idx, start_idx + length)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Return true if the tag covers the given position in the string
|
|
22
|
+
def covers? idx
|
|
23
|
+
idx >= start_idx && idx < end_idx
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Return true if the tag is above the given position in the string
|
|
27
|
+
def above? idx
|
|
28
|
+
idx < start_idx
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Return the range that this tag covers
|
|
32
|
+
def range
|
|
33
|
+
start_idx...end_idx
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Return if a given tag overlaps this one
|
|
37
|
+
def overlaps? other
|
|
38
|
+
return true if @start_idx < other.start_idx && @end_idx >= other.start_idx # we start below other & end in it
|
|
39
|
+
return true if @start_idx >= other.start_idx && @end_idx <= other.end_idx # we start and end in other
|
|
40
|
+
return true if @start_idx <= other.end_idx && @end_idx > other.end_idx # we start in other & end above it
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def shift idx
|
|
44
|
+
update_range(@start_idx + idx, @end_idx + idx)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def shift_end idx
|
|
48
|
+
update_range(@start_idx, @end_idx + idx)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def update_start start_idx
|
|
52
|
+
update_range(start_idx, @end_idx)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def update_end end_idx
|
|
56
|
+
update_range(@start_idx, end_idx)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def repurpose start_idx, end_idx
|
|
60
|
+
update_range(start_idx, end_idx)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Given a tag, merge its ranges with this one
|
|
64
|
+
# such that the lowest start and highest end
|
|
65
|
+
# become the values of this tag
|
|
66
|
+
#
|
|
67
|
+
# Returns true if the other tag was merged into
|
|
68
|
+
# this tag
|
|
69
|
+
def merge other
|
|
70
|
+
return unless overlaps?(other)
|
|
71
|
+
|
|
72
|
+
start = other.start_idx < @start_idx ? other.start_idx : @start_idx
|
|
73
|
+
finish = other.end_idx > @end_idx ? other.end_idx : @end_idx
|
|
74
|
+
update_range(start, finish)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Modification to tracked String can change the position and length of the tracked tag
|
|
78
|
+
# shift : negative value moves left
|
|
79
|
+
def copy_modified shift
|
|
80
|
+
start = start_idx + shift
|
|
81
|
+
# Tags cannot start below 0
|
|
82
|
+
new_start_idx = start >= 0 ? start : 0
|
|
83
|
+
# If a tag were to go negative, cut off the negative portion from length
|
|
84
|
+
new_length = start >= 0 ? length : (length + start)
|
|
85
|
+
Contrast::Agent::Assess::Tag.new(new_length, new_start_idx)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def str_val
|
|
89
|
+
@_str_val ||= "[#{ start_idx },#{ end_idx }]"
|
|
90
|
+
end
|
|
91
|
+
alias_method :to_s, :str_val
|
|
92
|
+
|
|
93
|
+
BELOW = 'BELOW'
|
|
94
|
+
LOW_SPAN = 'LOW_SPAN'
|
|
95
|
+
WITHIN = 'WITHIN'
|
|
96
|
+
WITHOUT = 'WITHOUT'
|
|
97
|
+
HIGH_SPAN = 'HIGH_SPAN'
|
|
98
|
+
ABOVE = 'ABOVE'
|
|
99
|
+
|
|
100
|
+
# The tag is ______ the range
|
|
101
|
+
# rrrrrrr == self.range, the range of the tag
|
|
102
|
+
def compare_range start, stop
|
|
103
|
+
# r starts and stops below
|
|
104
|
+
# rrrrrrrrrrrrr
|
|
105
|
+
# start stop
|
|
106
|
+
return BELOW if @start_idx < start && @end_idx <= start
|
|
107
|
+
# r starts below and finishes within
|
|
108
|
+
# rrrrrrrrrrrrr
|
|
109
|
+
# start stop
|
|
110
|
+
return LOW_SPAN if @start_idx < start && @end_idx > start && @end_idx <= stop
|
|
111
|
+
# r is between start and stop
|
|
112
|
+
# rrrrrrrrrrrrrrr
|
|
113
|
+
# start stop
|
|
114
|
+
return WITHIN if @start_idx >= start && @start_idx < stop && @end_idx <= stop
|
|
115
|
+
# r starts below and finishes above stop
|
|
116
|
+
# rrrrrrrrrrrrrrrrrrrrrrrr
|
|
117
|
+
# start stop
|
|
118
|
+
return WITHOUT if @start_idx < start && @end_idx > stop
|
|
119
|
+
# r starts within and finishes above stop
|
|
120
|
+
# rrrrrrrrrrrrr
|
|
121
|
+
# start stop
|
|
122
|
+
return HIGH_SPAN if @start_idx >= start && @start_idx < stop && @end_idx > stop
|
|
123
|
+
|
|
124
|
+
# starts and stops above
|
|
125
|
+
# rrrrrrrrrrrrr
|
|
126
|
+
# start stop
|
|
127
|
+
ABOVE
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
private
|
|
131
|
+
|
|
132
|
+
# Update range should be how start and end index of tags are changed,
|
|
133
|
+
# as it includes validation
|
|
134
|
+
#
|
|
135
|
+
# Note that we allow start_idx == end_idx b/c this is how we determine
|
|
136
|
+
# if a tag range is 'covered' in trigger detection
|
|
137
|
+
ERROR_NEGATIVE_START = 'Unable to set start idx negative'
|
|
138
|
+
ERROR_END_BEFORE_START = 'Unable to set start idx after end idx'
|
|
139
|
+
def update_range start_idx, end_idx
|
|
140
|
+
raise(ArgumentError, ERROR_NEGATIVE_START) if start_idx.negative?
|
|
141
|
+
raise(ArgumentError, ERROR_END_BEFORE_START) if end_idx < start_idx
|
|
142
|
+
|
|
143
|
+
@start_idx = start_idx
|
|
144
|
+
@end_idx = end_idx
|
|
145
|
+
@length = @end_idx - @start_idx
|
|
146
|
+
@_str_val = nil
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|