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.
Files changed (500) hide show
  1. checksums.yaml +7 -0
  2. data/.clang-format +5 -0
  3. data/.dockerignore +10 -0
  4. data/.gitignore +58 -0
  5. data/.gitmodules +6 -0
  6. data/.rspec +6 -0
  7. data/.simplecov +4 -0
  8. data/Gemfile +7 -0
  9. data/LICENSE.txt +12 -0
  10. data/Rakefile +15 -0
  11. data/exe/contrast_service +29 -0
  12. data/ext/build_funchook.rb +48 -0
  13. data/ext/cs__assess_active_record_named/cs__active_record_named.c +47 -0
  14. data/ext/cs__assess_active_record_named/cs__active_record_named.h +10 -0
  15. data/ext/cs__assess_active_record_named/extconf.rb +2 -0
  16. data/ext/cs__assess_array/cs__assess_array.c +38 -0
  17. data/ext/cs__assess_array/cs__assess_array.h +9 -0
  18. data/ext/cs__assess_array/extconf.rb +2 -0
  19. data/ext/cs__assess_basic_object/cs__assess_basic_object.c +50 -0
  20. data/ext/cs__assess_basic_object/cs__assess_basic_object.h +17 -0
  21. data/ext/cs__assess_basic_object/extconf.rb +2 -0
  22. data/ext/cs__assess_fiber_track/cs__assess_fiber_track.c +86 -0
  23. data/ext/cs__assess_fiber_track/cs__assess_fiber_track.h +34 -0
  24. data/ext/cs__assess_fiber_track/extconf.rb +2 -0
  25. data/ext/cs__assess_hash/cs__assess_hash.c +64 -0
  26. data/ext/cs__assess_hash/cs__assess_hash.h +24 -0
  27. data/ext/cs__assess_hash/extconf.rb +2 -0
  28. data/ext/cs__assess_kernel/cs__assess_kernel.c +36 -0
  29. data/ext/cs__assess_kernel/cs__assess_kernel.h +10 -0
  30. data/ext/cs__assess_kernel/extconf.rb +2 -0
  31. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +47 -0
  32. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +18 -0
  33. data/ext/cs__assess_marshal_module/extconf.rb +2 -0
  34. data/ext/cs__assess_module/cs__assess_module.c +78 -0
  35. data/ext/cs__assess_module/cs__assess_module.h +25 -0
  36. data/ext/cs__assess_module/extconf.rb +2 -0
  37. data/ext/cs__assess_regexp/cs__assess_regexp.c +48 -0
  38. data/ext/cs__assess_regexp/cs__assess_regexp.h +22 -0
  39. data/ext/cs__assess_regexp/extconf.rb +2 -0
  40. data/ext/cs__assess_regexp_track/cs__assess_regexp_track.c +63 -0
  41. data/ext/cs__assess_regexp_track/cs__assess_regexp_track.h +29 -0
  42. data/ext/cs__assess_regexp_track/extconf.rb +2 -0
  43. data/ext/cs__assess_string/cs__assess_string.c +38 -0
  44. data/ext/cs__assess_string/cs__assess_string.h +19 -0
  45. data/ext/cs__assess_string/extconf.rb +2 -0
  46. data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.c +31 -0
  47. data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.h +13 -0
  48. data/ext/cs__assess_string_interpolation26/extconf.rb +2 -0
  49. data/ext/cs__common/cs__common.c +60 -0
  50. data/ext/cs__common/cs__common.h +28 -0
  51. data/ext/cs__common/extconf.rb +20 -0
  52. data/ext/cs__contrast_patch/cs__contrast_patch.c +445 -0
  53. data/ext/cs__contrast_patch/cs__contrast_patch.h +196 -0
  54. data/ext/cs__contrast_patch/extconf.rb +2 -0
  55. data/ext/cs__protect_kernel/cs__protect_kernel.c +37 -0
  56. data/ext/cs__protect_kernel/cs__protect_kernel.h +11 -0
  57. data/ext/cs__protect_kernel/extconf.rb +2 -0
  58. data/ext/cs__scope/cs__scope.c +96 -0
  59. data/ext/cs__scope/cs__scope.h +33 -0
  60. data/ext/cs__scope/extconf.rb +2 -0
  61. data/ext/extconf_common.rb +49 -0
  62. data/funchook/LICENSE +360 -0
  63. data/funchook/Makefile +29 -0
  64. data/funchook/Makefile.in +29 -0
  65. data/funchook/README.md +121 -0
  66. data/funchook/appveyor.yml +42 -0
  67. data/funchook/autogen.sh +3 -0
  68. data/funchook/autom4te.cache/output.0 +4976 -0
  69. data/funchook/autom4te.cache/requests +78 -0
  70. data/funchook/autom4te.cache/traces.0 +364 -0
  71. data/funchook/config.guess +1530 -0
  72. data/funchook/config.log +490 -0
  73. data/funchook/config.status +1016 -0
  74. data/funchook/config.sub +1773 -0
  75. data/funchook/configure +4976 -0
  76. data/funchook/configure.ac +59 -0
  77. data/funchook/distorm/COPYING +26 -0
  78. data/funchook/distorm/MANIFEST +25 -0
  79. data/funchook/distorm/MANIFEST.in +4 -0
  80. data/funchook/distorm/README.md +12 -0
  81. data/funchook/distorm/disOps/disOps.py +795 -0
  82. data/funchook/distorm/disOps/x86db.py +404 -0
  83. data/funchook/distorm/disOps/x86header.py +247 -0
  84. data/funchook/distorm/disOps/x86sets.py +1664 -0
  85. data/funchook/distorm/examples/cs/TestdiStorm/Program.cs +79 -0
  86. data/funchook/distorm/examples/cs/TestdiStorm/Properties/AssemblyInfo.cs +36 -0
  87. data/funchook/distorm/examples/cs/TestdiStorm/TestdiStorm.csproj +69 -0
  88. data/funchook/distorm/examples/cs/distorm-net.sln +26 -0
  89. data/funchook/distorm/examples/cs/distorm-net/CodeInfo.cs +23 -0
  90. data/funchook/distorm/examples/cs/distorm-net/DecodedInst.cs +15 -0
  91. data/funchook/distorm/examples/cs/distorm-net/DecodedResult.cs +14 -0
  92. data/funchook/distorm/examples/cs/distorm-net/DecomposedInst.cs +36 -0
  93. data/funchook/distorm/examples/cs/distorm-net/DecomposedResult.cs +14 -0
  94. data/funchook/distorm/examples/cs/distorm-net/Opcodes.cs +1268 -0
  95. data/funchook/distorm/examples/cs/distorm-net/Opcodes.tt +37 -0
  96. data/funchook/distorm/examples/cs/distorm-net/Operand.cs +25 -0
  97. data/funchook/distorm/examples/cs/distorm-net/Properties/AssemblyInfo.cs +36 -0
  98. data/funchook/distorm/examples/cs/distorm-net/diStorm3.cs +411 -0
  99. data/funchook/distorm/examples/cs/distorm-net/distorm-net.csproj +80 -0
  100. data/funchook/distorm/examples/cs/readme +3 -0
  101. data/funchook/distorm/examples/ddk/README +48 -0
  102. data/funchook/distorm/examples/ddk/distorm.ini +11 -0
  103. data/funchook/distorm/examples/ddk/dummy.c +15 -0
  104. data/funchook/distorm/examples/ddk/main.c +91 -0
  105. data/funchook/distorm/examples/ddk/makefile +1 -0
  106. data/funchook/distorm/examples/ddk/sources +10 -0
  107. data/funchook/distorm/examples/java/Makefile +23 -0
  108. data/funchook/distorm/examples/java/distorm/src/Main.java +43 -0
  109. data/funchook/distorm/examples/java/distorm/src/diStorm3/CodeInfo.java +27 -0
  110. data/funchook/distorm/examples/java/distorm/src/diStorm3/DecodedInst.java +32 -0
  111. data/funchook/distorm/examples/java/distorm/src/diStorm3/DecodedResult.java +11 -0
  112. data/funchook/distorm/examples/java/distorm/src/diStorm3/DecomposedInst.java +89 -0
  113. data/funchook/distorm/examples/java/distorm/src/diStorm3/DecomposedResult.java +11 -0
  114. data/funchook/distorm/examples/java/distorm/src/diStorm3/OpcodeEnum.java +131 -0
  115. data/funchook/distorm/examples/java/distorm/src/diStorm3/Opcodes.java +1123 -0
  116. data/funchook/distorm/examples/java/distorm/src/diStorm3/Operand.java +24 -0
  117. data/funchook/distorm/examples/java/distorm/src/diStorm3/distorm3.java +41 -0
  118. data/funchook/distorm/examples/java/jdistorm.c +405 -0
  119. data/funchook/distorm/examples/java/jdistorm.h +40 -0
  120. data/funchook/distorm/examples/java/jdistorm.sln +20 -0
  121. data/funchook/distorm/examples/java/jdistorm.vcproj +208 -0
  122. data/funchook/distorm/examples/linux/Makefile +15 -0
  123. data/funchook/distorm/examples/linux/main.c +181 -0
  124. data/funchook/distorm/examples/tests/Makefile +15 -0
  125. data/funchook/distorm/examples/tests/main.cpp +42 -0
  126. data/funchook/distorm/examples/tests/main.py +66 -0
  127. data/funchook/distorm/examples/tests/test_distorm3.py +1672 -0
  128. data/funchook/distorm/examples/tests/tests.sln +20 -0
  129. data/funchook/distorm/examples/tests/tests.vcxproj +82 -0
  130. data/funchook/distorm/examples/tests/tests.vcxproj.filters +22 -0
  131. data/funchook/distorm/examples/win32/disasm.sln +25 -0
  132. data/funchook/distorm/examples/win32/disasm.vcxproj +201 -0
  133. data/funchook/distorm/examples/win32/disasm.vcxproj.filters +14 -0
  134. data/funchook/distorm/examples/win32/main.cpp +163 -0
  135. data/funchook/distorm/include/distorm.h +482 -0
  136. data/funchook/distorm/include/mnemonics.h +301 -0
  137. data/funchook/distorm/make/linux/Makefile +28 -0
  138. data/funchook/distorm/make/mac/Makefile +24 -0
  139. data/funchook/distorm/make/win32/cdistorm.vcxproj +239 -0
  140. data/funchook/distorm/make/win32/cdistorm.vcxproj.filters +80 -0
  141. data/funchook/distorm/make/win32/distorm.sln +25 -0
  142. data/funchook/distorm/make/win32/resource.h +14 -0
  143. data/funchook/distorm/make/win32/resource.rc +99 -0
  144. data/funchook/distorm/python/distorm3/__init__.py +957 -0
  145. data/funchook/distorm/python/distorm3/sample.py +51 -0
  146. data/funchook/distorm/setup.cfg +10 -0
  147. data/funchook/distorm/setup.py +266 -0
  148. data/funchook/distorm/src/config.h +169 -0
  149. data/funchook/distorm/src/decoder.c +641 -0
  150. data/funchook/distorm/src/decoder.h +33 -0
  151. data/funchook/distorm/src/distorm.c +413 -0
  152. data/funchook/distorm/src/instructions.c +597 -0
  153. data/funchook/distorm/src/instructions.h +463 -0
  154. data/funchook/distorm/src/insts.c +7939 -0
  155. data/funchook/distorm/src/insts.h +64 -0
  156. data/funchook/distorm/src/mnemonics.c +284 -0
  157. data/funchook/distorm/src/operands.c +1290 -0
  158. data/funchook/distorm/src/operands.h +28 -0
  159. data/funchook/distorm/src/prefix.c +368 -0
  160. data/funchook/distorm/src/prefix.h +64 -0
  161. data/funchook/distorm/src/textdefs.c +172 -0
  162. data/funchook/distorm/src/textdefs.h +57 -0
  163. data/funchook/distorm/src/wstring.c +47 -0
  164. data/funchook/distorm/src/wstring.h +35 -0
  165. data/funchook/distorm/src/x86defs.h +82 -0
  166. data/funchook/include/funchook.h +123 -0
  167. data/funchook/install-sh +527 -0
  168. data/funchook/src/Makefile +70 -0
  169. data/funchook/src/Makefile.in +70 -0
  170. data/funchook/src/__strerror.h +109 -0
  171. data/funchook/src/config.h +101 -0
  172. data/funchook/src/config.h.in +100 -0
  173. data/funchook/src/decoder.o +0 -0
  174. data/funchook/src/distorm.o +0 -0
  175. data/funchook/src/funchook.c +440 -0
  176. data/funchook/src/funchook.o +0 -0
  177. data/funchook/src/funchook_internal.h +155 -0
  178. data/funchook/src/funchook_io.c +182 -0
  179. data/funchook/src/funchook_io.h +64 -0
  180. data/funchook/src/funchook_io.o +0 -0
  181. data/funchook/src/funchook_syscall.S +134 -0
  182. data/funchook/src/funchook_syscall.o +0 -0
  183. data/funchook/src/funchook_unix.c +480 -0
  184. data/funchook/src/funchook_unix.o +0 -0
  185. data/funchook/src/funchook_windows.c +397 -0
  186. data/funchook/src/funchook_x86.c +622 -0
  187. data/funchook/src/funchook_x86.o +0 -0
  188. data/funchook/src/instructions.o +0 -0
  189. data/funchook/src/insts.o +0 -0
  190. data/funchook/src/libfunchook.so +0 -0
  191. data/funchook/src/mnemonics.o +0 -0
  192. data/funchook/src/operands.o +0 -0
  193. data/funchook/src/os_func.c +115 -0
  194. data/funchook/src/os_func.h +75 -0
  195. data/funchook/src/os_func.o +0 -0
  196. data/funchook/src/os_func_unix.c +94 -0
  197. data/funchook/src/os_func_unix.o +0 -0
  198. data/funchook/src/os_func_windows.c +32 -0
  199. data/funchook/src/prefix.o +0 -0
  200. data/funchook/src/printf_base.c +1688 -0
  201. data/funchook/src/printf_base.h +46 -0
  202. data/funchook/src/printf_base.o +0 -0
  203. data/funchook/src/textdefs.o +0 -0
  204. data/funchook/src/wstring.o +0 -0
  205. data/funchook/test/Makefile +43 -0
  206. data/funchook/test/Makefile.in +43 -0
  207. data/funchook/test/funchook_test +0 -0
  208. data/funchook/test/libfunchook_test.c +25 -0
  209. data/funchook/test/libfunchook_test.so +0 -0
  210. data/funchook/test/libfunchook_test2.c +18 -0
  211. data/funchook/test/suffix.list +600 -0
  212. data/funchook/test/test_main.c +430 -0
  213. data/funchook/test/test_main.o +0 -0
  214. data/funchook/test/x86_64_test.S +10 -0
  215. data/funchook/test/x86_64_test.o +0 -0
  216. data/funchook/test/x86_test.S +339 -0
  217. data/funchook/win32/config.h +1 -0
  218. data/funchook/win32/funchook.sln +52 -0
  219. data/funchook/win32/funchook.vcxproj +188 -0
  220. data/funchook/win32/funchook.vcxproj.filters +84 -0
  221. data/funchook/win32/funchook_test.vcxproj +170 -0
  222. data/funchook/win32/funchook_test.vcxproj.filters +22 -0
  223. data/funchook/win32/funchook_test_dll.vcxproj +184 -0
  224. data/funchook/win32/funchook_test_dll.vcxproj.filters +30 -0
  225. data/funchook/win32/funchook_test_exe.def +3 -0
  226. data/lib/contrast-agent.rb +8 -0
  227. data/lib/contrast.rb +57 -0
  228. data/lib/contrast/agent.rb +80 -0
  229. data/lib/contrast/agent/assess.rb +45 -0
  230. data/lib/contrast/agent/assess/adjusted_span.rb +25 -0
  231. data/lib/contrast/agent/assess/class_reverter.rb +82 -0
  232. data/lib/contrast/agent/assess/contrast_event.rb +398 -0
  233. data/lib/contrast/agent/assess/frozen_properties.rb +41 -0
  234. data/lib/contrast/agent/assess/insulator.rb +53 -0
  235. data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +78 -0
  236. data/lib/contrast/agent/assess/policy/patcher.rb +85 -0
  237. data/lib/contrast/agent/assess/policy/policy.rb +116 -0
  238. data/lib/contrast/agent/assess/policy/policy_node.rb +289 -0
  239. data/lib/contrast/agent/assess/policy/policy_scanner.rb +44 -0
  240. data/lib/contrast/agent/assess/policy/preshift.rb +94 -0
  241. data/lib/contrast/agent/assess/policy/propagation_method.rb +260 -0
  242. data/lib/contrast/agent/assess/policy/propagation_node.rb +127 -0
  243. data/lib/contrast/agent/assess/policy/propagator.rb +35 -0
  244. data/lib/contrast/agent/assess/policy/propagator/append.rb +54 -0
  245. data/lib/contrast/agent/assess/policy/propagator/base.rb +37 -0
  246. data/lib/contrast/agent/assess/policy/propagator/center.rb +73 -0
  247. data/lib/contrast/agent/assess/policy/propagator/custom.rb +36 -0
  248. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +62 -0
  249. data/lib/contrast/agent/assess/policy/propagator/insert.rb +55 -0
  250. data/lib/contrast/agent/assess/policy/propagator/keep.rb +26 -0
  251. data/lib/contrast/agent/assess/policy/propagator/next.rb +42 -0
  252. data/lib/contrast/agent/assess/policy/propagator/prepend.rb +50 -0
  253. data/lib/contrast/agent/assess/policy/propagator/remove.rb +76 -0
  254. data/lib/contrast/agent/assess/policy/propagator/replace.rb +27 -0
  255. data/lib/contrast/agent/assess/policy/propagator/reverse.rb +38 -0
  256. data/lib/contrast/agent/assess/policy/propagator/select.rb +86 -0
  257. data/lib/contrast/agent/assess/policy/propagator/splat.rb +60 -0
  258. data/lib/contrast/agent/assess/policy/propagator/split.rb +49 -0
  259. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +169 -0
  260. data/lib/contrast/agent/assess/policy/propagator/trim.rb +81 -0
  261. data/lib/contrast/agent/assess/policy/rewriter_patch.rb +79 -0
  262. data/lib/contrast/agent/assess/policy/source_method.rb +209 -0
  263. data/lib/contrast/agent/assess/policy/source_node.rb +62 -0
  264. data/lib/contrast/agent/assess/policy/trigger_method.rb +209 -0
  265. data/lib/contrast/agent/assess/policy/trigger_node.rb +198 -0
  266. data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +77 -0
  267. data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +31 -0
  268. data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +40 -0
  269. data/lib/contrast/agent/assess/properties.rb +392 -0
  270. data/lib/contrast/agent/assess/rule.rb +18 -0
  271. data/lib/contrast/agent/assess/rule/base.rb +72 -0
  272. data/lib/contrast/agent/assess/rule/csrf.rb +66 -0
  273. data/lib/contrast/agent/assess/rule/csrf/csrf_action.rb +28 -0
  274. data/lib/contrast/agent/assess/rule/csrf/csrf_applicator.rb +69 -0
  275. data/lib/contrast/agent/assess/rule/csrf/csrf_watcher.rb +132 -0
  276. data/lib/contrast/agent/assess/rule/provider.rb +21 -0
  277. data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +62 -0
  278. data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +73 -0
  279. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +121 -0
  280. data/lib/contrast/agent/assess/rule/redos.rb +68 -0
  281. data/lib/contrast/agent/assess/rule/response_scanning_rule.rb +47 -0
  282. data/lib/contrast/agent/assess/rule/response_watcher.rb +36 -0
  283. data/lib/contrast/agent/assess/rule/watcher.rb +36 -0
  284. data/lib/contrast/agent/assess/tag.rb +151 -0
  285. data/lib/contrast/agent/at_exit_hook.rb +33 -0
  286. data/lib/contrast/agent/class_reopener.rb +195 -0
  287. data/lib/contrast/agent/deadzone/policy/deadzone_node.rb +26 -0
  288. data/lib/contrast/agent/deadzone/policy/policy.rb +57 -0
  289. data/lib/contrast/agent/disable_reaction.rb +24 -0
  290. data/lib/contrast/agent/exclusion_matcher.rb +190 -0
  291. data/lib/contrast/agent/feature_state.rb +379 -0
  292. data/lib/contrast/agent/inventory/policy/policy.rb +32 -0
  293. data/lib/contrast/agent/inventory/policy/trigger_node.rb +22 -0
  294. data/lib/contrast/agent/logger_manager.rb +116 -0
  295. data/lib/contrast/agent/middleware.rb +352 -0
  296. data/lib/contrast/agent/module_data.rb +16 -0
  297. data/lib/contrast/agent/patching/policy/after_load_patch.rb +37 -0
  298. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +58 -0
  299. data/lib/contrast/agent/patching/policy/method_policy.rb +94 -0
  300. data/lib/contrast/agent/patching/policy/module_policy.rb +116 -0
  301. data/lib/contrast/agent/patching/policy/patch.rb +312 -0
  302. data/lib/contrast/agent/patching/policy/patch_status.rb +192 -0
  303. data/lib/contrast/agent/patching/policy/patcher.rb +310 -0
  304. data/lib/contrast/agent/patching/policy/policy.rb +138 -0
  305. data/lib/contrast/agent/patching/policy/policy_node.rb +80 -0
  306. data/lib/contrast/agent/patching/policy/policy_unpatcher.rb +28 -0
  307. data/lib/contrast/agent/patching/policy/trigger_node.rb +81 -0
  308. data/lib/contrast/agent/protect/policy/policy.rb +37 -0
  309. data/lib/contrast/agent/protect/policy/trigger_node.rb +23 -0
  310. data/lib/contrast/agent/protect/rule.rb +58 -0
  311. data/lib/contrast/agent/protect/rule/base.rb +300 -0
  312. data/lib/contrast/agent/protect/rule/base_service.rb +88 -0
  313. data/lib/contrast/agent/protect/rule/cmd_injection.rb +156 -0
  314. data/lib/contrast/agent/protect/rule/csrf.rb +118 -0
  315. data/lib/contrast/agent/protect/rule/csrf/csrf_evaluator.rb +103 -0
  316. data/lib/contrast/agent/protect/rule/csrf/csrf_token_injector.rb +85 -0
  317. data/lib/contrast/agent/protect/rule/default_scanner.rb +300 -0
  318. data/lib/contrast/agent/protect/rule/deserialization.rb +193 -0
  319. data/lib/contrast/agent/protect/rule/http_method_tampering.rb +80 -0
  320. data/lib/contrast/agent/protect/rule/no_sqli.rb +101 -0
  321. data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +40 -0
  322. data/lib/contrast/agent/protect/rule/path_traversal.rb +143 -0
  323. data/lib/contrast/agent/protect/rule/sqli.rb +101 -0
  324. data/lib/contrast/agent/protect/rule/sqli/default_sql_scanner.rb +16 -0
  325. data/lib/contrast/agent/protect/rule/sqli/mysql_sql_scanner.rb +38 -0
  326. data/lib/contrast/agent/protect/rule/sqli/postgres_sql_scanner.rb +22 -0
  327. data/lib/contrast/agent/protect/rule/sqli/sqlite_sql_scanner.rb +19 -0
  328. data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +20 -0
  329. data/lib/contrast/agent/protect/rule/xss.rb +24 -0
  330. data/lib/contrast/agent/protect/rule/xxe.rb +120 -0
  331. data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +82 -0
  332. data/lib/contrast/agent/railtie.rb +30 -0
  333. data/lib/contrast/agent/reaction_processor.rb +47 -0
  334. data/lib/contrast/agent/request.rb +493 -0
  335. data/lib/contrast/agent/request_context.rb +225 -0
  336. data/lib/contrast/agent/require_state.rb +61 -0
  337. data/lib/contrast/agent/response.rb +215 -0
  338. data/lib/contrast/agent/rewriter.rb +244 -0
  339. data/lib/contrast/agent/scope.rb +28 -0
  340. data/lib/contrast/agent/service_heartbeat.rb +37 -0
  341. data/lib/contrast/agent/settings_state.rb +148 -0
  342. data/lib/contrast/agent/socket_client.rb +125 -0
  343. data/lib/contrast/agent/thread.rb +26 -0
  344. data/lib/contrast/agent/tracepoint_hook.rb +51 -0
  345. data/lib/contrast/agent/version.rb +8 -0
  346. data/lib/contrast/api.rb +17 -0
  347. data/lib/contrast/api/.gitkeep +0 -0
  348. data/lib/contrast/api/connection_status.rb +49 -0
  349. data/lib/contrast/api/socket.rb +43 -0
  350. data/lib/contrast/api/speedracer.rb +206 -0
  351. data/lib/contrast/api/tcp_socket.rb +31 -0
  352. data/lib/contrast/api/unix_socket.rb +25 -0
  353. data/lib/contrast/common_agent_configuration.rb +86 -0
  354. data/lib/contrast/components/agent.rb +85 -0
  355. data/lib/contrast/components/app_context.rb +188 -0
  356. data/lib/contrast/components/assess.rb +67 -0
  357. data/lib/contrast/components/config.rb +135 -0
  358. data/lib/contrast/components/contrast_service.rb +113 -0
  359. data/lib/contrast/components/heap_dump.rb +34 -0
  360. data/lib/contrast/components/interface.rb +178 -0
  361. data/lib/contrast/components/inventory.rb +23 -0
  362. data/lib/contrast/components/logger.rb +92 -0
  363. data/lib/contrast/components/protect.rb +38 -0
  364. data/lib/contrast/components/sampling.rb +41 -0
  365. data/lib/contrast/components/scope.rb +106 -0
  366. data/lib/contrast/components/settings.rb +140 -0
  367. data/lib/contrast/config.rb +33 -0
  368. data/lib/contrast/config/agent_configuration.rb +24 -0
  369. data/lib/contrast/config/application_configuration.rb +27 -0
  370. data/lib/contrast/config/assess_configuration.rb +22 -0
  371. data/lib/contrast/config/assess_rules_configuration.rb +18 -0
  372. data/lib/contrast/config/base_configuration.rb +105 -0
  373. data/lib/contrast/config/default_value.rb +16 -0
  374. data/lib/contrast/config/exception_configuration.rb +21 -0
  375. data/lib/contrast/config/heap_dump_configuration.rb +23 -0
  376. data/lib/contrast/config/inventory_configuration.rb +20 -0
  377. data/lib/contrast/config/logger_configuration.rb +20 -0
  378. data/lib/contrast/config/protect_configuration.rb +20 -0
  379. data/lib/contrast/config/protect_rule_configuration.rb +37 -0
  380. data/lib/contrast/config/protect_rules_configuration.rb +30 -0
  381. data/lib/contrast/config/root_configuration.rb +26 -0
  382. data/lib/contrast/config/ruby_configuration.rb +39 -0
  383. data/lib/contrast/config/sampling_configuration.rb +22 -0
  384. data/lib/contrast/config/server_configuration.rb +23 -0
  385. data/lib/contrast/config/service_configuration.rb +22 -0
  386. data/lib/contrast/configuration.rb +214 -0
  387. data/lib/contrast/core_extensions/assess.rb +51 -0
  388. data/lib/contrast/core_extensions/assess/array.rb +58 -0
  389. data/lib/contrast/core_extensions/assess/assess_extension.rb +145 -0
  390. data/lib/contrast/core_extensions/assess/basic_object.rb +15 -0
  391. data/lib/contrast/core_extensions/assess/erb.rb +42 -0
  392. data/lib/contrast/core_extensions/assess/exec_trigger.rb +48 -0
  393. data/lib/contrast/core_extensions/assess/fiber.rb +125 -0
  394. data/lib/contrast/core_extensions/assess/hash.rb +22 -0
  395. data/lib/contrast/core_extensions/assess/kernel.rb +95 -0
  396. data/lib/contrast/core_extensions/assess/module.rb +14 -0
  397. data/lib/contrast/core_extensions/assess/regexp.rb +206 -0
  398. data/lib/contrast/core_extensions/assess/string.rb +75 -0
  399. data/lib/contrast/core_extensions/assess/tilt_template_trigger.rb +73 -0
  400. data/lib/contrast/core_extensions/delegator.rb +14 -0
  401. data/lib/contrast/core_extensions/eval_trigger.rb +52 -0
  402. data/lib/contrast/core_extensions/inventory.rb +22 -0
  403. data/lib/contrast/core_extensions/inventory/datastores.rb +37 -0
  404. data/lib/contrast/core_extensions/module.rb +42 -0
  405. data/lib/contrast/core_extensions/object.rb +27 -0
  406. data/lib/contrast/core_extensions/protect.rb +20 -0
  407. data/lib/contrast/core_extensions/protect/applies_command_injection_rule.rb +70 -0
  408. data/lib/contrast/core_extensions/protect/applies_deserialization_rule.rb +58 -0
  409. data/lib/contrast/core_extensions/protect/applies_no_sqli_rule.rb +81 -0
  410. data/lib/contrast/core_extensions/protect/applies_path_traversal_rule.rb +119 -0
  411. data/lib/contrast/core_extensions/protect/applies_sqli_rule.rb +63 -0
  412. data/lib/contrast/core_extensions/protect/applies_xxe_rule.rb +141 -0
  413. data/lib/contrast/core_extensions/protect/kernel.rb +30 -0
  414. data/lib/contrast/core_extensions/protect/psych.rb +7 -0
  415. data/lib/contrast/core_extensions/thread.rb +31 -0
  416. data/lib/contrast/internal_exception.rb +8 -0
  417. data/lib/contrast/rails_extensions/assess/action_controller_inheritance.rb +48 -0
  418. data/lib/contrast/rails_extensions/assess/active_record.rb +32 -0
  419. data/lib/contrast/rails_extensions/assess/active_record_named.rb +61 -0
  420. data/lib/contrast/rails_extensions/assess/configuration.rb +26 -0
  421. data/lib/contrast/rails_extensions/buffer.rb +30 -0
  422. data/lib/contrast/rails_extensions/rack.rb +45 -0
  423. data/lib/contrast/security_exception.rb +14 -0
  424. data/lib/contrast/sinatra_extensions/assess/cookie.rb +26 -0
  425. data/lib/contrast/sinatra_extensions/inventory/sinatra_base.rb +59 -0
  426. data/lib/contrast/tasks/service.rb +95 -0
  427. data/lib/contrast/utils/assess/sampling_util.rb +96 -0
  428. data/lib/contrast/utils/assess/tracking_util.rb +39 -0
  429. data/lib/contrast/utils/boolean_util.rb +33 -0
  430. data/lib/contrast/utils/cache.rb +69 -0
  431. data/lib/contrast/utils/class_util.rb +58 -0
  432. data/lib/contrast/utils/comment_range.rb +19 -0
  433. data/lib/contrast/utils/data_store_util.rb +23 -0
  434. data/lib/contrast/utils/duck_utils.rb +58 -0
  435. data/lib/contrast/utils/env_configuration_item.rb +52 -0
  436. data/lib/contrast/utils/environment_util.rb +152 -0
  437. data/lib/contrast/utils/freeze_util.rb +36 -0
  438. data/lib/contrast/utils/gemfile_reader.rb +191 -0
  439. data/lib/contrast/utils/hash_digest.rb +148 -0
  440. data/lib/contrast/utils/heap_dump_util.rb +113 -0
  441. data/lib/contrast/utils/invalid_configuration_util.rb +88 -0
  442. data/lib/contrast/utils/inventory_util.rb +126 -0
  443. data/lib/contrast/utils/io_util.rb +61 -0
  444. data/lib/contrast/utils/object_share.rb +117 -0
  445. data/lib/contrast/utils/operating_environment.rb +38 -0
  446. data/lib/contrast/utils/os.rb +49 -0
  447. data/lib/contrast/utils/path_util.rb +151 -0
  448. data/lib/contrast/utils/performs_logging.rb +152 -0
  449. data/lib/contrast/utils/preflight_util.rb +13 -0
  450. data/lib/contrast/utils/prevent_serialization.rb +52 -0
  451. data/lib/contrast/utils/rack_assess_session_cookie.rb +104 -0
  452. data/lib/contrast/utils/rails_assess_configuration.rb +95 -0
  453. data/lib/contrast/utils/random_util.rb +22 -0
  454. data/lib/contrast/utils/resource_loader.rb +23 -0
  455. data/lib/contrast/utils/ruby_ast_rewriter.rb +74 -0
  456. data/lib/contrast/utils/scope_util.rb +99 -0
  457. data/lib/contrast/utils/service_response_util.rb +116 -0
  458. data/lib/contrast/utils/service_sender_util.rb +98 -0
  459. data/lib/contrast/utils/sha256_builder.rb +69 -0
  460. data/lib/contrast/utils/sinatra_helper.rb +49 -0
  461. data/lib/contrast/utils/stack_trace_utils.rb +209 -0
  462. data/lib/contrast/utils/string_utils.rb +72 -0
  463. data/lib/contrast/utils/tag_util.rb +139 -0
  464. data/lib/contrast/utils/thread_tracker.rb +54 -0
  465. data/lib/contrast/utils/timer.rb +78 -0
  466. data/resources/assess/policy.json +1673 -0
  467. data/resources/csrf/inject.js +44 -0
  468. data/resources/deadzone/policy.json +55 -0
  469. data/resources/factory-bot-spec/spec_helper.rb +30 -0
  470. data/resources/inventory/policy.json +110 -0
  471. data/resources/protect/policy.json +417 -0
  472. data/resources/rubocops/kernel/catch_cop.rb +37 -0
  473. data/resources/rubocops/kernel/require_cop.rb +37 -0
  474. data/resources/rubocops/kernel/require_relative_cop.rb +33 -0
  475. data/resources/rubocops/module/autoload_cop.rb +37 -0
  476. data/resources/rubocops/module/const_defined_cop.rb +37 -0
  477. data/resources/rubocops/module/const_get_cop.rb +37 -0
  478. data/resources/rubocops/module/const_set_cop.rb +37 -0
  479. data/resources/rubocops/module/constants_cop.rb +37 -0
  480. data/resources/rubocops/module/name_cop.rb +37 -0
  481. data/resources/rubocops/object/class_cop.rb +37 -0
  482. data/resources/rubocops/object/freeze_cop.rb +37 -0
  483. data/resources/rubocops/object/frozen_cop.rb +37 -0
  484. data/resources/rubocops/object/is_a_cop.rb +37 -0
  485. data/resources/rubocops/object/method_cop.rb +37 -0
  486. data/resources/rubocops/object/respond_to_cop.rb +37 -0
  487. data/resources/rubocops/object/singleton_class_cop.rb +37 -0
  488. data/resources/rubocops/regexp/spelling_cop.rb +44 -0
  489. data/resources/rubocops/thread/new_cop.rb +39 -0
  490. data/resources/ruby-spec/ancestors_spec.rb +70 -0
  491. data/resources/ruby-spec/modulo_spec.rb +831 -0
  492. data/resources/ruby-spec/parameters_spec.rb +261 -0
  493. data/resources/ruby-spec/ruby_spec_spec_helper.rb +35 -0
  494. data/resources/test_marker.txt +1 -0
  495. data/ruby-agent.gemspec +129 -0
  496. data/service_executables/.gitkeep +0 -0
  497. data/service_executables/VERSION +1 -0
  498. data/service_executables/linux/contrast-service +0 -0
  499. data/service_executables/mac/contrast-service +0 -0
  500. metadata +945 -0
@@ -0,0 +1,33 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ cs__scoped_require 'contrast/components/interface'
5
+
6
+ module Contrast
7
+ module Agent
8
+ # This module adds an at_exit hook for us to send messages that may be lost at process exit
9
+ module AtExitHook
10
+ include Contrast::Components::Interface
11
+ access_component :logging, :contrast_service
12
+
13
+ TERMINATION_NOTICE = 'at_exit invoked, host application terminating'
14
+
15
+ def self.exit_hook
16
+ @_exit_hook ||= begin
17
+ at_exit do
18
+ logger.debug(TERMINATION_NOTICE)
19
+
20
+ context = Contrast::Agent::REQUEST_TRACKER.current
21
+ CONTRAST_SERVICE.send_message(context.activity) if context
22
+
23
+ logger.debug(" - current PID #{ @pid }")
24
+ logger.debug(" - current PPID #{ @ppid }")
25
+ logger.debug(" - process PID #{ Process.pid }")
26
+ logger.debug(" - process PPID #{ Process.ppid }")
27
+ end
28
+ true
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,195 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: false
3
+
4
+ cs__scoped_require 'ripper'
5
+ cs__scoped_require 'contrast/core_extensions/module'
6
+ cs__scoped_require 'contrast/components/interface'
7
+
8
+ # This method is left purposefully at the top level namespace. Moving it
9
+ # elsewhere will break functionality as it executes evaluations against the
10
+ # namespace from which it is called -- ie putting it in Contrast would make all
11
+ # changes it intends for Foo happen to Contrast::Foo instead
12
+ #
13
+ # @param class_name [String] the name of the class in which the eval will
14
+ # redefine functionality
15
+ # @param content [String] the String content that will function as the code in
16
+ # the given class
17
+ def unbound_eval class_name, content
18
+ # Yuck, this is a top-level method that has to break encapsulation
19
+ # in order to access scoping!
20
+ Contrast::Components::Scope::COMPONENT_INTERFACE.scope_for_current_ec.enter_contrast_scope
21
+ eval(content) # rubocop:disable Security/Eval
22
+ rescue Exception # rubocop:disable Lint/RescueException
23
+ Contrast::Agent::SettingsState.log_error("Unable to perform unbound eval of new content for #{ class_name }.")
24
+ ensure
25
+ Contrast::Components::Scope::COMPONENT_INTERFACE.scope_for_current_ec.exit_contrast_scope
26
+ end
27
+
28
+ module Contrast
29
+ module Agent
30
+ # Used for Ruby 2.4 & 2.5 to allow us to rewrite those methods which have
31
+ # interpolation in them.
32
+ # @deprecated Changes to this class are discouraged as this approach is
33
+ # being phased out with support for those language versions.
34
+ class ClassReopener
35
+ END_NEW_LINE = "end\n".cs__freeze
36
+ PROTECTED_WITH_NEW_LINE = "protected\n".cs__freeze
37
+ PRIVATE_WITH_NEW_LINE = "private\n".cs__freeze
38
+ CLASS_SELF_LINE = "class << self\n".cs__freeze
39
+
40
+ attr_reader :public_singleton_methods, :class_module_path, :class_name, :files, :is_class, :name_space,
41
+ :public_instance_methods, :protected_instance_methods, :private_instance_methods, :locations
42
+
43
+ def initialize module_data
44
+ @class_module_path = module_data.name
45
+ clazz = module_data.mod
46
+ @is_class = clazz.is_a?(Class)
47
+ @public_instance_methods = []
48
+ @protected_instance_methods = []
49
+ @private_instance_methods = []
50
+ @public_singleton_methods = []
51
+ @files = {}
52
+ @name_space = []
53
+ @class_name = nil
54
+ @locations = Hash.new { |h, k| h[k] = [] }
55
+ gather_modules
56
+ end
57
+
58
+ def gather_modules
59
+ return if class_module_path.nil?
60
+
61
+ segments = class_module_path.split(Contrast::Utils::ObjectShare::DOUBLE_COLON)
62
+ @class_name = segments.last
63
+ current = nil
64
+ segments[0..-2].each do |chunk|
65
+ defined = current ? current.cs__const_defined?(chunk) : Module.cs__const_defined?(chunk)
66
+ next unless defined
67
+
68
+ current = current ? current.cs__const_get(chunk) : Module.cs__const_get(chunk)
69
+ if current.is_a?(Class)
70
+ name_space << [chunk, Class]
71
+ elsif current.is_a?(Module)
72
+ name_space << [chunk, Module]
73
+ end
74
+ end
75
+ end
76
+
77
+ def staged_changes?
78
+ public_singleton_methods.any? ||
79
+ public_instance_methods.any? ||
80
+ protected_instance_methods.any? ||
81
+ private_instance_methods.any?
82
+ end
83
+
84
+ def written_from_location? source_location
85
+ return false unless source_location
86
+
87
+ file = source_location[0]
88
+ location = source_location[1]
89
+ locs = locations[file]
90
+ return true if locs.include?(location)
91
+
92
+ locs << location
93
+ false
94
+ end
95
+
96
+ def commit_patches
97
+ return unless staged_changes?
98
+
99
+ content = build_content
100
+ valid = Ripper.sexp(content)
101
+ unbound_eval(class_name, content) if !!valid && !class_name.empty?
102
+ end
103
+
104
+ def source_code location, method_name
105
+ file_name = location[0]
106
+ line_number = location[1]
107
+ return unless file_name && line_number
108
+
109
+ unless files.key?(file_name)
110
+ return unless File.exist?(file_name)
111
+
112
+ files[file_name] = File.readlines(file_name)
113
+ end
114
+
115
+ lines = files[file_name]
116
+
117
+ old_verbose = $VERBOSE
118
+ $VERBOSE = nil
119
+ code = ''
120
+ complete = false
121
+ # location#line_number is 1 based, arrays are 0 based
122
+ line_number -= 1
123
+ lines[line_number..-1].each do |line|
124
+ begin
125
+ code << line
126
+ RubyVM::InstructionSequence.compile(code) # this will raise SyntaxError for malformed code
127
+ # Assert that a line which ends with a , or \ is incomplete.
128
+ complete = code !~ /[,\\]\s*\z/
129
+ break if complete
130
+ rescue SyntaxError
131
+ code.gsub(/\#\{.*?\}/, 'temp')
132
+ end
133
+ end
134
+ $VERBOSE = old_verbose
135
+ raise SyntaxError, "Failure: method #{ method_name } in #{ file_name } at #{ line_number }" unless complete
136
+
137
+ code
138
+ end
139
+
140
+ private
141
+
142
+ def build_content
143
+ content = ''
144
+ name_space.each do |arr|
145
+ name = arr[0]
146
+ type = arr[1]
147
+ if type == Class
148
+ content << "class #{ name }\n"
149
+ elsif type == Module
150
+ content << "module #{ name }\n"
151
+ end
152
+ end
153
+
154
+ # Set the name to be a class or module
155
+ content << if is_class
156
+ "class #{ class_name }\n"
157
+ else
158
+ "module #{ class_name }\n"
159
+ end
160
+
161
+ # Recreate the updated class methods
162
+ if public_singleton_methods.any?
163
+ content << CLASS_SELF_LINE
164
+ content << public_singleton_methods.join(Contrast::Utils::ObjectShare::NEW_LINE)
165
+ content << Contrast::Utils::ObjectShare::NEW_LINE
166
+ content << END_NEW_LINE
167
+ end
168
+
169
+ # Recreate the updated instance methods
170
+ if public_instance_methods.any?
171
+ content << public_instance_methods.join(Contrast::Utils::ObjectShare::NEW_LINE)
172
+ content << Contrast::Utils::ObjectShare::NEW_LINE
173
+ end
174
+
175
+ if protected_instance_methods.any?
176
+ content << PROTECTED_WITH_NEW_LINE
177
+ content << protected_instance_methods.join(Contrast::Utils::ObjectShare::NEW_LINE)
178
+ content << Contrast::Utils::ObjectShare::NEW_LINE
179
+ end
180
+
181
+ if private_instance_methods.any?
182
+ content << PRIVATE_WITH_NEW_LINE
183
+ content << private_instance_methods.join(Contrast::Utils::ObjectShare::NEW_LINE)
184
+ content << Contrast::Utils::ObjectShare::NEW_LINE
185
+ end
186
+
187
+ content << END_NEW_LINE
188
+ name_space.length.times do
189
+ content << END_NEW_LINE
190
+ end
191
+ content
192
+ end
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ cs__scoped_require 'contrast/agent/patching/policy/policy_node'
5
+
6
+ module Contrast
7
+ module Agent
8
+ module Deadzone
9
+ module Policy
10
+ # This class functions to translate our policy.json into an actionable
11
+ # Ruby object, allowing for dynamic patching over hardcoded patching,
12
+ # specifically for those methods in which other Contrast operations
13
+ # should not apply
14
+ class DeadzoneNode < Contrast::Agent::Patching::Policy::PolicyNode
15
+ def node_class
16
+ 'Deadzone'
17
+ end
18
+
19
+ def feature
20
+ 'Deadzone'
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,57 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ cs__scoped_require 'contrast/agent/deadzone/policy/deadzone_node'
5
+ cs__scoped_require 'contrast/agent/patching/policy/policy'
6
+
7
+ module Contrast
8
+ module Agent
9
+ module Deadzone
10
+ module Policy
11
+ # This is just a holder for our policy. Takes the policy JSON and
12
+ # converts it into hashes that we can access nicely
13
+ class Policy < Contrast::Agent::Patching::Policy::Policy
14
+ def self.policy_folder
15
+ 'deadzone'
16
+ end
17
+
18
+ DEADZONES_KEY = 'deadzones'
19
+ attr_reader :deadzones
20
+
21
+ def initialize
22
+ @deadzones = []
23
+ super
24
+ end
25
+
26
+ def node_type
27
+ Contrast::Agent::Deadzone::Policy::DeadzoneNode
28
+ end
29
+
30
+ def from_hash_string string
31
+ policy_data = JSON.parse(string)
32
+
33
+ policy_data[DEADZONES_KEY].each do |deadzone_hash|
34
+ add_node(node_type.new(deadzone_hash))
35
+ end
36
+ end
37
+
38
+ def add_node node, _node_type = :deadzones
39
+ unless node
40
+ logger.error(nil, 'Node was nil when adding node to policy')
41
+ return
42
+ end
43
+
44
+ begin
45
+ node.validate
46
+ rescue ArgumentError => e
47
+ logger.error(e, e.message)
48
+ return
49
+ end
50
+
51
+ @deadzones << node
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ 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
+ cs__scoped_require 'contrast/components/interface'
5
+
6
+ module Contrast
7
+ module Agent
8
+ # A Reaction from TeamServer which indicates the Agent should be disabled,
9
+ # typically because some configuration setting did not satisfy requirements
10
+ # set by the Organization's Administrator
11
+ class DisableReaction
12
+ include Contrast::Components::Interface
13
+ access_component :logging, :agent
14
+
15
+ def self.run _reaction, level
16
+ logger.with_level(
17
+ nil,
18
+ 'Contrast received instructions to disable itself - Disabling now',
19
+ level)
20
+ AGENT.disable!
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,190 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ cs__scoped_require 'contrast/components/interface'
5
+
6
+ module Contrast
7
+ module Agent
8
+ # Exclusions are ways for the User to tell the Agent to ignore sections of
9
+ # the Application. If a request or an event matches one of these, the
10
+ # functions of the Agent are suppressed for that request or event.
11
+ class ExclusionMatcher
12
+ include Contrast::Components::Interface
13
+ access_component :logging
14
+
15
+ def initialize excl
16
+ @exclusion = excl
17
+ @protect = @exclusion.protect
18
+ @assess = @exclusion.assess
19
+
20
+ handle_wildcard_input
21
+ handle_wildcard_url
22
+ handle_wildcard_code
23
+ end
24
+
25
+ # According to the docs for exclusions, user input applies to all inputs if
26
+ # the name supplied is an '*' or '.*'. The name matcher does NOT support
27
+ # regexp beyond this.
28
+ # https://docs.contrastsecurity.com/admin-policymgmt.html#exclude
29
+ def handle_wildcard_input
30
+ return unless @exclusion.input_name
31
+
32
+ @wildcard_input = @exclusion.input_name == '.*' ||
33
+ @exclusion.input_name == Contrast::Utils::ObjectShare::ASTERISK
34
+ end
35
+
36
+ # According to the docs for exclusions, urls apply to all urls if the url
37
+ # supplied is '/.*' or if the URL mode is all. Otherwise, the URL supplied is
38
+ # to be treated as a regular expression that must match the entire URL
39
+ # against which it is tested.
40
+ # https://docs.contrastsecurity.com/admin-policymgmt.html#exclude
41
+ def handle_wildcard_url
42
+ @wildcard_url = match_all?
43
+ return if @wildcard_url
44
+ return unless @exclusion.urls&.any?
45
+
46
+ @wildcard_url ||= @exclusion.urls.any? { |test| test == '/.*' }
47
+ return if @wildcard_url
48
+
49
+ @urls = []
50
+ @exclusion.urls.each do |url|
51
+ url_pattern = build_regexp(url, true, true)
52
+ @urls << url_pattern if url_pattern
53
+ end
54
+ end
55
+
56
+ # According to the docs for exclusions, code applies to the entire stacktrace
57
+ # of the caller, and can act as a regexp. Per our user instructions in the
58
+ # Contrast UI, these comparisons must be done at the end of the input.
59
+ # https://docs.contrastsecurity.com/admin-policymgmt.html#exclude
60
+ def handle_wildcard_code
61
+ return unless @exclusion.blacklist&.any?
62
+
63
+ @wildcard_exclusions = []
64
+ @exclusion.blacklist.each do |code|
65
+ class_name, method_name = code.split(Contrast::Utils::ObjectShare::COLON)
66
+ class_pattern = build_regexp(class_name, false, true)
67
+ method_pattern = build_regexp(method_name)
68
+ next unless class_pattern && method_pattern
69
+
70
+ @wildcard_exclusions << [class_pattern, method_pattern]
71
+ end
72
+ end
73
+
74
+ def build_regexp pattern, start_anchor = false, end_anchor = false
75
+ pattern = Contrast::Utils::ObjectShare::CARROT + pattern if start_anchor
76
+ pattern += Contrast::Utils::ObjectShare::DOLLAR_SIGN if end_anchor
77
+ Regexp.compile(pattern)
78
+ rescue RegexpError => e
79
+ logger.error(e, "Unable to generate a pattern for #{ pattern }. It will not be used for exclusion matching.")
80
+ end
81
+
82
+ def protect?
83
+ @protect
84
+ end
85
+
86
+ def assess?
87
+ @assess
88
+ end
89
+
90
+ def url?
91
+ @exclusion.type == :URL
92
+ end
93
+
94
+ def input?
95
+ @exclusion.type == :INPUT
96
+ end
97
+
98
+ def code?
99
+ @exclusion.type == :CODE
100
+ end
101
+
102
+ def name
103
+ @exclusion.name
104
+ end
105
+
106
+ def match_all?
107
+ @exclusion.match_strategy == :ALL
108
+ end
109
+
110
+ # Determine if the given rule is excluded by this exclusion.
111
+ # In this case, the `protection_rules` being empty means apply to all rules,
112
+ # not no rules
113
+ #
114
+ # @param rule - the id of the rule which we're checking for exclusion
115
+ def protection_rule? rule
116
+ protect? &&
117
+ (@exclusion.protection_rules.empty? ||
118
+ @exclusion.protection_rules.include?(rule)
119
+ )
120
+ end
121
+
122
+ # Determine if the given rule is excluded by this exclusion.
123
+ # In this case, the `assessment_rules` being empty means apply to all rules,
124
+ # not no rules
125
+ #
126
+ # @param rule - the id of the rule which we're checking for exclusion
127
+ def assess_rule? rule
128
+ assess? &&
129
+ (@exclusion.assessment_rules.empty? ||
130
+ @exclusion.assessment_rules.include?(rule)
131
+ )
132
+ end
133
+
134
+ def match_url? url
135
+ return false unless url?
136
+ return true if @wildcard_url
137
+
138
+ @urls.any? { |test| url.match?(test) }
139
+ end
140
+
141
+ def match_input? value, type
142
+ return false unless input?
143
+
144
+ exclusion_type = @exclusion.input_type
145
+ case type
146
+ when :PARAMETER_NAME, :PARAMETER_VALUE
147
+ return exclusion_type == :PARAMETER && value_match?(value)
148
+ when :COOKIE_NAME, :COOKIE_VALUE
149
+ return exclusion_type == :COOKIE && value_match?(value)
150
+ when :HEADER
151
+ return exclusion_type == :HEADER && value_match?(value, false)
152
+ when :BODY
153
+ return exclusion_type == :BODY
154
+ when :QUERYSTRING
155
+ return exclusion_type == :QUERYSTRING
156
+ end
157
+
158
+ false
159
+ end
160
+
161
+ def value_match? value, case_sensitive = true
162
+ return true if @wildcard_input
163
+
164
+ if case_sensitive
165
+ value == @exclusion.input_name
166
+ else
167
+ @exclusion.input_name.casecmp(value).zero?
168
+ end
169
+ end
170
+
171
+ def match_code? stack_trace
172
+ return false unless code?
173
+ return false if @wildcard_exclusions&.empty?
174
+
175
+ @wildcard_exclusions.each do |code|
176
+ class_name = code[0]
177
+ method_name = code[1]
178
+ stack_trace.each do |location|
179
+ next unless location.base_label.match?(method_name)
180
+ next unless location.path.match?(class_name)
181
+
182
+ return true
183
+ end
184
+ end
185
+
186
+ false
187
+ end
188
+ end
189
+ end
190
+ end