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,44 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ cs__scoped_require 'contrast/utils/object_share'
5
+ cs__scoped_require 'contrast/components/interface'
6
+ cs__scoped_require 'contrast/core_extensions/assess/assess_extension'
7
+
8
+ module Contrast
9
+ module Agent
10
+ module Assess
11
+ module Policy
12
+ # This is how we scan our customer's code. It provides a way to analyze
13
+ # the classes we need to observe to find vulnerabilities in the context
14
+ # of a file vs data flow, such as the detection of Hardcoded Passwords
15
+ # or Keys.
16
+ module PolicyScanner
17
+ include Contrast::Components::Interface
18
+ access_component :analysis, :logging
19
+
20
+ class << self
21
+ def scan trace_point
22
+ return unless ASSESS.enabled?
23
+ return unless ASSESS.require_scan?
24
+
25
+ return unless trace_point.path
26
+ return if trace_point.path.start_with?(Gem.dir)
27
+
28
+ mod = trace_point.self
29
+ return if mod.cs__frozen? || mod.singleton_class?
30
+
31
+ policy.providers.each_value do |provider|
32
+ provider.analyze mod
33
+ end
34
+ end
35
+
36
+ def policy
37
+ Contrast::Agent::Assess::Policy::Policy.instance
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,94 @@
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
+ module Assess
9
+ # In order to properly shift tags to account for the changes this method
10
+ # caused, we'll need to store the state before the change occurred.
11
+ class PreShift
12
+ include Contrast::Components::Interface
13
+ access_component :analysis, :logging
14
+
15
+ UNDUPLICABLE_MODULES = [
16
+ Enumerator # dup'ing results in 'can't copy execution context'
17
+ ].cs__freeze
18
+
19
+ attr_accessor :object, :object_length, :args, :arg_lengths
20
+
21
+ class << self
22
+ # Save the state before we do the propagation. This is one of the
23
+ # few things that we'll call BEFORE calling the original method.
24
+ # Unfortunately, we may waste some time here if the method then
25
+ # throws an exception, but hey, it threw an exception. These few
26
+ # extra objects aren't the real problem in that case.
27
+ #
28
+ # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode]
29
+ # The node responsible for the propagation action required by this
30
+ # method.
31
+ # @param object [Object] the object on which the method is to be
32
+ # called.
33
+ # @param args [Array<Object>] the arguments to be passed to the
34
+ # method.
35
+ # @return [Contrast::Agent::Assess::PreShift, nil] a holder saving
36
+ # the state of the object and arguments just prior to the method
37
+ # being called or nil if one is not required.
38
+ def build_preshift propagation_node, object, args
39
+ return nil unless propagation_node
40
+ return nil unless ASSESS.enabled?
41
+
42
+ initializing = propagation_node.method_name == :initialize
43
+ return nil if unsafe_io_object?(object, initializing)
44
+
45
+ needs_object = propagation_node.needs_object?
46
+ needs_args = propagation_node.needs_args?
47
+
48
+ preshift = Contrast::Agent::Assess::PreShift.new
49
+ append_object_details(preshift, initializing, object) if needs_object
50
+ append_arg_details(preshift, args) if needs_args
51
+
52
+ preshift
53
+ rescue StandardError => e
54
+ logger.error(e, 'Unable to build preshift for method.')
55
+ nil
56
+ end
57
+
58
+ private
59
+
60
+ def unsafe_io_object? object, initializing
61
+ Contrast::Utils::DuckUtils.quacks_like_closable_io(object) && !initializing && object.closed?
62
+ end
63
+
64
+ def can_dup? initializing, object
65
+ return false if initializing
66
+
67
+ check = object.is_a?(Module) ? object : object.cs__class
68
+ !UNDUPLICABLE_MODULES.include?(check)
69
+ end
70
+
71
+ def append_object_details preshift, initializing, object
72
+ preshift.object = can_dup?(initializing, object) ? object.dup : object
73
+ preshift.object.cs__copy_from(object) if object.cs__frozen? && Contrast::Utils::DuckUtils.quacks_to?(preshift.object, :cs__copy_from)
74
+ preshift.object_length = if Contrast::Utils::DuckUtils.quacks_to?(preshift.object, :length)
75
+ object.length
76
+ else
77
+ 0
78
+ end
79
+ end
80
+
81
+ def append_arg_details preshift, args
82
+ preshift.args = args.dup
83
+ preshift.args.each_with_index do |arg, index|
84
+ next unless args[index].cs__frozen? && Contrast::Utils::DuckUtils.quacks_to?(arg, :cs__copy_from)
85
+
86
+ arg.cs__copy_from(args[index])
87
+ end
88
+ preshift.arg_lengths = preshift.args.map { |arg| Contrast::Utils::DuckUtils.quacks_to?(arg, :length) ? arg.length : 0 }
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,260 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ # This class is responsible for the continuation of traces. A Propagator is any
5
+ # method that transforms an untrusted value. In general, these methods work on
6
+ # the String class or a holder of Strings
7
+ cs__scoped_require 'set'
8
+
9
+ cs__scoped_require 'contrast/utils/object_share'
10
+ cs__scoped_require 'contrast/utils/sha256_builder'
11
+
12
+ cs__scoped_require 'contrast/agent/assess/policy/propagator'
13
+
14
+ cs__scoped_require 'contrast/components/interface'
15
+
16
+ module Contrast
17
+ module Agent
18
+ module Assess
19
+ module Policy
20
+ # This module contains the logic for determining how to propagate tags
21
+ # and events from a source to a target
22
+ module PropagationMethod
23
+ include Contrast::Components::Interface
24
+ access_component :logging
25
+
26
+ APPEND_ACTION = 'APPEND'
27
+ CENTER_ACTION = 'CENTER'
28
+ INSERT_ACTION = 'INSERT'
29
+ KEEP_ACTION = 'KEEP'
30
+ NEXT_ACTION = 'NEXT'
31
+ PREPEND_ACTION = 'PREPEND'
32
+ REPLACE_ACTION = 'REPLACE'
33
+ REMOVE_ACTION = 'REMOVE'
34
+ REVERSE_ACTION = 'REVERSE'
35
+ SPLAT_ACTION = 'SPLAT'
36
+ SPLIT_ACTION = 'SPLIT'
37
+ TAG_ACTION = 'TAG'
38
+ DB_WRITE_ACTION = 'DB_WRITE'
39
+ CUSTOM_ACTION = 'CUSTOM'
40
+
41
+ class << self
42
+ def determine_target propagation_node, ret, object, args
43
+ target_key = propagation_node.targets[0]
44
+ return ret if target_key == Contrast::Utils::ObjectShare::RETURN_KEY
45
+ return object if target_key == Contrast::Utils::ObjectShare::OBJECT_KEY
46
+
47
+ return args[target_key] if target_key.is_a?(Integer)
48
+
49
+ arg = nil
50
+ args.each do |search|
51
+ next unless search.is_a?(Hash)
52
+
53
+ arg = search[target_key]
54
+ break if arg
55
+ end
56
+ arg
57
+ end
58
+
59
+ def apply_propagation method_policy, preshift, object, ret, args, block
60
+ return unless method_policy.propagation_node
61
+ return unless preshift
62
+
63
+ propagation_node = method_policy.propagation_node
64
+
65
+ target = determine_target(propagation_node, ret, object, args)
66
+ PropagationMethod.apply_propagator(propagation_node, preshift, target, object, ret, 0, args, block)
67
+ end
68
+
69
+ PROPAGATION_ACTIONS = {
70
+ APPEND_ACTION => Contrast::Agent::Assess::Policy::Propagator::Append,
71
+ CENTER_ACTION => Contrast::Agent::Assess::Policy::Propagator::Center,
72
+ INSERT_ACTION => Contrast::Agent::Assess::Policy::Propagator::Insert,
73
+ KEEP_ACTION => Contrast::Agent::Assess::Policy::Propagator::Keep,
74
+ NEXT_ACTION => Contrast::Agent::Assess::Policy::Propagator::Next,
75
+ PREPEND_ACTION => Contrast::Agent::Assess::Policy::Propagator::Prepend,
76
+ REPLACE_ACTION => Contrast::Agent::Assess::Policy::Propagator::Replace,
77
+ REMOVE_ACTION => Contrast::Agent::Assess::Policy::Propagator::Remove,
78
+ REVERSE_ACTION => Contrast::Agent::Assess::Policy::Propagator::Reverse,
79
+ SPLAT_ACTION => Contrast::Agent::Assess::Policy::Propagator::Splat,
80
+ SPLIT_ACTION => Contrast::Agent::Assess::Policy::Propagator::Split
81
+ }.cs__freeze
82
+
83
+ # I lied above. We had to figure out what the target of the propagation was.
84
+ # Now that we know, we'll actually do things to it.
85
+ def apply_propagator propagation_node, preshift, target, object, ret, invoked, args, block
86
+ context = Contrast::Agent::REQUEST_TRACKER.current
87
+ return unless context && propagation_node && valid_target?(target, propagation_node)
88
+ return unless valid_length?(target, propagation_node.action)
89
+
90
+ if propagation_node.action == DB_WRITE_ACTION
91
+ Contrast::Agent::Assess::Policy::Propagator::DatabaseWrite.propagate(propagation_node, preshift, ret)
92
+ elsif propagation_node.action == CUSTOM_ACTION
93
+ Contrast::Agent::Assess::Policy::Propagator::Custom.propagate(propagation_node, preshift, ret, block)
94
+ elsif propagation_node.action == SPLIT_ACTION
95
+ Contrast::Agent::Assess::Policy::Propagator::Split.propagate(propagation_node, preshift, target)
96
+ logger.debug(
97
+ nil,
98
+ "Propagator #{ propagation_node.id } detected: propagated to #{ target.__id__ }")
99
+ elsif Contrast::Utils::DuckUtils.quacks_to?(target, :cs__properties)
100
+ handle_cs_properties_propagation(propagation_node, preshift, target, object, ret, invoked, args, block)
101
+ elsif Contrast::Utils::DuckUtils.quacks_like_tracked_hash?(target)
102
+ handle_hash_propagation(propagation_node, preshift, target, object, ret, invoked, args, block)
103
+ elsif Contrast::Utils::DuckUtils.quacks_like_tracked_enumerable?(target)
104
+ handle_enumerable_propagation(propagation_node, preshift, target, object, ret, invoked, args, block)
105
+ end
106
+ rescue StandardError => e
107
+ logger.warn(e, "Unable to apply propagator #{ propagation_node.id }")
108
+ end
109
+
110
+ # Custom actions tend to be the more complex of our propagations.
111
+ # Often, the method has to make decisions about the target based on
112
+ # the context with which the method was called. As such, defer
113
+ # determining if the target is valid to that method.
114
+ #
115
+ # In all other cases, a target is valid for propagation if it is not
116
+ # nil
117
+ def valid_target? target, propagation_node
118
+ return true if propagation_node.action == CUSTOM_ACTION
119
+
120
+ !!target
121
+ end
122
+
123
+ ZERO_LENGTH_ACTIONS = [
124
+ DB_WRITE_ACTION,
125
+ CUSTOM_ACTION,
126
+ KEEP_ACTION,
127
+ REPLACE_ACTION,
128
+ SPLAT_ACTION
129
+ ].cs__freeze
130
+ # If the action required needs a length and the target does not have
131
+ # one, the length is not valid
132
+ def valid_length? target, action
133
+ return true if ZERO_LENGTH_ACTIONS.include?(action)
134
+
135
+ if Contrast::Utils::DuckUtils.quacks_to?(target, :length)
136
+ target.length != 0 # rubocop:disable Style/ZeroLengthPredicate
137
+ else
138
+ !target.to_s.empty?
139
+ end
140
+ end
141
+
142
+ # Before we do any work, we should check if we even need to.
143
+ # If the source of this patcher is not tracked, there's no need to do
144
+ # anything. A copy of nothing is still nothing.
145
+ def can_propagate? propagation_node, preshift, target
146
+ # We cannot propagate to things that do not have cs__properties.
147
+ return false unless Contrast::Utils::DuckUtils.quacks_to?(target, :cs__properties)
148
+
149
+ # We cannot propagate to frozen things that have not been
150
+ # previously tracked. We probably shouldn't propagate to frozen
151
+ # things at all, as they're supposed to be immutable, but third
152
+ # parties do jenky things, so allow it as long as it is safe to do.
153
+ return false if target.cs__properties == Contrast::Agent::Assess::Insulator.generate_frozen.properties &&
154
+ propagation_node.targets[0] != Contrast::Utils::ObjectShare::RETURN_KEY
155
+ return true if Contrast::Utils::Assess::TrackingUtil.tracked?(target)
156
+ return false unless preshift
157
+
158
+ propagation_node.sources.each do |source|
159
+ case source
160
+ when Contrast::Utils::ObjectShare::OBJECT_KEY
161
+ return true if Contrast::Utils::Assess::TrackingUtil.tracked?(preshift.object)
162
+ else # has to be P, there's no ret source type (yet? ever?)
163
+ return true if preshift.args && Contrast::Utils::Assess::TrackingUtil.tracked?(preshift.args[source])
164
+ end
165
+ end
166
+ false
167
+ end
168
+
169
+ # If this patcher has tags, apply them to the entire target
170
+ def apply_tags propagation_node, target
171
+ return unless propagation_node.tags
172
+
173
+ length = Contrast::Utils::StringUtils.ret_length(target)
174
+ propagation_node.tags.each do |tag|
175
+ span = Contrast::Agent::Assess::AdjustedSpan.new(0, length)
176
+ target.cs__properties.add_tag(tag, span)
177
+ end
178
+ end
179
+
180
+ # If this patcher has tags, remove them from the entire target
181
+ def apply_untags propagation_node, target
182
+ return unless propagation_node.untags
183
+
184
+ propagation_node.untags.each do |tag|
185
+ target.cs__properties.delete_tags(tag)
186
+ end
187
+ end
188
+
189
+ private
190
+
191
+ def handle_hash_propagation propagation_node, preshift, target, object, ret, invoked, args, block
192
+ invoked += 2
193
+ target.each_pair do |key, value|
194
+ apply_propagator(propagation_node, preshift, key, object, ret, invoked, args, block)
195
+ apply_propagator(propagation_node, preshift, value, object, ret, invoked, args, block)
196
+ end
197
+ end
198
+
199
+ def handle_enumerable_propagation propagation_node, preshift, target, object, ret, invoked, args, block
200
+ invoked += 2
201
+ target.each do |value|
202
+ next if target == value # Some Enumerable#each are overriden to return self the first time which leads to infinite propagation
203
+
204
+ apply_propagator(propagation_node, preshift, value, object, ret, invoked, args, block)
205
+ end
206
+ end
207
+
208
+ def handle_cs_properties_propagation propagation_node, preshift, target, object, ret, invoked, args, _block
209
+ invoked += 1
210
+ return unless can_propagate?(propagation_node, preshift, target)
211
+
212
+ # propagate all the tags from the sources to the target
213
+ propagation_class = PROPAGATION_ACTIONS.fetch(propagation_node.action, nil)
214
+ unless propagation_class
215
+ logger.warn(
216
+ nil,
217
+ "Unknown action type #{ propagation_node.action }. Unable to "\
218
+ "propagate for #{ propagation_node.id }.")
219
+ return ret
220
+ end
221
+
222
+ restore_frozen_state = false
223
+ if target.cs__frozen?
224
+ return ret unless propagation_node.targets[0] == Contrast::Utils::ObjectShare::RETURN_KEY
225
+
226
+ restore_frozen_state = true
227
+ ret = Contrast::Utils::FreezeUtil.unfreeze_dup(target)
228
+ target = ret
229
+ end
230
+ propagation_class.propagate(propagation_node, preshift, target)
231
+
232
+ # Once we've propagated, attempt to tag the target if there is a tag(s) to be applied
233
+ apply_tags(propagation_node, target)
234
+
235
+ # Even though we skipped propagating tags from the source if they
236
+ # were included in untags, the target may have already had some on
237
+ # it. Let's go ahead and remove them.
238
+ # In this order, untags takes precedent over tags; but we control
239
+ # both and there should never be a propagator that has a tag in
240
+ # its untag.
241
+ apply_untags(propagation_node, target)
242
+
243
+ target.cs__properties.add_properties(propagation_node.properties)
244
+
245
+ target.cs__properties.build_event(propagation_node, target, object, ret, args, invoked)
246
+
247
+ logger.debug(
248
+ nil,
249
+ "Propagator #{ propagation_node.id } detected: propagated to "\
250
+ "#{ target.__id__ }")
251
+
252
+ ret.cs__freeze if restore_frozen_state
253
+ ret
254
+ end
255
+ end
256
+ end
257
+ end
258
+ end
259
+ end
260
+ end
@@ -0,0 +1,127 @@
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_node'
5
+ module Contrast
6
+ module Agent
7
+ module Assess
8
+ module Policy
9
+ # This class functions to translate our policy.json into an actionable
10
+ # Ruby object, allowing for dynamic patching over hardcoded patching,
11
+ # specifically for those methods which result in the transformation of
12
+ # untrusted data (indicate points in the application where user
13
+ # controlled input is modified).
14
+ class PropagationNode < PolicyNode
15
+ JSON_ACTION = 'action'
16
+ JSON_UNTAGS = 'untags'
17
+ JSON_PATCH_CLASS = 'patch_class'
18
+ JSON_PATCH_METHOD = 'patch_method'
19
+
20
+ attr_accessor :action, :untags, :patch_class, :patch_method
21
+
22
+ # Most things here carry over from PolicyNode.
23
+ # A couple things are new / have new rules
24
+ #
25
+ # Source - from where the tainted data flows, cannot be nil
26
+ # Target - to where the tainted data flows, cannot be nil
27
+ # Action - how the tainted data flows from source to target, should not be nil
28
+ # Tags - array of tags to apply to the target, can be nil if no tags are added
29
+ # Untags - array of tags to remove from the target, can be nil if not tags are removed
30
+ # id, class_name, instance_method, method_name, source, target, action, tags = nil, untags = nil
31
+ def initialize propagation_hash = {}
32
+ super(propagation_hash)
33
+ @action = propagation_hash[JSON_ACTION]
34
+ @untags = Set.new(propagation_hash[JSON_UNTAGS])
35
+ @patch_class = propagation_hash[JSON_PATCH_CLASS]
36
+ @patch_method = propagation_hash[JSON_PATCH_METHOD]
37
+ @patch_method = @patch_method.to_sym if @patch_method
38
+ validate
39
+ end
40
+
41
+ TAGGER = 'Tagger'
42
+ PROPAGATOR = 'Propagator'
43
+
44
+ def node_class
45
+ @_node_class ||= tagger? ? TAGGER : PROPAGATOR
46
+ end
47
+
48
+ # Unlike the other agents, we don't have separate tag & propagation
49
+ # events. To make TS happy, we need to have different types though.
50
+ # Pretty straight forward: if there's a tag, this is a tagger
51
+ def node_type
52
+ tagger? ? :TYPE_TAG : :TYPE_PROPAGATION
53
+ end
54
+
55
+ # Standard validation + TS trace version two rules:
56
+ # Must have source, target, and action
57
+ def validate
58
+ super
59
+ raise(ArgumentError, "Propagator #{ id } did not have a proper action. Unable to create.") unless action
60
+
61
+ if @action == 'CUSTOM'
62
+ raise(ArgumentError, "Propagator #{ id } did not have a proper patch_class. Unable to create.") unless patch_class
63
+ raise(ArgumentError, "Propagator #{ id } did not have a proper patch_method. Unable to create.") unless patch_method.is_a?(Symbol)
64
+ else
65
+ raise(ArgumentError, "Propagator #{ id } did not have a proper target. Unable to create.") unless targets&.any?
66
+ raise(ArgumentError, "Propagator #{ id } did not have a proper source. Unable to create.") unless sources&.any?
67
+ end
68
+ validate_untags
69
+ end
70
+
71
+ def validate_untags
72
+ return unless untags
73
+
74
+ untags.each do |tag|
75
+ raise(ArgumentError, "#{ node_type } #{ id } did not have a valid untag. #{ tag } is not a known value.") unless VALID_TAGS.include?(tag)
76
+ raise(ArgumentError, "#{ node_type } #{ id } had the same tag and untag, #{ tag }.") if tags&.include?(tag)
77
+ end
78
+ end
79
+
80
+ def needs_object?
81
+ @_needs_object ||= begin
82
+ if action == Contrast::Agent::Assess::Policy::PropagationMethod::CUSTOM_ACTION
83
+ true
84
+ elsif action == Contrast::Agent::Assess::Policy::PropagationMethod::DB_WRITE_ACTION
85
+ true
86
+ elsif sources.any? { |source| source == Contrast::Utils::ObjectShare::OBJECT_KEY }
87
+ true
88
+ elsif targets.any? { |target| target == Contrast::Utils::ObjectShare::OBJECT_KEY }
89
+ true
90
+ else
91
+ false
92
+ end
93
+ end
94
+ end
95
+
96
+ def needs_args?
97
+ @_needs_args ||= begin
98
+ if action == Contrast::Agent::Assess::Policy::PropagationMethod::CUSTOM_ACTION
99
+ true
100
+ elsif action == Contrast::Agent::Assess::Policy::PropagationMethod::DB_WRITE_ACTION
101
+ true
102
+ elsif sources.any? { |source| source.is_a?(Integer) || source.is_a?(Symbol) }
103
+ true
104
+ elsif targets.any? { |target| target.is_a?(Integer) || target.is_a?(Symbol) }
105
+ true
106
+ else
107
+ false
108
+ end
109
+ end
110
+ end
111
+
112
+ # This is a tagger if it has a tag or an untag.
113
+ # It indicates this method is more than just a transformation,
114
+ # it is an interesting security event that has a meaningful
115
+ # change.
116
+ def tagger?
117
+ @_tagger ||= begin
118
+ has_tags = tags&.any?
119
+ has_untags = untags&.any?
120
+ has_tags || has_untags
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end