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,101 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
cs__scoped_require 'contrast/core_extensions/protect/applies_sqli_rule'
|
|
5
|
+
|
|
6
|
+
module Contrast
|
|
7
|
+
module Agent
|
|
8
|
+
module Protect
|
|
9
|
+
module Rule
|
|
10
|
+
# The Ruby implementation of the Protect SQL Injection rule.
|
|
11
|
+
class Sqli < Contrast::Agent::Protect::Rule::BaseService
|
|
12
|
+
NAME = 'sql-injection'
|
|
13
|
+
BLOCK_MESSAGE = 'SQLi rule triggered. Response blocked.'
|
|
14
|
+
|
|
15
|
+
def name
|
|
16
|
+
NAME
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def block_message
|
|
20
|
+
BLOCK_MESSAGE
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def infilter context, database, query_string
|
|
24
|
+
return nil unless infilter?(context)
|
|
25
|
+
|
|
26
|
+
result = find_attacker(context, query_string, database: database)
|
|
27
|
+
return nil unless result
|
|
28
|
+
|
|
29
|
+
append_to_activity(context, result)
|
|
30
|
+
|
|
31
|
+
raise Contrast::SecurityException.new(self, BLOCK_MESSAGE) if blocked?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def build_attack_with_match context, input_analysis_result, result, query_string, **kwargs
|
|
35
|
+
attack_string = input_analysis_result.value
|
|
36
|
+
regexp = Regexp.new(Regexp.escape(attack_string), Regexp::IGNORECASE)
|
|
37
|
+
|
|
38
|
+
return nil unless query_string.match?(regexp)
|
|
39
|
+
|
|
40
|
+
database = kwargs[:database]
|
|
41
|
+
scanner = select_scanner(database)
|
|
42
|
+
|
|
43
|
+
ss = StringScanner.new(query_string)
|
|
44
|
+
length = attack_string.length
|
|
45
|
+
while ss.scan_until(regexp)
|
|
46
|
+
# the pos of StringScanner is at the end of the regexp (input string),
|
|
47
|
+
# we need the beginning
|
|
48
|
+
idx = ss.pos - attack_string.length
|
|
49
|
+
last_boundary, boundary = scanner.crosses_boundary(query_string, idx, input_analysis_result.value)
|
|
50
|
+
next unless last_boundary && boundary
|
|
51
|
+
|
|
52
|
+
input_analysis_result.attack_count = input_analysis_result.attack_count + 1
|
|
53
|
+
|
|
54
|
+
kwargs[:start_idx] = idx
|
|
55
|
+
kwargs[:end_idx] = idx + length
|
|
56
|
+
kwargs[:boundary_overrun_idx] = boundary
|
|
57
|
+
kwargs[:input_boundary_idx] = last_boundary
|
|
58
|
+
|
|
59
|
+
result ||= build_attack_result(context)
|
|
60
|
+
update_successful_attack_response(context, input_analysis_result, result, query_string)
|
|
61
|
+
append_sample(context, input_analysis_result, result, query_string, **kwargs)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
result
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
protected
|
|
68
|
+
|
|
69
|
+
def build_sample context, input_analysis_result, candidate_string, **kwargs
|
|
70
|
+
input = input_analysis_result.value
|
|
71
|
+
|
|
72
|
+
sample = build_base_sample(context, input_analysis_result)
|
|
73
|
+
sample.sqli = Contrast::Api::Dtm::SqlInjectionDetails.new
|
|
74
|
+
sample.sqli.query = Contrast::Utils::StringUtils.protobuf_safe_string(candidate_string)
|
|
75
|
+
sample.sqli.start_idx = sample.sqli.query.index(input).to_i
|
|
76
|
+
sample.sqli.end_idx = sample.sqli.start_idx + input.length
|
|
77
|
+
sample.sqli.boundary_overrun_idx = kwargs[:boundary].to_i
|
|
78
|
+
sample.sqli.input_boundary_idx = kwargs[:last_boundary].to_i
|
|
79
|
+
sample
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def select_scanner database
|
|
85
|
+
@sql_scanners ||= {
|
|
86
|
+
Contrast::CoreExtensions::Protect::AppliesSqliRule::DATABASE_MYSQL =>
|
|
87
|
+
Contrast::Agent::Protect::Rule::Sqli::MysqlSqlScanner.new,
|
|
88
|
+
Contrast::CoreExtensions::Protect::AppliesSqliRule::DATABASE_PG =>
|
|
89
|
+
Contrast::Agent::Protect::Rule::Sqli::PostgresSqlScanner.new,
|
|
90
|
+
Contrast::CoreExtensions::Protect::AppliesSqliRule::DATABASE_SQLITE =>
|
|
91
|
+
Contrast::Agent::Protect::Rule::Sqli::SqliteSqlScanner.new
|
|
92
|
+
}.cs__freeze
|
|
93
|
+
|
|
94
|
+
@default_sql_scanner ||= Contrast::Agent::Protect::Rule::Sqli::DefaultSqlScanner.new
|
|
95
|
+
@sql_scanners[database.to_s] || @default_sql_scanner
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
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 Protect
|
|
7
|
+
module Rule
|
|
8
|
+
# @deprecated RUBY-356
|
|
9
|
+
class Sqli
|
|
10
|
+
class DefaultSqlScanner < Contrast::Agent::Protect::Rule::DefaultScanner
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# This class is the concrete implementation of the DefaultSqlScanner designed
|
|
5
|
+
# to support the customizations of MySQL.
|
|
6
|
+
#
|
|
7
|
+
# @deprecated RUBY-356
|
|
8
|
+
# rubocop:disable Style/ClassAndModuleChildren
|
|
9
|
+
class Contrast::Agent::Protect::Rule::Sqli::MysqlSqlScanner <
|
|
10
|
+
Contrast::Agent::Protect::Rule::Sqli::DefaultSqlScanner
|
|
11
|
+
# rubocop:enable Style/ClassAndModuleChildren
|
|
12
|
+
|
|
13
|
+
# Is the current character '#' or are the current and
|
|
14
|
+
# subsequent characters both '-' ?
|
|
15
|
+
def start_line_comment? char, index, query
|
|
16
|
+
return true if char == Contrast::Utils::ObjectShare::POUND_SIGN
|
|
17
|
+
return false unless char == Contrast::Utils::ObjectShare::DASH
|
|
18
|
+
return false unless (query.length - 2) >= index
|
|
19
|
+
|
|
20
|
+
query[index + 1] == Contrast::Utils::ObjectShare::DASH
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Is the current character / sequence of characters the start of a block
|
|
24
|
+
# comment. In MySQL, '/*!' is an inline comment that has code that's
|
|
25
|
+
# executed, so it does not count as a block comment start
|
|
26
|
+
def start_block_comment? char, index, query
|
|
27
|
+
return false unless char == Contrast::Utils::ObjectShare::SLASH
|
|
28
|
+
return false unless (query.length - 3) >= index
|
|
29
|
+
|
|
30
|
+
query[index + 1] == Contrast::Utils::ObjectShare::ASTERISK &&
|
|
31
|
+
query[index + 2] != Contrast::Utils::ObjectShare::EXCLAMATION
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Indicates if '""' inside of double quotes is the equivalent of '\"'
|
|
35
|
+
def double_quote_escape_in_double_quote?
|
|
36
|
+
true
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
5
|
+
# frozen_string_literal: true
|
|
6
|
+
|
|
7
|
+
module Contrast
|
|
8
|
+
module Agent
|
|
9
|
+
module Protect
|
|
10
|
+
module Rule
|
|
11
|
+
class Sqli
|
|
12
|
+
# This class is the concrete implementation of the DefaultSqlScanner designed
|
|
13
|
+
# to support the customizations of MySQL.
|
|
14
|
+
#
|
|
15
|
+
# @deprecated RUBY-356
|
|
16
|
+
class PostgresSqlScanner < Contrast::Agent::Protect::Rule::Sqli::DefaultSqlScanner
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
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 Protect
|
|
7
|
+
module Rule
|
|
8
|
+
class Sqli
|
|
9
|
+
# This class is the concrete implementation of the DefaultSqlScanner designed
|
|
10
|
+
# to support the customizations of MySQL.
|
|
11
|
+
#
|
|
12
|
+
# @deprecated RUBY-356
|
|
13
|
+
class SqliteSqlScanner < Contrast::Agent::Protect::Rule::Sqli::DefaultSqlScanner
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
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 Protect
|
|
7
|
+
module Rule
|
|
8
|
+
# The Ruby implementation of the Protect Unsafe File Upload rule.
|
|
9
|
+
class UnsafeFileUpload < Contrast::Agent::Protect::Rule::BaseService
|
|
10
|
+
NAME = 'unsafe-file-upload'
|
|
11
|
+
BLOCK_MESSAGE = 'Unsafe file upload rule triggered. Request blocked.'
|
|
12
|
+
|
|
13
|
+
def name
|
|
14
|
+
NAME
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
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 Protect
|
|
7
|
+
module Rule
|
|
8
|
+
# The Ruby implementation of the Protect Cross-Site Scripting rule.
|
|
9
|
+
class Xss < Contrast::Agent::Protect::Rule::BaseService
|
|
10
|
+
NAME = 'reflected-xss'
|
|
11
|
+
BLOCK_MESSAGE = 'XSS rule triggered. Response blocked.'
|
|
12
|
+
|
|
13
|
+
def name
|
|
14
|
+
NAME
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def stream_safe?
|
|
18
|
+
false
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
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/timer'
|
|
5
|
+
|
|
6
|
+
module Contrast
|
|
7
|
+
module Agent
|
|
8
|
+
module Protect
|
|
9
|
+
module Rule
|
|
10
|
+
# Implementation of the XXE Protect Rule used to evaluate XML calls for exploit
|
|
11
|
+
# of unsafe external entity resolution.
|
|
12
|
+
class Xxe < Contrast::Agent::Protect::Rule::Base
|
|
13
|
+
NAME = 'xxe'
|
|
14
|
+
EXPLOIT_CHARACTERS = Contrast::Utils::ObjectShare::EMPTY_ARRAY
|
|
15
|
+
BLOCK_MESSAGE = 'XXE rule triggered. Response blocked.'
|
|
16
|
+
EXTERNAL_ENTITY_PATTERN = /<!ENTITY\s+[a-zA-Z0-f]+\s+(?:SYSTEM|PUBLIC)\s+(.*?)>/.cs__freeze
|
|
17
|
+
|
|
18
|
+
def name
|
|
19
|
+
NAME
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def infilter context, framework, xml
|
|
23
|
+
result = find_attacker(context, xml, framework: framework)
|
|
24
|
+
return nil unless result
|
|
25
|
+
|
|
26
|
+
append_to_activity(context, result)
|
|
27
|
+
return unless blocked?
|
|
28
|
+
|
|
29
|
+
raise Contrast::SecurityException.new(self, BLOCK_MESSAGE)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
protected
|
|
33
|
+
|
|
34
|
+
def find_attacker context, xml, **kwargs
|
|
35
|
+
return nil unless xml
|
|
36
|
+
return nil if protect_excluded_by_code?
|
|
37
|
+
|
|
38
|
+
logger.debug("checking: #{ name } in '#{ kwargs[:framework] }'")
|
|
39
|
+
|
|
40
|
+
xxe_details, last_idx = build_details(xml)
|
|
41
|
+
return nil unless xxe_details
|
|
42
|
+
|
|
43
|
+
# For our definition, the prolog goes from the start of the XML
|
|
44
|
+
# string to the end of the last entity declaration.
|
|
45
|
+
xxe_details.xml = Contrast::Utils::StringUtils.protobuf_safe_string(xml[0, last_idx])
|
|
46
|
+
ia_result = build_evaluation(xxe_details.xml)
|
|
47
|
+
result = build_attack_with_match(
|
|
48
|
+
context,
|
|
49
|
+
ia_result,
|
|
50
|
+
nil,
|
|
51
|
+
nil,
|
|
52
|
+
details: xxe_details)
|
|
53
|
+
|
|
54
|
+
result
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def build_details xml, _evaluation = nil
|
|
58
|
+
last_idx = 0
|
|
59
|
+
ss = StringScanner.new(xml)
|
|
60
|
+
while ss.scan_until(EXTERNAL_ENTITY_PATTERN)
|
|
61
|
+
last_idx = ss.pos
|
|
62
|
+
entity_wrapper = Contrast::Agent::Protect::Rule::Xxe::EntityWrapper.new(ss.matched)
|
|
63
|
+
next unless entity_wrapper.external_entity?
|
|
64
|
+
|
|
65
|
+
xxe_details ||= Contrast::Api::Dtm::XxeDetails.new
|
|
66
|
+
xxe_details.declared_entities << build_match(ss)
|
|
67
|
+
xxe_details.entities_resolved << build_wrapper(entity_wrapper)
|
|
68
|
+
end
|
|
69
|
+
[xxe_details, last_idx]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def build_sample context, ia_result, _url, **kwargs
|
|
73
|
+
sample = build_base_sample(context, ia_result)
|
|
74
|
+
sample.xxe = kwargs[:details]
|
|
75
|
+
sample
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
INPUT_NAME = 'XML Prolog'
|
|
79
|
+
def build_user_input ia_result
|
|
80
|
+
input = Contrast::Api::Dtm::UserInput.new
|
|
81
|
+
input.key = INPUT_NAME
|
|
82
|
+
input.input_type = :UNKNOWN
|
|
83
|
+
input.document_type = :XML
|
|
84
|
+
input.value = ia_result.value
|
|
85
|
+
input
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
# We know that this attack happened, so the result is always matched
|
|
91
|
+
# and the level is always critical. Only variable is the XML value
|
|
92
|
+
# supplied by the attacker.
|
|
93
|
+
def build_evaluation xml
|
|
94
|
+
ia_result = Contrast::Api::Settings::InputAnalysisResult.new
|
|
95
|
+
ia_result.rule_id = name
|
|
96
|
+
ia_result.input_type = :UNKNOWN
|
|
97
|
+
ia_result.value = Contrast::Utils::StringUtils.protobuf_safe_string(xml)
|
|
98
|
+
ia_result
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def build_match string_scanner
|
|
102
|
+
match = Contrast::Api::Dtm::XxeMatch.new
|
|
103
|
+
match.end_idx = string_scanner.pos.to_i
|
|
104
|
+
match.start_idx = match.end_idx - string_scanner.matched_size
|
|
105
|
+
match
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def build_wrapper entity_wrapper
|
|
109
|
+
wrapper = Contrast::Api::Dtm::XxeWrapper.new
|
|
110
|
+
wrapper.system_id = Contrast::Utils::StringUtils.protobuf_safe_string(
|
|
111
|
+
entity_wrapper.system_id)
|
|
112
|
+
wrapper.public_id = Contrast::Utils::StringUtils.protobuf_safe_string(
|
|
113
|
+
entity_wrapper.public_id)
|
|
114
|
+
wrapper
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
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 Protect
|
|
7
|
+
module Rule
|
|
8
|
+
class Xxe
|
|
9
|
+
# A holder for the external entity which was determined to be an
|
|
10
|
+
# attack.
|
|
11
|
+
class EntityWrapper
|
|
12
|
+
attr_reader :system_id, :public_id
|
|
13
|
+
|
|
14
|
+
def initialize entity
|
|
15
|
+
@system_id = parse_system_id(entity)
|
|
16
|
+
# an entity cannot be system and public
|
|
17
|
+
@public_id = parse_public_id(entity) unless @system_id
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def external_entity?
|
|
21
|
+
@_external_entity ||= begin
|
|
22
|
+
return external_id?(@system_id) if @system_id
|
|
23
|
+
return external_id?(@public_id) if @public_id
|
|
24
|
+
|
|
25
|
+
false
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# <!ENTITY name SYSTEM "URI">
|
|
30
|
+
SYSTEM_ID_REGEXP = /<!ENTITY\s+([a-zA-Z0-f]+)\s+SYSTEM\s+"(?<id>.*?)">/.cs__freeze
|
|
31
|
+
def parse_system_id entity
|
|
32
|
+
match = SYSTEM_ID_REGEXP.match(entity)
|
|
33
|
+
match[:id] if match
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# <!ENTITY name PUBLIC "public_ID" "URI">
|
|
37
|
+
PUBLIC_ID_REGEXP = /<!ENTITY\s+([a-zA-Z0-f]+)\s+PUBLIC\s+".*?"\s+"(?<id>.*?)">/.cs__freeze
|
|
38
|
+
def parse_public_id entity
|
|
39
|
+
match = PUBLIC_ID_REGEXP.match(entity)
|
|
40
|
+
match[:id] if match
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
DTD_MARKER = '.dtd'
|
|
44
|
+
FILE_START = 'file:'
|
|
45
|
+
FTP_START = 'ftp:'
|
|
46
|
+
GOPHER_START = 'gopher:'
|
|
47
|
+
JAR_START = 'jar:'
|
|
48
|
+
UP_DIR_LINUX = '../'
|
|
49
|
+
UP_DIR_WIN = '..\\'
|
|
50
|
+
# we only use this against lowercase strings, removed A-Z for speed
|
|
51
|
+
FILE_PATTERN_WINDOWS = /^[\\\\]*[a-z]{1,3}:.*/.cs__freeze
|
|
52
|
+
def external_id? entity_id
|
|
53
|
+
return false unless entity_id
|
|
54
|
+
|
|
55
|
+
# downcase this since we don't have an ignore case compare
|
|
56
|
+
tmp_id = entity_id.to_s.downcase
|
|
57
|
+
|
|
58
|
+
# external if http(s) and not a dtd file
|
|
59
|
+
http = tmp_id.start_with?(Contrast::Utils::ObjectShare::HTTP_START,
|
|
60
|
+
Contrast::Utils::ObjectShare::HTTPS_START)
|
|
61
|
+
return true if http && !tmp_id.end_with?(DTD_MARKER)
|
|
62
|
+
|
|
63
|
+
# external if using external protocol
|
|
64
|
+
return true if tmp_id.start_with?(FTP_START, FILE_START,
|
|
65
|
+
JAR_START, GOPHER_START)
|
|
66
|
+
|
|
67
|
+
# external if start with path marker (/ or .)
|
|
68
|
+
return true if tmp_id.start_with?(Contrast::Utils::ObjectShare::SLASH,
|
|
69
|
+
Contrast::Utils::ObjectShare::PERIOD)
|
|
70
|
+
|
|
71
|
+
# external if start with path up marker (../ or ..\)
|
|
72
|
+
return true if tmp_id.start_with?(UP_DIR_LINUX, UP_DIR_WIN)
|
|
73
|
+
|
|
74
|
+
# external if matches windows file pattern
|
|
75
|
+
tmp_id.match?(FILE_PATTERN_WINDOWS)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|