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,15 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ cs__scoped_require 'contrast/core_extensions/eval_trigger'
5
+ cs__scoped_require 'contrast/agent/patching/policy/patcher'
6
+
7
+ # Our patch into the BasicObject class, allowing us to track calls to the eval
8
+ # method
9
+ class BasicObject
10
+ class << self
11
+ include Contrast::CoreExtensions::Assess::EvalTrigger
12
+ end
13
+ end
14
+
15
+ cs__scoped_require 'cs__assess_basic_object/cs__assess_basic_object'
@@ -0,0 +1,42 @@
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
+ # This module is used to track propagation through ERB template rendering
7
+ module ERBPropagator
8
+ class << self
9
+ include Contrast::Components::Interface
10
+ access_component :logging
11
+
12
+ def result_tagger patcher, preshift, ret, _block
13
+ return unless preshift.args.length >= 1
14
+
15
+ logger.debug('ERBPropagator - running propagation')
16
+ used_binding = preshift.args[0]
17
+ binding_variable_set = used_binding.local_variables
18
+
19
+ erb_pre_result = preshift.object.src
20
+ binding_variable_set.each do |bound_var_symbol|
21
+ bound_variable_value = used_binding.local_variable_get(bound_var_symbol)
22
+ next unless bound_variable_value.cs__respond_to?(:cs__tracked?) && bound_variable_value.cs__tracked?
23
+ next unless erb_pre_result.include?(bound_var_symbol.to_s)
24
+
25
+ start_index = ret.index(bound_variable_value)
26
+ next if start_index.nil?
27
+
28
+ logger.debug('ERBPropagator - found bound_variable in erb template result')
29
+ ret.cs__copy_from(bound_variable_value, start_index)
30
+ end
31
+ ret.cs__properties.build_event(
32
+ patcher,
33
+ ret,
34
+ preshift.object,
35
+ ret,
36
+ preshift.args,
37
+ 1)
38
+ logger.debug('ERBPropgator - Finished erb result propagation')
39
+ ret
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,48 @@
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 CoreExtensions
8
+ module Assess
9
+ # This Module allows us to track calls to the Kernel#exec method, which
10
+ # violates the design of most methods we track in that we have to apply
11
+ # the trigger at the start in order to account for the process hand off.
12
+ module ExecTrigger
13
+ include Contrast::Components::Interface
14
+ access_component :contrast_service
15
+ def apply_trigger source
16
+ current_context = Contrast::Agent::REQUEST_TRACKER.current
17
+ return unless current_context
18
+
19
+ # Since we know this is the source of the trigger, we can do some
20
+ # optimization here and return when it is not tracked
21
+ return unless Contrast::Utils::Assess::TrackingUtil.tracked?(source)
22
+
23
+ # source might not be all the args passed in, but it is the one we care
24
+ # about. we could pass in all the args in the last param here if it
25
+ # becomes an issue in rendering on TS
26
+ Contrast::Agent::Assess::Policy::TriggerMethod.build_finding(
27
+ current_context,
28
+ trigger_node,
29
+ source,
30
+ self,
31
+ '',
32
+ 1,
33
+ source)
34
+ # Exec replaces the current process, if we occur in a forked process our appendage of this finding will not make it to TS
35
+ CONTRAST_SERVICE.send_message(current_context.activity)
36
+ end
37
+
38
+ private
39
+
40
+ def trigger_node
41
+ @_trigger_node ||= begin
42
+ Contrast::Agent::Assess::Policy::Policy.instance.find_node('cmd-injection', 'Kernel', :exec, false)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,125 @@
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
+ cs__scoped_require 'fiber'
7
+
8
+ # In order to instrument some difficult methods like String#gsub, as it
9
+ # returns an enumerator, we need to instrument methods on Fiber.
10
+ # Specifically, we instrument 'rb_fiber_yield' and 'rb_fiber_new' in
11
+ # order to track what happens within Enumerator#next.
12
+ # TODO: RUBY-531 move these out of Fiber class
13
+ class Fiber
14
+ include Contrast::CoreExtensions::Assess::AssessExtension
15
+ include Contrast::Components::Interface
16
+
17
+ access_component :analysis, :scope
18
+
19
+ FIBER_NEW_NODE_HASH = {
20
+ 'class_name' => 'Fiber',
21
+ 'instance_method' => true,
22
+ 'method_visibility' => 'public',
23
+ 'method_name' => 'c_new', # TODO: Why do we patch new here and not initalize? Historically, new has been problematic.
24
+ 'action' => 'CUSTOM',
25
+ 'source' => 'O',
26
+ 'target' => 'R',
27
+ 'patch_class' => 'NOOP',
28
+ 'patch_method' => 'track_rb_fiber_new'
29
+ }.cs__freeze
30
+ FIBER_NEW_NODE = Contrast::Agent::Assess::Policy::PropagationNode.new(FIBER_NEW_NODE_HASH)
31
+ private_constant :FIBER_NEW_NODE_HASH
32
+ private_constant :FIBER_NEW_NODE
33
+
34
+ FIBER_YIELD_NODE_HASH = {
35
+ 'class_name' => 'Fiber',
36
+ 'instance_method' => true,
37
+ 'method_visibility' => 'public',
38
+ 'method_name' => 'c_yield',
39
+ 'action' => 'CUSTOM',
40
+ 'source' => 'O',
41
+ 'target' => 'R',
42
+ 'patch_class' => 'NOOP',
43
+ 'patch_method' => 'track_rb_fiber_yield'
44
+ }.cs__freeze
45
+ FIBER_YIELD_NODE = Contrast::Agent::Assess::Policy::PropagationNode.new(FIBER_YIELD_NODE_HASH)
46
+ private_constant :FIBER_YIELD_NODE_HASH
47
+ private_constant :FIBER_YIELD_NODE
48
+
49
+ class << self
50
+ def track_rb_fiber_yield fiber, _method, results
51
+ # results will be nil if StopIteration was raised,
52
+ # otherwise an Array of the yielded arguments
53
+ return if results.nil?
54
+
55
+ return unless ASSESS.enabled?
56
+
57
+ with_contrast_scope do
58
+ results.each do |result|
59
+ next unless Contrast::Utils::DuckUtils.quacks_like_cs_patched?(result)
60
+ next if result.cs__frozen?
61
+
62
+ cs__splat_tags(result, fiber)
63
+ result.cs__properties.build_event(
64
+ FIBER_YIELD_NODE,
65
+ result,
66
+ fiber,
67
+ result,
68
+ [])
69
+ end
70
+ end
71
+ end
72
+
73
+ def track_rb_fiber_new fiber, _enum, _enum_method, underlying, _underlying_method
74
+ return unless Contrast::Utils::DuckUtils.quacks_like_cs_patched?(underlying)
75
+ return unless underlying.is_a?(String) && !underlying.empty?
76
+
77
+ return unless ASSESS.enabled?
78
+
79
+ with_contrast_scope do
80
+ cs__splat_tags(fiber, underlying)
81
+ fiber.cs__properties.build_event(
82
+ FIBER_NEW_NODE,
83
+ fiber,
84
+ underlying,
85
+ fiber,
86
+ [])
87
+ end
88
+ end
89
+
90
+ def instrument_fiber_track
91
+ @_instrument_fiber_variables ||= begin
92
+ cs__scoped_require 'cs__assess_fiber_track/cs__assess_fiber_track'
93
+ true
94
+ end
95
+ rescue StandardError => e
96
+ logger.error(e, 'Error loading fiber track patch')
97
+ false
98
+ end
99
+
100
+ # Some propagation occurred, but we're not sure what the
101
+ # exact transformation was. To be safe, we just explode
102
+ # all the tags from the source to the return.
103
+ #
104
+ # If the return already had that tag, the existing tag
105
+ # range is recycled to save us an object.
106
+ def cs__splat_tags ret, source = self
107
+ source.cs__properties.tag_keys.each do |key|
108
+ length = Contrast::Utils::StringUtils.ret_length(ret)
109
+ existing = ret.cs__properties.fetch_tag(key)
110
+ # if the tag already exists, drop all but the first range
111
+ # then change that range to cover the entire return
112
+ if existing&.any?
113
+ existing.drop(existing.length - 1)
114
+ range = existing[0]
115
+ range.repurpose(0, length)
116
+ else
117
+ span = Contrast::Agent::Assess::AdjustedSpan.new(0, length)
118
+ ret.cs__properties.add_tag(key, span)
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ Fiber.instrument_fiber_track
@@ -0,0 +1,22 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ # This Class provides us with a way to invoke Hash propagation for those
5
+ # methods which are too complex to fit into one of the standard
6
+ # Contrast::Agent::Assess::Policy::Propagator molds.
7
+ class Hash
8
+ def self.cs__duplicate_and_freeze object
9
+ return object unless object.is_a?(String) && !object.cs__frozen?
10
+ return object unless object.cs__tracked?
11
+
12
+ object.dup.cs__freeze
13
+ rescue StandardError
14
+ logger.error("Unable to track dataflow through array for #{ object }")
15
+ end
16
+
17
+ def cs__bracket_set *args
18
+ Hash.cs__duplicate_and_freeze(args[0])
19
+ end
20
+ end
21
+
22
+ cs__scoped_require 'cs__assess_hash/cs__assess_hash'
@@ -0,0 +1,95 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ cs__scoped_require 'contrast/components/interface'
5
+ cs__scoped_require 'contrast/core_extensions/assess/exec_trigger'
6
+
7
+ # This module provides us with a way to invoke Kernel propagation for those
8
+ # methods which are too complex to fit into one of the standard
9
+ # Contrast::Agent::Assess::Policy::Propagator molds without cluttering up the
10
+ # Kernel Module or exposing our methods there.
11
+ module KernelPropagator
12
+ class << self
13
+ include Contrast::Components::Interface
14
+ include Contrast::CoreExtensions::Assess::ExecTrigger
15
+
16
+ access_component :logging
17
+
18
+ # We're 'tracking' sprintf now, meaning if anything is tracked on the way
19
+ # in, the entire result will be tracked out. We're going to take this
20
+ # approach for now b/c it's fast and easy. I don't super love it, and by
21
+ # that I mean I hate it.
22
+ #
23
+ # To actually track this, we'd have to find the index of the new things
24
+ # being added, then remove the tags at the range of the format marker,
25
+ # which is some arbitrary length thing, and add the new tags from the
26
+ # inserted string, shifted down by the length of the aforementioned
27
+ # marker.
28
+ #
29
+ # marker is in the format %[flags][width][.precision]type, type being a
30
+ # single character. We could regexp this with %.+[bBdiouxXeEfgGaAcps%]
31
+ #
32
+ # also, b/c Ruby hates us, there are things called absolute markers,
33
+ # (digit)$, that go in the flags section. These cannot be mixed w/ the
34
+ # order assumed type
35
+ #
36
+ # oh, and there's also %<name>type and %{name}... b/c of course there is
37
+ # -HM
38
+ def sprintf_tagger patcher, preshift, ret, _block
39
+ format_string = preshift.args[0]
40
+ args = preshift.args[1]
41
+
42
+ track_sprintf(ret, format_string, args)
43
+
44
+ ret.cs__properties.build_event(
45
+ patcher,
46
+ ret,
47
+ preshift.object,
48
+ ret,
49
+ preshift.args,
50
+ 1)
51
+ ret
52
+ end
53
+
54
+ def track_sprintf result, format_string, args
55
+ tracked_inputs = []
56
+ tracked_inputs << format_string if format_string.cs__tracked?
57
+ if args.is_a?(String)
58
+ tracked_inputs << args if args.cs__tracked?
59
+ elsif args.is_a?(Hash)
60
+ args.each_value do |value|
61
+ next unless Contrast::Utils::DuckUtils.quacks_to?(
62
+ value,
63
+ :cs__tracked?)
64
+ next unless value.cs__tracked?
65
+
66
+ tracked_inputs << value
67
+ end
68
+ elsif args.is_a?(Array)
69
+ args.each do |value|
70
+ next unless Contrast::Utils::DuckUtils.quacks_to?(value, :cs__tracked?)
71
+ next unless value.cs__tracked?
72
+
73
+ tracked_inputs << value
74
+ end
75
+ end
76
+ return result if tracked_inputs.empty?
77
+
78
+ tracked_inputs.each do |input|
79
+ input.cs__properties.events.each do |event|
80
+ result.cs__properties.events << event
81
+ end
82
+ input.cs__splat_tags(result)
83
+ end
84
+
85
+ result
86
+ rescue StandardError => e
87
+ logger.error(
88
+ e,
89
+ 'Unable to track dataflow through sprintf')
90
+ result
91
+ end
92
+ end
93
+ end
94
+
95
+ cs__scoped_require 'cs__assess_kernel/cs__assess_kernel'
@@ -0,0 +1,14 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ cs__scoped_require 'contrast/core_extensions/eval_trigger'
5
+
6
+ # Our patch into the Module class, allowing us to track calls to the eval
7
+ # method
8
+ class Module
9
+ class << self
10
+ include Contrast::CoreExtensions::Assess::EvalTrigger
11
+ end
12
+ end
13
+
14
+ cs__scoped_require 'cs__assess_module/cs__assess_module'
@@ -0,0 +1,206 @@
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
+ # Monkeypatch Ruby Regexp with Contrast Security tagging support
7
+ class Regexp
8
+ include Contrast::Components::Interface
9
+ include Contrast::CoreExtensions::Assess::AssessExtension
10
+
11
+ access_component :analysis, :logging, :scope
12
+
13
+ def cs__regexp_tagger info_hash
14
+ return unless ASSESS.enabled?
15
+
16
+ # Because we have a special case for this propagation,
17
+ # it falls out of regular scoping. As such, any patch to the `=~` method
18
+ # that goes through normal channels, like that for the redos rule,
19
+ # will force this to be in a scope of 1 (instead of the normal 0).
20
+ # As such, a scope of 1 here indicates that,
21
+ # so we know that we're in the top level call for this method.
22
+ # normal patch [-alias-]> special case patch [-alias-]> original method
23
+ # TODO: RUBY-686
24
+ return if scope_for_current_ec.instance_variable_get(:@contrast_scope) > 1
25
+
26
+ with_contrast_scope do
27
+ result = info_hash[:result]
28
+ return unless result
29
+
30
+ string = info_hash[:string] || nil
31
+ return unless string
32
+
33
+ regexp = info_hash[:regexp]
34
+ return unless (Contrast::Utils::DuckUtils.quacks_to?(string, :cs__tracked?) && string.cs__tracked?) ||
35
+ (Contrast::Utils::DuckUtils.quacks_to?(regexp, :cs__tracked?) && regexp.cs__tracked?)
36
+
37
+ Regexp.cs__splat_tags(info_hash[:back_ref], string)
38
+ Regexp.cs__build_event(ARRAY_NODE, info_hash[:back_ref], result, [string])
39
+ end
40
+ end
41
+
42
+ REGEXP_EQUAL_SQUIGGLE_HASH = {
43
+ 'id' => 'regexp_100',
44
+ 'class_name' => 'Regexp',
45
+ 'instance_method' => true,
46
+ 'method_visibility' => 'public',
47
+ 'method_name' => '=~',
48
+ 'source' => 'P0',
49
+ 'target' => 'R',
50
+ 'action' => 'KEEP'
51
+ }.cs__freeze
52
+ ARRAY_NODE = Contrast::Agent::Assess::Policy::PropagationNode.new(REGEXP_EQUAL_SQUIGGLE_HASH)
53
+ private_constant :REGEXP_EQUAL_SQUIGGLE_HASH
54
+ private_constant :ARRAY_NODE
55
+
56
+ REGEXP_MATCH_HASH = {
57
+ 'id' => 'regexp_101',
58
+ 'class_name' => 'Regexp',
59
+ 'instance_method' => true,
60
+ 'method_visibility' => 'public',
61
+ 'method_name' => 'match',
62
+ 'source' => 'P0',
63
+ 'target' => 'R',
64
+ 'action' => 'SPLAT'
65
+ }.cs__freeze
66
+ MATCH_NODE = Contrast::Agent::Assess::Policy::PropagationNode.new(REGEXP_MATCH_HASH)
67
+ private_constant :REGEXP_MATCH_HASH
68
+ private_constant :MATCH_NODE
69
+
70
+ POST_HASH = {
71
+ 'class_name' => 'MatchData',
72
+ 'instance_method' => true,
73
+ 'method_visibility' => 'public',
74
+ 'method_name' => 'post_match',
75
+ 'source' => 'O',
76
+ 'target' => 'R',
77
+ 'action' => 'REMOVE'
78
+ }.cs__freeze
79
+ POST_WEAVER = Contrast::Agent::Assess::Policy::PropagationNode.new(POST_HASH)
80
+ private_constant :POST_HASH
81
+ private_constant :POST_WEAVER
82
+
83
+ PRE_HASH = {
84
+ 'class_name' => 'MatchData',
85
+ 'instance_method' => true,
86
+ 'method_visibility' => 'public',
87
+ 'method_name' => 'pre_match',
88
+ 'source' => 'O',
89
+ 'target' => 'R',
90
+ 'action' => 'SPLAT'
91
+ }.cs__freeze
92
+ PRE_WEAVER = Contrast::Agent::Assess::Policy::PropagationNode.new(PRE_HASH)
93
+ private_constant :PRE_HASH
94
+ private_constant :PRE_WEAVER
95
+
96
+ LAST_PAREN_HASH = {
97
+ 'class_name' => 'MatchData',
98
+ 'instance_method' => true,
99
+ 'method_visibility' => 'public',
100
+ 'method_name' => 'last_paren',
101
+ 'source' => 'O',
102
+ 'target' => 'R',
103
+ 'action' => 'SPLAT'
104
+ }.cs__freeze
105
+ LAST_PAREN_WEAVER = Contrast::Agent::Assess::Policy::PropagationNode.new(LAST_PAREN_HASH)
106
+ private_constant :LAST_PAREN_HASH
107
+ private_constant :LAST_PAREN_WEAVER
108
+
109
+ NTH_HASH = {
110
+ 'class_name' => 'MatchData',
111
+ 'instance_method' => true,
112
+ 'method_visibility' => 'public',
113
+ 'method_name' => 'nth_match',
114
+ 'source' => 'O',
115
+ 'target' => 'R',
116
+ 'action' => 'SPLAT'
117
+ }.cs__freeze
118
+ NTH_WEAVER = Contrast::Agent::Assess::Policy::PropagationNode.new(NTH_HASH)
119
+ private_constant :NTH_HASH
120
+ private_constant :NTH_WEAVER
121
+
122
+ class << self
123
+ def track_rb_pre_match backref, target
124
+ track_rb_c(PRE_WEAVER, backref, target)
125
+ end
126
+
127
+ def track_rb_post_match backref, target
128
+ track_rb_c(POST_WEAVER, backref, target)
129
+ end
130
+
131
+ def track_rb_reg_match_last backref, target
132
+ track_rb_c(LAST_PAREN_WEAVER, backref, target)
133
+ end
134
+
135
+ def track_rb_n_match backref, target
136
+ track_rb_c(NTH_WEAVER, backref, target)
137
+ end
138
+
139
+ # Some propagation occurred, but we're not sure what the
140
+ # exact transformation was. To be safe, we just explode
141
+ # all the tags from the source to the return.
142
+ #
143
+ # If the return already had that tag, the existing tag
144
+ # range is recycled to save us an object.
145
+ def cs__splat_tags ret, source = self
146
+ source.cs__properties.tag_keys.each do |key|
147
+ length = Contrast::Utils::StringUtils.ret_length(ret)
148
+ existing = ret.cs__properties.fetch_tag(key)
149
+ # if the tag already exists, drop all but the first range
150
+ # then change that range to cover the entire return
151
+ if existing&.any?
152
+ existing.drop(existing.length - 1)
153
+ range = existing[0]
154
+ range.repurpose(0, length)
155
+ else
156
+ span = Contrast::Agent::Assess::AdjustedSpan.new(0, length)
157
+ ret.cs__properties.add_tag(key, span)
158
+ end
159
+ end
160
+ end
161
+
162
+ def cs__build_event node, target, ret, args
163
+ return unless Contrast::Utils::DuckUtils.quacks_to?(target, :cs__tracked?)
164
+ return unless target.cs__tracked?
165
+
166
+ target.cs__properties.build_event(
167
+ node,
168
+ target,
169
+ self,
170
+ ret,
171
+ args)
172
+ end
173
+
174
+ def instrument_regexp_track
175
+ @_instrument_regexp_variables ||= begin
176
+ cs__scoped_require 'cs__assess_regexp_track/cs__assess_regexp_track'
177
+ true
178
+ end
179
+ rescue StandardError => e
180
+ logger.error(e, 'Error loading regexp track patch')
181
+ false
182
+ end
183
+
184
+ private
185
+
186
+ def track_rb_c weaver, backref, target
187
+ return target unless ASSESS.enabled?
188
+ return target unless backref&.respond_to?(:cs__properties)
189
+ return target unless target.is_a?(String) && !target.empty?
190
+
191
+ with_contrast_scope do
192
+ cs__splat_tags(target, backref)
193
+ target.cs__properties.build_event(
194
+ weaver,
195
+ target,
196
+ self,
197
+ target,
198
+ [])
199
+ target
200
+ end
201
+ end
202
+ end
203
+ end
204
+
205
+ cs__scoped_require 'cs__assess_regexp/cs__assess_regexp'
206
+ Regexp.instrument_regexp_track