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,41 @@
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 'set'
5
+ cs__scoped_require 'base64'
6
+ cs__scoped_require 'contrast/utils/tag_util'
7
+ cs__scoped_require 'contrast/utils/prevent_serialization'
8
+
9
+ module Contrast
10
+ module Agent
11
+ module Assess
12
+ # This class is used as an NoOP version of Properties. We'll pass this to
13
+ # any attempt to access Properties on a frozen object including
14
+ # AssessExtension iff that object did not have Properties before it was
15
+ # placed in a frozen state.
16
+ class FrozenProperties
17
+ include Contrast::Utils::PreventSerialization
18
+
19
+ def events
20
+ Contrast::Utils::ObjectShare::EMPTY_ARRAY
21
+ end
22
+
23
+ def properties
24
+ Contrast::Utils::ObjectShare::EMPTY_HASH
25
+ end
26
+
27
+ def tracked?
28
+ false
29
+ end
30
+
31
+ def tagged? _label
32
+ false
33
+ end
34
+
35
+ def any_tags_between? _start, _finish
36
+ false
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,53 @@
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/prevent_serialization'
5
+ cs__scoped_require 'contrast/agent/assess/properties'
6
+
7
+ module Contrast
8
+ module Agent
9
+ module Assess
10
+ # This is just a wrapper around Properties so that if they are on a frozen
11
+ # object, they are left mutable for us.
12
+ class Insulator
13
+ # Return a new delegator with a properties method, used to track
14
+ # properties in a manner that won't be serialized.
15
+ #
16
+ # @return [SimpleDelegator<Object>]
17
+ def self.generate
18
+ delegator = SimpleDelegator.new(nil)
19
+ delegator.extend(Contrast::Utils::PreventPsychSerialization)
20
+ delegator
21
+ end
22
+
23
+ # Return the frozen properties delegator, which is a
24
+ #
25
+ # @return [SimpleDelegator<Object>]
26
+ def self.generate_frozen
27
+ @_generate_frozen ||= begin
28
+ delegator = SimpleDelegator.new(nil)
29
+ delegator.extend(Contrast::Utils::PreventPsychSerialization)
30
+ delegator
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ # Our patch of the SimpleDelegator class, allowing us to leverage its
39
+ # marshal_dump and marshal_load methods to hide our properties on an object so
40
+ # that they will not be dumped or loaded.
41
+ # We do this to prevent polluting data that may run on applications that are no
42
+ # longer instrumented with Contrast
43
+ class SimpleDelegator
44
+ # rubocop:disable Naming/MemoizedInstanceVariableName
45
+ def properties
46
+ @delegate_properties ||= Contrast::Agent::Assess::Properties.new
47
+ end
48
+
49
+ def frozen_properties
50
+ @delegate_frozen_properties ||= Contrast::Agent::Assess::FrozenProperties.new
51
+ end
52
+ # rubocop:enable Naming/MemoizedInstanceVariableName
53
+ end
@@ -0,0 +1,78 @@
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/method_policy'
5
+
6
+ module Contrast
7
+ module Agent
8
+ module Assess
9
+ module Policy
10
+ # This class is used to create dynamic source nodes & source nodes from a db model that receives untrusted data
11
+ class DynamicSourceFactory
12
+ DB_SOURCE_TYPE = 'TAINTED_DATABASE'
13
+ WRITE_QUERY_TIME = 'writeDateTimeUtc'
14
+ WRITE_QUERY_URL = 'writeRequestUrl'
15
+ READ_TABLE = 'readTable'
16
+ READ_COLUMN = 'readColumn'
17
+ class << self
18
+ def create_sources klass, tainted_columns
19
+ instance_methods = klass.instance_methods
20
+ instance_methods.concat(klass.private_instance_methods)
21
+ tainted_columns.each_pair do |field, events|
22
+ dynamic_source_node = create_source_node(klass, field)
23
+ Contrast::Agent::Assess::Policy::Policy.instance.add_node(dynamic_source_node, :dynamic_source)
24
+
25
+ method_policy = Contrast::Agent::Patching::Policy::MethodPolicy.new
26
+ method_policy.method_name = field.to_sym
27
+ method_policy.method_visibility = :public
28
+ method_policy.instance_method = true
29
+ method_policy.source_node = dynamic_source_node
30
+ Contrast::Agent::Patching::Policy::Patcher.patch_method(klass, instance_methods, method_policy)
31
+
32
+ current_context = Contrast::Agent::REQUEST_TRACKER.current
33
+
34
+ next unless current_context.activity.dynamic_sources[dynamic_source_node.id]
35
+
36
+ dynamic_source = create_dynamic_source(current_context, dynamic_source_node, field, events)
37
+
38
+ node_id = Contrast::Utils::StringUtils.force_utf8(dynamic_source_node.id)
39
+ current_context.activity.dynamic_sources[node_id] = dynamic_source
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def create_source_node klass, field
46
+ node = Contrast::Agent::Assess::Policy::SourceNode.new
47
+ node.class_name = klass.cs__name
48
+ node.instance_method = true
49
+ node.method_name = field.to_sym
50
+ node.method_visibility = :public
51
+ node.target_string = Contrast::Utils::ObjectShare::RETURN_KEY
52
+ node.type = DB_SOURCE_TYPE
53
+ node.add_property('dynamic_source_id', node.id)
54
+ node
55
+ end
56
+
57
+ def create_dynamic_source current_context, source_node, field, events
58
+ dynamic_source = Contrast::Api::Dtm::DynamicSource.new
59
+ dynamic_source.class_name = Contrast::Utils::StringUtils.force_utf8(source_node.class_name)
60
+ dynamic_source.method_name = Contrast::Utils::StringUtils.force_utf8(field)
61
+ dynamic_source.instance_method = source_node.instance_method?
62
+ dynamic_source.target = Contrast::Utils::StringUtils.force_utf8(source_node.target_string)
63
+ events.each do |event|
64
+ dynamic_source.events << event.to_dtm_event
65
+ end
66
+ dynamic_source.properties[READ_TABLE] = Contrast::Utils::StringUtils.force_utf8(source_node.class_name)
67
+ dynamic_source.properties[READ_COLUMN] = Contrast::Utils::StringUtils.force_utf8(field)
68
+ dynamic_source.properties[WRITE_QUERY_TIME] = Contrast::Utils::StringUtils.force_utf8(Contrast::Utils::Timer.now_ms)
69
+ url = current_context.request.normalized_uri
70
+ dynamic_source.properties[WRITE_QUERY_URL] = Contrast::Utils::StringUtils.force_utf8(url)
71
+ dynamic_source
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,85 @@
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/assess/policy/policy'
5
+ cs__scoped_require 'contrast/agent/patching/policy/patcher'
6
+ cs__scoped_require 'contrast/agent/patching/policy/method_policy'
7
+ cs__scoped_require 'contrast/agent/patching/policy/module_policy'
8
+
9
+ module Contrast
10
+ module Agent
11
+ module Assess
12
+ module Policy
13
+ # This is how we patch into our customer's code. It provides a way to
14
+ # track which classes we need to patch into and, once we've woven,
15
+ # provides a map for which methods our renamed functions need to call
16
+ # and how.
17
+ module Patcher
18
+ include Contrast::Components::Interface
19
+ access_component :logging, :analysis, :agent, :scope
20
+
21
+ class << self
22
+ def policy
23
+ Contrast::Agent::Assess::Policy::Policy.instance
24
+ end
25
+
26
+ def patcher
27
+ Contrast::Agent::Patching::Policy::Patcher
28
+ end
29
+
30
+ # Some of the methods we care about, especially those used as dynamic
31
+ # sources, are truly dynamic, in that they do not exist on class
32
+ # load. These methods only exist once a module or class eval has been
33
+ # called. This hook is provided so that patches to those methods can
34
+ # pass us execution flow once a new method has been made available.
35
+ def patch_assess_on_eval mod
36
+ return unless ASSESS.enabled?
37
+
38
+ with_contrast_scope { patcher.patch_specific_module(mod) }
39
+ rescue StandardError => e
40
+ logger.warn(
41
+ e,
42
+ "Unable to patch assess into #{ mod.cs__name } on eval")
43
+ end
44
+
45
+ # Exposed so that methods can be dynamically patched on creation at
46
+ # runtime, like those generated by
47
+ # ActiveRecord::AttributeMethods::Read::ClassMethods#define_method_attribute
48
+ CLASS_TYPES = [
49
+ Contrast::Utils::ObjectShare::CLASS,
50
+ Contrast::Utils::ObjectShare::MODULE
51
+ ].cs__freeze
52
+ def patch_assess_method clazz, method_name
53
+ # Module.define_method is called a lot in Class and Module. We
54
+ # currently do not expect these define_methods to result in methods
55
+ # that require patching, so for the sake of performance, we're going
56
+ # to skip evaluating them
57
+ class_name = clazz.cs__name
58
+ return if CLASS_TYPES.include?(class_name)
59
+ return unless ASSESS.enabled?
60
+
61
+ source_nodes = Contrast::Agent::Patching::Policy::ModulePolicy.nodes_for_module(policy.sources, class_name)
62
+ return if source_nodes.empty?
63
+
64
+ method_array = []
65
+ method_array << method_name
66
+ source_nodes.each do |source_node|
67
+ next unless source_node.method_name.to_s == method_name
68
+
69
+ method_policy = Contrast::Agent::Patching::Policy::MethodPolicy.new(source_node: source_node,
70
+ method_name: source_node.method_name,
71
+ method_visibility: source_node.method_visibility,
72
+ instance_method: true)
73
+ patcher.patch_method(clazz, method_array, method_policy)
74
+ end
75
+ rescue StandardError => e
76
+ logger.warn(
77
+ e,
78
+ "Unable to patch assess into #{ class_name }##{ method_name } on define_method_attribute")
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,116 @@
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 'json'
5
+ cs__scoped_require 'contrast/agent/assess/rule/provider/hardcoded_value_rule'
6
+ cs__scoped_require 'contrast/agent/assess/rule/provider/hardcoded_key'
7
+ cs__scoped_require 'contrast/agent/assess/rule/provider/hardcoded_password'
8
+ cs__scoped_require 'contrast/agent/assess/policy/policy_node'
9
+ cs__scoped_require 'contrast/agent/assess/policy/source_node'
10
+ cs__scoped_require 'contrast/agent/assess/policy/propagation_node'
11
+ cs__scoped_require 'contrast/agent/assess/policy/trigger_node'
12
+ cs__scoped_require 'contrast/agent/patching/policy/policy'
13
+
14
+ module Contrast
15
+ module Agent
16
+ module Assess
17
+ module Policy
18
+ # This is just a holder for our policy. Takes the policy JSON and
19
+ # converts it into hashes that we can access nicely
20
+ class Policy < Contrast::Agent::Patching::Policy::Policy
21
+ # Indicates the folder in `resources` where this policy lives.
22
+ def self.policy_folder
23
+ 'assess'
24
+ end
25
+
26
+ # Indicates is this feature has been disabled by the configuration,
27
+ # read at startup, and therefore can never be enabled.
28
+ def disabled_globally?
29
+ ASSESS.forcibly_disabled?
30
+ end
31
+
32
+ def node_type
33
+ Contrast::Agent::Assess::Policy::TriggerNode
34
+ end
35
+
36
+ def initialize
37
+ super
38
+ load_providers
39
+ end
40
+
41
+ # Our policy for dataflow rules is a 'dope ass' JSON file. Rather than
42
+ # hard code in a bunch of things to monkey patch, we let the JSON file
43
+ # define the conditions in which sources, propagators, and triggers are
44
+ # applied.
45
+ # This let's us be flexible and extensible
46
+ # * when we want to do lvl 2 rules, we could have the customers unzip
47
+ # our gem, insert things into the json, zip, and go *
48
+ def from_hash_string string
49
+ # The default behavior of the agent is to load the policy on startup,
50
+ # as at this point we do not know in which mode we'll be run.
51
+ #
52
+ # If the configuration file explicitly disables a feature, we know
53
+ # that we will not ever be able to enable it, so in that case, we
54
+ # can skip policy loading.
55
+ return if disabled_globally?
56
+
57
+ policy_data = JSON.parse(string)
58
+
59
+ policy_data[SOURCES_KEY].each do |source_hash|
60
+ source = Contrast::Agent::Assess::Policy::SourceNode.new(source_hash)
61
+ add_node(source, :source)
62
+ end
63
+
64
+ policy_data[PROPAGATION_KEY].each do |propagator_hash|
65
+ prop = Contrast::Agent::Assess::Policy::PropagationNode.new(propagator_hash)
66
+ add_node(prop, :propagator)
67
+ end
68
+
69
+ policy_data[RULES_KEY].each do |rule_hash|
70
+ rule_hash[TRIGGERS_KEY].each do |trigger_hash|
71
+ trigger_node = node_type.new(trigger_hash, rule_hash)
72
+ add_node(trigger_node)
73
+ end
74
+ end
75
+
76
+ tracked_classes.concat(policy_data[TRACKED_CLASSES_KEY])
77
+ end
78
+
79
+ # Providers is a term that we're taking from Java until we come up with
80
+ # a name that we (I) don't hate. Basically, these are more static like
81
+ # rules. They don't do dataflow or response scanning. Instead, they
82
+ # watch for things to be loaded (configs, classes, whateves) and
83
+ # determine if these loaded things are unsafe.
84
+ #
85
+ # ** if we want, we could add this as a section to the aforementioned
86
+ # 'dope ass' JSON
87
+ def load_providers
88
+ PROVIDER_CLASSES.each do |clazz|
89
+ instance = clazz.new
90
+ providers[instance.rule_id] = instance
91
+ end
92
+ end
93
+
94
+ PROVIDER_CLASSES = [
95
+ Contrast::Agent::Assess::Rule::Provider::HardcodedKey,
96
+ Contrast::Agent::Assess::Rule::Provider::HardcodedPassword
97
+ ].cs__freeze
98
+
99
+ # Handles updating the dynamic sources of this Application and indicates
100
+ # if doing so results in a state that requires repatching -- i.e. new
101
+ # dynamic sources have been discovered by agents monitoring other
102
+ # instances of this application
103
+ def update_dynamic_sources dynamic_sources_map
104
+ dynamic_sources_map.each do |key, dynamic_source|
105
+ # key is the dynamic source node id
106
+ next if sources.any? { |source| source.id == key }
107
+
108
+ dynamic_source_node = Contrast::Agent::Assess::Policy::SourceNode.build_dynamic_source(key, dynamic_source)
109
+ add_node(dynamic_source_node, :dynamic_source)
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,289 @@
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 Assess
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
+ class PolicyNode < Contrast::Agent::Patching::Policy::PolicyNode
13
+ attr_accessor :tags, :type
14
+ attr_reader :sources, :targets, :source_string, :target_string
15
+
16
+ def initialize policy_hash = {}
17
+ super(policy_hash)
18
+ @source_string = policy_hash[JSON_SOURCE]
19
+ @target_string = policy_hash[JSON_TARGET]
20
+ @tags = Set.new(policy_hash[JSON_TAGS])
21
+ generate_sources
22
+ generate_targets
23
+ end
24
+
25
+ def feature
26
+ 'Assess'
27
+ end
28
+
29
+ def node_class
30
+ 'Node'
31
+ end
32
+
33
+ def node_type
34
+ :TYPE_METHOD
35
+ end
36
+
37
+ def target
38
+ @_target ||= begin
39
+ if targets&.any?
40
+ targets[0]
41
+ elsif sources&.any?
42
+ sources[0]
43
+ end
44
+ end
45
+ end
46
+
47
+ def source_string= value
48
+ @source_string = value
49
+ generate_sources
50
+ end
51
+
52
+ def target_string= value
53
+ @target_string = value
54
+ generate_targets
55
+ end
56
+
57
+ # Sometimes we need to tie information to an event. We'll add a
58
+ # properties section to the patch node, which can pass them along to
59
+ # the pre-dtm event
60
+ def add_property name, value
61
+ return unless name && value
62
+
63
+ @properties ||= {}
64
+ @properties[name] = value
65
+ end
66
+
67
+ def get_property name
68
+ return unless @properties
69
+
70
+ @properties[name]
71
+ end
72
+
73
+ # Given a source in the format A,B,C, populate the sources of this node
74
+ # 1) Split on ','
75
+ # 2) If 'O', add the source, else it's P (we don't have R sources) and
76
+ # needs to be converted. P type will either be P:name or P# where #
77
+ # is the index of the paramter. Drop the P and store the int as int
78
+ # or name as symbol
79
+ def generate_sources
80
+ if source_string
81
+ @sources = []
82
+ source_string.split(Contrast::Utils::ObjectShare::COMMA).each do |s|
83
+ is_object = (s == Contrast::Utils::ObjectShare::OBJECT_KEY)
84
+ if is_object
85
+ @sources << s
86
+ else
87
+ parameter_source = s[1..-1]
88
+ @sources << if parameter_source.start_with?(Contrast::Utils::ObjectShare::COLON)
89
+ parameter_source[1..-1].to_sym
90
+ else
91
+ parameter_source.to_i
92
+ end
93
+ end
94
+ end
95
+ else
96
+ @sources = Contrast::Utils::ObjectShare::EMPTY_ARRAY
97
+ end
98
+ end
99
+
100
+ # Given a target in the format A,B,C, populate the targets of this node
101
+ # 1) Split on ','
102
+ # 2) If 'O' or 'R', add the target, else it's P and needs to be
103
+ # converted. P type will either be P:name or P# where # is the index
104
+ # of the paramter. Drop the P and store the int as int or name as
105
+ # symbol
106
+ def generate_targets
107
+ if target_string
108
+ @targets = []
109
+ target_string.split(Contrast::Utils::ObjectShare::COMMA).each do |t|
110
+ case t
111
+ when Contrast::Utils::ObjectShare::OBJECT_KEY
112
+ @targets << t
113
+ when Contrast::Utils::ObjectShare::RETURN_KEY
114
+ @targets << t
115
+ else
116
+ parameter_target = t[1..-1]
117
+ @targets << if parameter_target.start_with?(Contrast::Utils::ObjectShare::COLON)
118
+ parameter_target[1..-1].to_sym
119
+ else
120
+ parameter_target.to_i
121
+ end
122
+ end
123
+ end
124
+ else
125
+ @targets = Contrast::Utils::ObjectShare::EMPTY_ARRAY
126
+ end
127
+ end
128
+
129
+ # Don't let nodes be created that will be missing things we need
130
+ # later on. Really, if they don't have these things, they couldn't have
131
+ # done their jobs anyway.
132
+ def validate
133
+ super
134
+ validate_tags
135
+ end
136
+
137
+ # TeamServer is picky. The tags here match to ENUMs there. If there
138
+ # isn't a matching ENUM in TS land, the database gets got. We really
139
+ # don't want to get them, so we're going to prevent the node from being
140
+ # made.
141
+ def validate_tags
142
+ return unless tags
143
+
144
+ tags.each do |tag|
145
+ next if VALID_TAGS.include?(tag) || VALID_SOURCE_TAGS.include?(tag)
146
+
147
+ raise(ArgumentError,
148
+ "#{ node_class } #{ id } had an invalid tag. #{ tag } is not a known value.")
149
+ end
150
+ end
151
+
152
+ ALL_TYPE = 'A'
153
+ CREATION_TYPE = 'CREATION'
154
+ TRIGGER_TYPE = 'TRIGGER'
155
+ TO_MARKER = '2'
156
+ # Convert our action, built from our source and target, into
157
+ # the TS appropriate action. That's a single source to single
158
+ # target marker (A,O,P,R)
159
+ #
160
+ # Creation (source nodes) don't have sources (they are the source)
161
+ # Trigger (trigger nodes) don't have targets (they are the target)
162
+ # Everything else (propagation nodes) are Source2Target
163
+ def build_action
164
+ @event_action ||= begin
165
+ source = source_string
166
+ target = target_string
167
+ if source.nil?
168
+ :CREATION
169
+ elsif target.nil?
170
+ :TRIGGER
171
+ else
172
+ # TeamServer can't handle the multi-source or multi-target
173
+ # values. Give it some help by changing them to 'A'
174
+ source = ALL_TYPE if source.include?(Contrast::Utils::ObjectShare::COMMA)
175
+ target = ALL_TYPE if target.include?(Contrast::Utils::ObjectShare::COMMA)
176
+ str = source[0] + TO_MARKER + target[0] # TODO: RUBY-139 PERF -- save in the patcher
177
+ str.to_sym
178
+ end
179
+ end
180
+ @event_action
181
+ end
182
+
183
+ # EventTagTypeDTM
184
+ VALID_TAGS = %w[
185
+ XML_ENCODED
186
+ XML_DECODED
187
+ HTML_ENCODED
188
+ HTML_DECODED
189
+ URL_ENCODED
190
+ URL_DECODED
191
+ CSS_ENCODED
192
+ CSS_DECODED
193
+ BASE64_ENCODED
194
+ BASE64_DECODED
195
+ JAVASCRIPT_ENCODED
196
+ JAVASCRIPT_DECODED
197
+ JAVA_ENCODED
198
+ JAVA_DECODED
199
+ CSV_ENCODED
200
+ CSV_DECODED
201
+ SQL_ENCODED
202
+ SQL_DECODED
203
+ LDAP_ENCODED
204
+ LDAP_DECODED
205
+ XPATH_ENCODED
206
+ XPATH_DECODED
207
+ OS_ENCODED
208
+ OS_DECODED
209
+ VBSCRIPT_ENCODED
210
+ VBSCRIPT_DECODED
211
+ POTENTIAL_SANITIZED
212
+ POTENTIAL_VALIDATED
213
+ NO_CONTROL_CHARS
214
+ CUSTOM
215
+
216
+ CUSTOM_ENCODED
217
+ CUSTOM_ENCODED_CMD_INJECTION
218
+ CUSTOM_ENCODED_EXPRESSION_LANGUAGE_INJECTION
219
+ CUSTOM_ENCODED_HEADER_INJECTION
220
+ CUSTOM_ENCODED_HQL_INJECTION
221
+ CUSTOM_ENCODED_LDAP_INJECTION
222
+ CUSTOM_ENCODED_LOG_INJECTION
223
+ CUSTOM_ENCODED_NOSQL_INJECTION
224
+ CUSTOM_ENCODED_PATH_TRAVERSAL
225
+ CUSTOM_ENCODED_REDOS
226
+ CUSTOM_ENCODED_REFLECTED_XSS
227
+ CUSTOM_ENCODED_REFLECTION_INJECTION
228
+ CUSTOM_ENCODED_SMTP_INJECTION
229
+ CUSTOM_ENCODED_SQL_INJECTION
230
+ CUSTOM_ENCODED_SSRF
231
+ CUSTOM_ENCODED_STORED_XSS
232
+ CUSTOM_ENCODED_TRUST_BOUNDARY_VIOLATION
233
+ CUSTOM_ENCODED_UNSAFE_CODE_EXECUTION
234
+ CUSTOM_ENCODED_UNSAFE_READLINE
235
+ CUSTOM_ENCODED_UNSAFE_XML_DECODE
236
+ CUSTOM_ENCODED_UNTRUSTED_DESERIALIZATION
237
+ CUSTOM_ENCODED_UNVALIDATED_FORWARD
238
+ CUSTOM_ENCODED_UNVALIDATED_REDIRECT
239
+ CUSTOM_ENCODED_XPATH_INJECTION
240
+ CUSTOM_ENCODED_XXE
241
+ CUSTOM_SECURITY_CONTROL_APPLIED
242
+
243
+ CUSTOM_VALIDATED
244
+ CUSTOM_VALIDATED_CMD_INJECTION
245
+ CUSTOM_VALIDATED_EXPRESSION_LANGUAGE_INJECTION
246
+ CUSTOM_VALIDATED_HEADER_INJECTION
247
+ CUSTOM_VALIDATED_HQL_INJECTION
248
+ CUSTOM_VALIDATED_LDAP_INJECTION
249
+ CUSTOM_VALIDATED_LOG_INJECTION
250
+ CUSTOM_VALIDATED_NOSQL_INJECTION
251
+ CUSTOM_VALIDATED_PATH_TRAVERSAL
252
+ CUSTOM_VALIDATED_REDOS
253
+ CUSTOM_VALIDATED_REFLECTED_XSS
254
+ CUSTOM_VALIDATED_REFLECTION_INJECTION
255
+ CUSTOM_VALIDATED_SMTP_INJECTION
256
+ CUSTOM_VALIDATED_SQL_INJECTION
257
+ CUSTOM_VALIDATED_SSRF
258
+ CUSTOM_VALIDATED_STORED_XSS
259
+ CUSTOM_VALIDATED_TRUST_BOUNDARY_VIOLATION
260
+ CUSTOM_VALIDATED_UNSAFE_CODE_EXECUTION
261
+ CUSTOM_VALIDATED_UNSAFE_READLINE
262
+ CUSTOM_VALIDATED_UNSAFE_XML_DECODE
263
+ CUSTOM_VALIDATED_UNTRUSTED_DESERIALIZATION
264
+ CUSTOM_VALIDATED_UNVALIDATED_FORWARD
265
+ CUSTOM_VALIDATED_UNVALIDATED_REDIRECT
266
+ CUSTOM_VALIDATED_XPATH_INJECTION
267
+ CUSTOM_VALIDATED_XXE
268
+
269
+ DATABASE_WRITE
270
+ ].cs__freeze
271
+
272
+ VALID_SOURCE_TAGS = %w[
273
+ NO_NEWLINES
274
+ UNTRUSTED
275
+ CROSS_SITE
276
+ LIMITED_CHARS
277
+ ].cs__freeze
278
+
279
+ # The keys used to read from policy.json to create the individual
280
+ # policy nodes. These are common across node types
281
+ JSON_SOURCE = 'source'
282
+ JSON_TARGET = 'target'
283
+ JSON_TAGS = 'tags'
284
+ JSON_DATAFLOW = 'dataflow'
285
+ end
286
+ end
287
+ end
288
+ end
289
+ end