wg-metasploit_data_models 4.1.4.01 → 4.1.4.02

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 (440) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.github/workflows/verify.yml +68 -0
  4. data/.gitignore +29 -0
  5. data/.rspec +3 -0
  6. data/.simplecov +38 -0
  7. data/.yardopts +4 -0
  8. data/CHANGELOG.md +6 -0
  9. data/CONTRIBUTING.md +133 -0
  10. data/Gemfile +46 -0
  11. data/LICENSE +27 -0
  12. data/README.md +65 -0
  13. data/RELEASING.md +82 -0
  14. data/Rakefile +72 -0
  15. data/UPGRADING.md +1 -0
  16. data/app/models/mdm/api_key.rb +61 -0
  17. data/app/models/mdm/async_callback.rb +64 -0
  18. data/app/models/mdm/client.rb +50 -0
  19. data/app/models/mdm/cred.rb +205 -0
  20. data/app/models/mdm/event.rb +83 -0
  21. data/app/models/mdm/exploit_attempt.rb +105 -0
  22. data/app/models/mdm/exploited_host.rb +42 -0
  23. data/app/models/mdm/host.rb +619 -0
  24. data/app/models/mdm/host_detail.rb +62 -0
  25. data/app/models/mdm/host_tag.rb +49 -0
  26. data/app/models/mdm/listener.rb +82 -0
  27. data/app/models/mdm/loot.rb +161 -0
  28. data/app/models/mdm/macro.rb +62 -0
  29. data/app/models/mdm/mod_ref.rb +24 -0
  30. data/app/models/mdm/module/action.rb +33 -0
  31. data/app/models/mdm/module/arch.rb +28 -0
  32. data/app/models/mdm/module/author.rb +34 -0
  33. data/app/models/mdm/module/detail.rb +388 -0
  34. data/app/models/mdm/module/mixin.rb +31 -0
  35. data/app/models/mdm/module/platform.rb +29 -0
  36. data/app/models/mdm/module/ref.rb +42 -0
  37. data/app/models/mdm/module/target.rb +37 -0
  38. data/app/models/mdm/nexpose_console.rb +121 -0
  39. data/app/models/mdm/note.rb +125 -0
  40. data/app/models/mdm/payload.rb +103 -0
  41. data/app/models/mdm/profile.rb +45 -0
  42. data/app/models/mdm/ref.rb +48 -0
  43. data/app/models/mdm/route.rb +28 -0
  44. data/app/models/mdm/service.rb +267 -0
  45. data/app/models/mdm/session.rb +203 -0
  46. data/app/models/mdm/session_event.rb +44 -0
  47. data/app/models/mdm/tag.rb +114 -0
  48. data/app/models/mdm/task.rb +168 -0
  49. data/app/models/mdm/task_cred.rb +45 -0
  50. data/app/models/mdm/task_host.rb +41 -0
  51. data/app/models/mdm/task_service.rb +41 -0
  52. data/app/models/mdm/task_session.rb +41 -0
  53. data/app/models/mdm/user.rb +230 -0
  54. data/app/models/mdm/vuln.rb +204 -0
  55. data/app/models/mdm/vuln_attempt.rb +76 -0
  56. data/app/models/mdm/vuln_detail.rb +156 -0
  57. data/app/models/mdm/vuln_ref.rb +21 -0
  58. data/app/models/mdm/web_form.rb +53 -0
  59. data/app/models/mdm/web_page.rb +92 -0
  60. data/app/models/mdm/web_site.rb +113 -0
  61. data/app/models/mdm/web_vuln.rb +193 -0
  62. data/app/models/mdm/wmap_request.rb +101 -0
  63. data/app/models/mdm/wmap_target.rb +56 -0
  64. data/app/models/mdm/workspace.rb +286 -0
  65. data/app/models/metasploit_data_models/automatic_exploitation/match.rb +43 -0
  66. data/app/models/metasploit_data_models/automatic_exploitation/match_result.rb +71 -0
  67. data/app/models/metasploit_data_models/automatic_exploitation/match_set.rb +40 -0
  68. data/app/models/metasploit_data_models/automatic_exploitation/run.rb +29 -0
  69. data/app/models/metasploit_data_models/ip_address/v4/cidr.rb +14 -0
  70. data/app/models/metasploit_data_models/ip_address/v4/nmap.rb +14 -0
  71. data/app/models/metasploit_data_models/ip_address/v4/range.rb +12 -0
  72. data/app/models/metasploit_data_models/ip_address/v4/segment/nmap/list.rb +125 -0
  73. data/app/models/metasploit_data_models/ip_address/v4/segment/nmap/range.rb +12 -0
  74. data/app/models/metasploit_data_models/ip_address/v4/segment/single.rb +123 -0
  75. data/app/models/metasploit_data_models/ip_address/v4/segmented.rb +200 -0
  76. data/app/models/metasploit_data_models/ip_address/v4/single.rb +53 -0
  77. data/app/models/metasploit_data_models/module_run.rb +213 -0
  78. data/app/models/metasploit_data_models/search/operation/ip_address.rb +60 -0
  79. data/app/models/metasploit_data_models/search/operation/port/number.rb +25 -0
  80. data/app/models/metasploit_data_models/search/operation/port/range.rb +79 -0
  81. data/app/models/metasploit_data_models/search/operation/range.rb +56 -0
  82. data/app/models/metasploit_data_models/search/operator/ip_address.rb +33 -0
  83. data/app/models/metasploit_data_models/search/operator/multitext.rb +73 -0
  84. data/app/models/metasploit_data_models/search/operator/port/list.rb +67 -0
  85. data/app/models/metasploit_data_models/search/visitor/attribute.rb +17 -0
  86. data/app/models/metasploit_data_models/search/visitor/includes.rb +47 -0
  87. data/app/models/metasploit_data_models/search/visitor/joins.rb +67 -0
  88. data/app/models/metasploit_data_models/search/visitor/method.rb +16 -0
  89. data/app/models/metasploit_data_models/search/visitor/relation.rb +91 -0
  90. data/app/models/metasploit_data_models/search/visitor/where.rb +128 -0
  91. data/config/initializers/arel_helper.rb +5 -0
  92. data/config/initializers/ipaddr.rb +29 -0
  93. data/config/locales/en.yml +94 -0
  94. data/console_db.yml +9 -0
  95. data/db/migrate/000_create_tables.rb +79 -0
  96. data/db/migrate/001_add_wmap_tables.rb +35 -0
  97. data/db/migrate/002_add_workspaces.rb +36 -0
  98. data/db/migrate/003_move_notes.rb +20 -0
  99. data/db/migrate/004_add_events_table.rb +16 -0
  100. data/db/migrate/005_expand_info.rb +58 -0
  101. data/db/migrate/006_add_timestamps.rb +26 -0
  102. data/db/migrate/007_add_loots.rb +20 -0
  103. data/db/migrate/008_create_users.rb +16 -0
  104. data/db/migrate/009_add_loots_ctype.rb +10 -0
  105. data/db/migrate/010_add_alert_fields.rb +16 -0
  106. data/db/migrate/011_add_reports.rb +19 -0
  107. data/db/migrate/012_add_tasks.rb +24 -0
  108. data/db/migrate/013_add_tasks_result.rb +10 -0
  109. data/db/migrate/014_add_loots_fields.rb +12 -0
  110. data/db/migrate/015_rename_user.rb +16 -0
  111. data/db/migrate/016_add_host_purpose.rb +10 -0
  112. data/db/migrate/017_expand_info2.rb +58 -0
  113. data/db/migrate/018_add_workspace_user_info.rb +29 -0
  114. data/db/migrate/019_add_workspace_desc.rb +23 -0
  115. data/db/migrate/020_add_user_preferences.rb +11 -0
  116. data/db/migrate/021_standardize_info_and_data.rb +18 -0
  117. data/db/migrate/022_enlarge_event_info.rb +10 -0
  118. data/db/migrate/023_add_report_downloaded_at.rb +10 -0
  119. data/db/migrate/024_convert_service_info_to_text.rb +12 -0
  120. data/db/migrate/025_add_user_admin.rb +19 -0
  121. data/db/migrate/026_add_creds_table.rb +19 -0
  122. data/db/migrate/20100819123300_migrate_cred_data.rb +154 -0
  123. data/db/migrate/20100824151500_add_exploited_table.rb +16 -0
  124. data/db/migrate/20100908001428_add_owner_to_workspaces.rb +9 -0
  125. data/db/migrate/20100911122000_add_report_templates.rb +18 -0
  126. data/db/migrate/20100916151530_require_admin_flag.rb +15 -0
  127. data/db/migrate/20100916175000_add_campaigns_and_templates.rb +61 -0
  128. data/db/migrate/20100920012100_add_generate_exe_column.rb +8 -0
  129. data/db/migrate/20100926214000_add_template_prefs.rb +11 -0
  130. data/db/migrate/20101001000000_add_web_tables.rb +57 -0
  131. data/db/migrate/20101002000000_add_query.rb +10 -0
  132. data/db/migrate/20101007000000_add_vuln_info.rb +15 -0
  133. data/db/migrate/20101008111800_add_clients_to_campaigns.rb +10 -0
  134. data/db/migrate/20101009023300_add_campaign_attachments.rb +15 -0
  135. data/db/migrate/20101104135100_add_imported_creds.rb +17 -0
  136. data/db/migrate/20101203000000_fix_web_tables.rb +34 -0
  137. data/db/migrate/20101203000001_expand_host_comment.rb +12 -0
  138. data/db/migrate/20101206212033_add_limit_to_network_to_workspaces.rb +9 -0
  139. data/db/migrate/20110112154300_add_module_uuid_to_tasks.rb +9 -0
  140. data/db/migrate/20110204112800_add_host_tags.rb +28 -0
  141. data/db/migrate/20110317144932_add_session_table.rb +110 -0
  142. data/db/migrate/20110414180600_add_local_id_to_session_table.rb +11 -0
  143. data/db/migrate/20110415175705_add_routes_table.rb +18 -0
  144. data/db/migrate/20110422000000_convert_binary.rb +73 -0
  145. data/db/migrate/20110425095900_add_last_seen_to_sessions.rb +8 -0
  146. data/db/migrate/20110513143900_track_successful_exploits.rb +31 -0
  147. data/db/migrate/20110517160800_rename_and_prune_nessus_vulns.rb +26 -0
  148. data/db/migrate/20110527000000_add_task_id_to_reports_table.rb +11 -0
  149. data/db/migrate/20110527000001_add_api_keys_table.rb +12 -0
  150. data/db/migrate/20110606000001_add_macros_table.rb +16 -0
  151. data/db/migrate/20110622000000_add_settings_to_tasks_table.rb +12 -0
  152. data/db/migrate/20110624000001_add_listeners_table.rb +19 -0
  153. data/db/migrate/20110625000001_add_macro_to_listeners_table.rb +12 -0
  154. data/db/migrate/20110630000001_add_nexpose_consoles_table.rb +21 -0
  155. data/db/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb +12 -0
  156. data/db/migrate/20110717000001_add_profiles_table.rb +15 -0
  157. data/db/migrate/20110727163801_expand_cred_ptype_column.rb +9 -0
  158. data/db/migrate/20110730000001_add_initial_indexes.rb +85 -0
  159. data/db/migrate/20110812000001_prune_indexes.rb +23 -0
  160. data/db/migrate/20110922000000_expand_notes.rb +9 -0
  161. data/db/migrate/20110928101300_add_mod_ref_table.rb +17 -0
  162. data/db/migrate/20111011110000_add_display_name_to_reports_table.rb +24 -0
  163. data/db/migrate/20111203000000_inet_columns.rb +13 -0
  164. data/db/migrate/20111204000000_more_inet_columns.rb +17 -0
  165. data/db/migrate/20111210000000_add_scope_to_hosts.rb +9 -0
  166. data/db/migrate/20120126110000_add_virtual_host_to_hosts.rb +9 -0
  167. data/db/migrate/20120411173220_rename_workspace_members.rb +9 -0
  168. data/db/migrate/20120601152442_add_counter_caches_to_hosts.rb +21 -0
  169. data/db/migrate/20120625000000_add_vuln_details.rb +34 -0
  170. data/db/migrate/20120625000001_add_host_details.rb +16 -0
  171. data/db/migrate/20120625000002_expand_details.rb +16 -0
  172. data/db/migrate/20120625000003_expand_details2.rb +24 -0
  173. data/db/migrate/20120625000004_add_vuln_attempts.rb +19 -0
  174. data/db/migrate/20120625000005_add_vuln_and_host_counter_caches.rb +14 -0
  175. data/db/migrate/20120625000006_add_module_details.rb +118 -0
  176. data/db/migrate/20120625000007_add_exploit_attempts.rb +26 -0
  177. data/db/migrate/20120625000008_add_fail_message.rb +12 -0
  178. data/db/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb +13 -0
  179. data/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb +19 -0
  180. data/db/migrate/20130412154159_change_foreign_key_in_module_actions.rb +25 -0
  181. data/db/migrate/20130412171844_change_foreign_key_in_module_archs.rb +25 -0
  182. data/db/migrate/20130412173121_change_foreign_key_in_module_authors.rb +25 -0
  183. data/db/migrate/20130412173640_change_foreign_key_in_module_mixins.rb +25 -0
  184. data/db/migrate/20130412174254_change_foreign_key_in_module_platforms.rb +25 -0
  185. data/db/migrate/20130412174719_change_foreign_key_in_module_refs.rb +25 -0
  186. data/db/migrate/20130412175040_change_foreign_key_in_module_targets.rb +25 -0
  187. data/db/migrate/20130423211152_add_creds_counter_cache.rb +24 -0
  188. data/db/migrate/20130430151353_change_required_columns_to_null_false_in_hosts.rb +11 -0
  189. data/db/migrate/20130430162145_enforce_address_uniqueness_in_workspace_in_hosts.rb +101 -0
  190. data/db/migrate/20130510021637_remove_campaigns.rb +11 -0
  191. data/db/migrate/20130515164311_change_web_vulns_confidence_to_integer.rb +48 -0
  192. data/db/migrate/20130515172727_valid_mdm_web_vuln_params.rb +30 -0
  193. data/db/migrate/20130516204810_making_vulns_refs_a_real_ar_model.rb +5 -0
  194. data/db/migrate/20130522001343_create_task_creds.rb +9 -0
  195. data/db/migrate/20130522032517_create_task_hosts.rb +9 -0
  196. data/db/migrate/20130522041110_create_task_services.rb +9 -0
  197. data/db/migrate/20130525015035_remove_campaign_id_from_clients.rb +9 -0
  198. data/db/migrate/20130525212420_drop_table_imported_creds.rb +14 -0
  199. data/db/migrate/20130531144949_making_host_tags_a_real_ar_model.rb +6 -0
  200. data/db/migrate/20130604145732_create_task_sessions.rb +9 -0
  201. data/db/migrate/20130717150737_remove_pname_validation.rb +7 -0
  202. data/db/migrate/20131002004641_create_automatic_exploitation_matches.rb +13 -0
  203. data/db/migrate/20131002164449_create_automatic_exploitation_match_sets.rb +12 -0
  204. data/db/migrate/20131008213344_create_automatic_exploitation_runs.rb +11 -0
  205. data/db/migrate/20131011184338_module_detail_on_automatic_exploitation_match.rb +10 -0
  206. data/db/migrate/20131017150735_create_automatic_exploitation_match_results.rb +11 -0
  207. data/db/migrate/20131021185657_make_match_polymorphic.rb +11 -0
  208. data/db/migrate/20140905031549_add_detected_arch_to_host.rb +5 -0
  209. data/db/migrate/20150112203945_remove_duplicate_services.rb +17 -0
  210. data/db/migrate/20150205192745_drop_service_uniqueness_index.rb +5 -0
  211. data/db/migrate/20150209195939_add_vuln_id_to_note.rb +6 -0
  212. data/db/migrate/20150212214222_remove_duplicate_services2.rb +17 -0
  213. data/db/migrate/20150219173821_create_module_runs.rb +23 -0
  214. data/db/migrate/20150219215039_add_module_run_to_session.rb +8 -0
  215. data/db/migrate/20150226151459_add_module_run_fk_to_loot.rb +8 -0
  216. data/db/migrate/20150312155312_add_module_full_name_to_match.rb +6 -0
  217. data/db/migrate/20150317145455_rename_module_indices.rb +29 -0
  218. data/db/migrate/20150326183742_add_missing_ae_indices.rb +13 -0
  219. data/db/migrate/20150421211719_rename_automatic_exploitation_index.rb +16 -0
  220. data/db/migrate/20150514182921_add_origin_to_mdm_vuln.rb +13 -0
  221. data/db/migrate/20160415153312_remove_not_null_from_web_vuln_p_arams.rb +5 -0
  222. data/db/migrate/20161004165612_add_fingerprinted_to_workspace.rb +5 -0
  223. data/db/migrate/20161227212223_add_os_family_to_hosts.rb +5 -0
  224. data/db/migrate/20180904120211_create_payloads.rb +21 -0
  225. data/db/migrate/20190308134512_create_async_callbacks.rb +13 -0
  226. data/db/migrate/20190507120211_remove_payload_workspaces.rb +5 -0
  227. data/lib/mdm/host/operating_system_normalization.rb +942 -0
  228. data/lib/mdm/module.rb +13 -0
  229. data/lib/mdm.rb +57 -0
  230. data/lib/metasploit_data_models/automatic_exploitation.rb +25 -0
  231. data/lib/metasploit_data_models/base64_serializer.rb +99 -0
  232. data/lib/metasploit_data_models/change_required_columns_to_null_false.rb +21 -0
  233. data/lib/metasploit_data_models/engine.rb +32 -0
  234. data/lib/metasploit_data_models/ip_address/cidr.rb +174 -0
  235. data/lib/metasploit_data_models/ip_address/range.rb +181 -0
  236. data/lib/metasploit_data_models/ip_address/v4/segment/nmap.rb +7 -0
  237. data/lib/metasploit_data_models/ip_address/v4/segment.rb +7 -0
  238. data/lib/metasploit_data_models/ip_address/v4.rb +11 -0
  239. data/lib/metasploit_data_models/ip_address.rb +9 -0
  240. data/lib/metasploit_data_models/match/child.rb +48 -0
  241. data/lib/metasploit_data_models/match/parent.rb +103 -0
  242. data/lib/metasploit_data_models/match.rb +8 -0
  243. data/lib/metasploit_data_models/search/operation/port.rb +9 -0
  244. data/lib/metasploit_data_models/search/operation.rb +9 -0
  245. data/lib/metasploit_data_models/search/operator/port.rb +6 -0
  246. data/lib/metasploit_data_models/search/operator.rb +8 -0
  247. data/lib/metasploit_data_models/search/visitor.rb +11 -0
  248. data/lib/metasploit_data_models/search.rb +8 -0
  249. data/lib/metasploit_data_models/serialized_prefs.rb +27 -0
  250. data/lib/metasploit_data_models/version.rb +13 -0
  251. data/lib/metasploit_data_models.rb +56 -0
  252. data/metasploit_data_models.gemspec +65 -0
  253. data/script/rails +8 -0
  254. data/spec/app/models/mdm/api_key_spec.rb +3 -0
  255. data/spec/app/models/mdm/client_spec.rb +43 -0
  256. data/spec/app/models/mdm/cred_spec.rb +346 -0
  257. data/spec/app/models/mdm/event_spec.rb +90 -0
  258. data/spec/app/models/mdm/exploit_attempt_spec.rb +59 -0
  259. data/spec/app/models/mdm/exploited_host_spec.rb +44 -0
  260. data/spec/app/models/mdm/host_detail_spec.rb +48 -0
  261. data/spec/app/models/mdm/host_spec.rb +1139 -0
  262. data/spec/app/models/mdm/host_tag_spec.rb +69 -0
  263. data/spec/app/models/mdm/listener_spec.rb +107 -0
  264. data/spec/app/models/mdm/loot_spec.rb +84 -0
  265. data/spec/app/models/mdm/macro_spec.rb +3 -0
  266. data/spec/app/models/mdm/mod_ref_spec.rb +3 -0
  267. data/spec/app/models/mdm/module/action_spec.rb +34 -0
  268. data/spec/app/models/mdm/module/arch_spec.rb +34 -0
  269. data/spec/app/models/mdm/module/author_spec.rb +52 -0
  270. data/spec/app/models/mdm/module/detail_spec.rb +746 -0
  271. data/spec/app/models/mdm/module/mixin_spec.rb +34 -0
  272. data/spec/app/models/mdm/module/platform_spec.rb +34 -0
  273. data/spec/app/models/mdm/module/ref_spec.rb +58 -0
  274. data/spec/app/models/mdm/module/target_spec.rb +36 -0
  275. data/spec/app/models/mdm/nexpose_console_spec.rb +146 -0
  276. data/spec/app/models/mdm/note_spec.rb +91 -0
  277. data/spec/app/models/mdm/profile_spec.rb +3 -0
  278. data/spec/app/models/mdm/ref_spec.rb +71 -0
  279. data/spec/app/models/mdm/route_spec.rb +35 -0
  280. data/spec/app/models/mdm/service_spec.rb +232 -0
  281. data/spec/app/models/mdm/session_event_spec.rb +42 -0
  282. data/spec/app/models/mdm/session_spec.rb +118 -0
  283. data/spec/app/models/mdm/tag_spec.rb +116 -0
  284. data/spec/app/models/mdm/task_cred_spec.rb +51 -0
  285. data/spec/app/models/mdm/task_host_spec.rb +50 -0
  286. data/spec/app/models/mdm/task_service_spec.rb +50 -0
  287. data/spec/app/models/mdm/task_session_spec.rb +46 -0
  288. data/spec/app/models/mdm/task_spec.rb +71 -0
  289. data/spec/app/models/mdm/user_spec.rb +50 -0
  290. data/spec/app/models/mdm/vuln_attempt_spec.rb +53 -0
  291. data/spec/app/models/mdm/vuln_detail_spec.rb +65 -0
  292. data/spec/app/models/mdm/vuln_ref_spec.rb +46 -0
  293. data/spec/app/models/mdm/vuln_spec.rb +299 -0
  294. data/spec/app/models/mdm/web_form_spec.rb +46 -0
  295. data/spec/app/models/mdm/web_page_spec.rb +101 -0
  296. data/spec/app/models/mdm/web_site_spec.rb +85 -0
  297. data/spec/app/models/mdm/web_vuln_spec.rb +312 -0
  298. data/spec/app/models/mdm/wmap_request_spec.rb +5 -0
  299. data/spec/app/models/mdm/wmap_target_spec.rb +5 -0
  300. data/spec/app/models/mdm/workspace_spec.rb +500 -0
  301. data/spec/app/models/metasploit_data_models/automatic_exploitation/match_result_spec.rb +86 -0
  302. data/spec/app/models/metasploit_data_models/automatic_exploitation/match_set_spec.rb +46 -0
  303. data/spec/app/models/metasploit_data_models/automatic_exploitation/match_spec.rb +37 -0
  304. data/spec/app/models/metasploit_data_models/automatic_exploitation/run_spec.rb +38 -0
  305. data/spec/app/models/metasploit_data_models/ip_address/v4/cidr_spec.rb +119 -0
  306. data/spec/app/models/metasploit_data_models/ip_address/v4/nmap_spec.rb +149 -0
  307. data/spec/app/models/metasploit_data_models/ip_address/v4/range_spec.rb +298 -0
  308. data/spec/app/models/metasploit_data_models/ip_address/v4/segment/nmap/list_spec.rb +276 -0
  309. data/spec/app/models/metasploit_data_models/ip_address/v4/segment/nmap/range_spec.rb +302 -0
  310. data/spec/app/models/metasploit_data_models/ip_address/v4/segment/segmented_spec.rb +27 -0
  311. data/spec/app/models/metasploit_data_models/ip_address/v4/segment/single_spec.rb +324 -0
  312. data/spec/app/models/metasploit_data_models/ip_address/v4/single_spec.rb +181 -0
  313. data/spec/app/models/metasploit_data_models/module_run_spec.rb +134 -0
  314. data/spec/app/models/metasploit_data_models/search/operation/ip_address_spec.rb +180 -0
  315. data/spec/app/models/metasploit_data_models/search/operation/port/number_spec.rb +39 -0
  316. data/spec/app/models/metasploit_data_models/search/operation/port/range_spec.rb +138 -0
  317. data/spec/app/models/metasploit_data_models/search/operation/range_spec.rb +233 -0
  318. data/spec/app/models/metasploit_data_models/search/operator/ip_address_spec.rb +17 -0
  319. data/spec/app/models/metasploit_data_models/search/operator/multitext_spec.rb +160 -0
  320. data/spec/app/models/metasploit_data_models/search/operator/port/list_spec.rb +162 -0
  321. data/spec/app/models/metasploit_data_models/search/visitor/attribute_spec.rb +96 -0
  322. data/spec/app/models/metasploit_data_models/search/visitor/includes_spec.rb +175 -0
  323. data/spec/app/models/metasploit_data_models/search/visitor/joins_spec.rb +396 -0
  324. data/spec/app/models/metasploit_data_models/search/visitor/method_spec.rb +49 -0
  325. data/spec/app/models/metasploit_data_models/search/visitor/relation_spec.rb +925 -0
  326. data/spec/app/models/metasploit_data_models/search/visitor/where_spec.rb +187 -0
  327. data/spec/dummy/Rakefile +7 -0
  328. data/spec/dummy/app/assets/config/manifest.js +1 -0
  329. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  330. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  331. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  332. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  333. data/spec/dummy/app/mailers/.gitkeep +0 -0
  334. data/spec/dummy/app/models/.gitkeep +0 -0
  335. data/spec/dummy/app/models/application_record.rb +3 -0
  336. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  337. data/spec/dummy/bin/bundle +3 -0
  338. data/spec/dummy/bin/rails +4 -0
  339. data/spec/dummy/bin/rake +4 -0
  340. data/spec/dummy/config/application.rb +61 -0
  341. data/spec/dummy/config/boot.rb +4 -0
  342. data/spec/dummy/config/database.yml.example +22 -0
  343. data/spec/dummy/config/database.yml.github_actions +21 -0
  344. data/spec/dummy/config/environment.rb +5 -0
  345. data/spec/dummy/config/environments/development.rb +37 -0
  346. data/spec/dummy/config/environments/production.rb +78 -0
  347. data/spec/dummy/config/environments/test.rb +39 -0
  348. data/spec/dummy/config/initializers/active_record_migrations.rb +4 -0
  349. data/spec/dummy/config/initializers/assets.rb +8 -0
  350. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  351. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  352. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  353. data/spec/dummy/config/initializers/inflections.rb +16 -0
  354. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  355. data/spec/dummy/config/initializers/session_store.rb +3 -0
  356. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  357. data/spec/dummy/config/locales/en.yml +23 -0
  358. data/spec/dummy/config/routes.rb +2 -0
  359. data/spec/dummy/config.ru +4 -0
  360. data/spec/dummy/db/structure.sql +3430 -0
  361. data/spec/dummy/db/structure.sql.from_rails_3 +3403 -0
  362. data/spec/dummy/lib/assets/.gitkeep +0 -0
  363. data/spec/dummy/log/.gitkeep +0 -0
  364. data/spec/dummy/public/404.html +26 -0
  365. data/spec/dummy/public/422.html +26 -0
  366. data/spec/dummy/public/500.html +25 -0
  367. data/spec/dummy/public/favicon.ico +0 -0
  368. data/spec/dummy/script/rails +6 -0
  369. data/spec/factories/mdm/addresses.rb +12 -0
  370. data/spec/factories/mdm/clients.rb +8 -0
  371. data/spec/factories/mdm/creds.rb +17 -0
  372. data/spec/factories/mdm/events.rb +15 -0
  373. data/spec/factories/mdm/exploit_attempts.rb +8 -0
  374. data/spec/factories/mdm/exploited_hosts.rb +7 -0
  375. data/spec/factories/mdm/fingerprints/nessus_fingerprints.rb +6 -0
  376. data/spec/factories/mdm/fingerprints/nexpose_fingerprints.rb +6 -0
  377. data/spec/factories/mdm/fingerprints/nmap_fingerprints.rb +6 -0
  378. data/spec/factories/mdm/fingerprints/retina_fingerprints.rb +6 -0
  379. data/spec/factories/mdm/fingerprints/session_fingerprints.rb +6 -0
  380. data/spec/factories/mdm/host_details.rb +8 -0
  381. data/spec/factories/mdm/host_tags.rb +9 -0
  382. data/spec/factories/mdm/hosts.rb +85 -0
  383. data/spec/factories/mdm/listeners.rb +12 -0
  384. data/spec/factories/mdm/loots.rb +11 -0
  385. data/spec/factories/mdm/module/actions.rb +14 -0
  386. data/spec/factories/mdm/module/archs.rb +14 -0
  387. data/spec/factories/mdm/module/authors.rb +22 -0
  388. data/spec/factories/mdm/module/details.rb +73 -0
  389. data/spec/factories/mdm/module/mixins.rb +14 -0
  390. data/spec/factories/mdm/module/platforms.rb +14 -0
  391. data/spec/factories/mdm/module/refs.rb +14 -0
  392. data/spec/factories/mdm/module/targets.rb +19 -0
  393. data/spec/factories/mdm/nexpose_consoles.rb +15 -0
  394. data/spec/factories/mdm/notes.rb +12 -0
  395. data/spec/factories/mdm/refs.rb +9 -0
  396. data/spec/factories/mdm/routes.rb +36 -0
  397. data/spec/factories/mdm/services.rb +41 -0
  398. data/spec/factories/mdm/session_events.rb +8 -0
  399. data/spec/factories/mdm/sessions.rb +13 -0
  400. data/spec/factories/mdm/tags.rb +14 -0
  401. data/spec/factories/mdm/task.rb +16 -0
  402. data/spec/factories/mdm/task_creds.rb +9 -0
  403. data/spec/factories/mdm/task_hosts.rb +9 -0
  404. data/spec/factories/mdm/task_services.rb +8 -0
  405. data/spec/factories/mdm/task_sessions.rb +8 -0
  406. data/spec/factories/mdm/users.rb +22 -0
  407. data/spec/factories/mdm/vuln_attempts.rb +8 -0
  408. data/spec/factories/mdm/vuln_details.rb +8 -0
  409. data/spec/factories/mdm/vuln_refs.rb +4 -0
  410. data/spec/factories/mdm/vulns.rb +20 -0
  411. data/spec/factories/mdm/web_forms.rb +33 -0
  412. data/spec/factories/mdm/web_pages.rb +64 -0
  413. data/spec/factories/mdm/web_sites.rb +8 -0
  414. data/spec/factories/mdm/web_vulns.rb +64 -0
  415. data/spec/factories/mdm/workspaces.rb +23 -0
  416. data/spec/factories/metasploit_data_models/automatic_exploitation/match_results.rb +7 -0
  417. data/spec/factories/metasploit_data_models/automatic_exploitation/match_sets.rb +8 -0
  418. data/spec/factories/metasploit_data_models/automatic_exploitation/matches.rb +7 -0
  419. data/spec/factories/metasploit_data_models/automatic_exploitation/runs.rb +6 -0
  420. data/spec/factories/module_runs.rb +40 -0
  421. data/spec/lib/base64_serializer_spec.rb +172 -0
  422. data/spec/lib/ipaddr_spec.rb +29 -0
  423. data/spec/lib/metasploit_data_models/ip_address/cidr_spec.rb +356 -0
  424. data/spec/lib/metasploit_data_models/ip_address/range_spec.rb +75 -0
  425. data/spec/lib/metasploit_data_models/match/child_spec.rb +59 -0
  426. data/spec/lib/metasploit_data_models/match/parent_spec.rb +153 -0
  427. data/spec/lib/metasploit_data_models_spec.rb +13 -0
  428. data/spec/spec_helper.rb +148 -0
  429. data/spec/support/matchers/match_regex_exactly.rb +28 -0
  430. data/spec/support/shared/contexts/rex/text.rb +15 -0
  431. data/spec/support/shared/examples/coerces_inet_column_type_to_string.rb +15 -0
  432. data/spec/support/shared/examples/mdm/module/detail/does_not_support_stance_with_mtype.rb +20 -0
  433. data/spec/support/shared/examples/mdm/module/detail/supports_stance_with_mtype.rb +36 -0
  434. data/spec/support/shared/examples/metasploit_data_models/search/operation/ipaddress/match.rb +109 -0
  435. data/spec/support/shared/examples/metasploit_data_models/search/visitor/includes/visit/with_children.rb +38 -0
  436. data/spec/support/shared/examples/metasploit_data_models/search/visitor/includes/visit/with_metasploit_model_search_operation_base.rb +26 -0
  437. data/spec/support/shared/examples/metasploit_data_models/search/visitor/relation/visit/matching_record.rb +50 -0
  438. data/spec/support/shared/examples/metasploit_data_models/search/visitor/where/visit/with_equality.rb +34 -0
  439. data/spec/support/shared/examples/metasploit_data_models/search/visitor/where/visit/with_metasploit_model_search_group_base.rb +51 -0
  440. metadata +444 -6
@@ -0,0 +1,1139 @@
1
+ RSpec.describe Mdm::Host, type: :model do
2
+ include_context 'Rex::Text'
3
+
4
+ subject(:host) do
5
+ FactoryBot.build(:mdm_host)
6
+ end
7
+
8
+ let(:architectures) do
9
+ [
10
+ 'armbe',
11
+ 'armle',
12
+ 'cbea',
13
+ 'cbea64',
14
+ 'cmd',
15
+ 'java',
16
+ 'mips',
17
+ 'mipsbe',
18
+ 'mipsle',
19
+ 'php',
20
+ 'ppc',
21
+ 'ppc64',
22
+ 'ruby',
23
+ 'sparc',
24
+ 'tty',
25
+ 'x64',
26
+ 'x86',
27
+ 'x86_64',
28
+ '',
29
+ 'Unknown',
30
+ ]
31
+ end
32
+
33
+ let(:states) do
34
+ [
35
+ 'alive',
36
+ 'down',
37
+ 'unknown'
38
+ ]
39
+ end
40
+
41
+ it_should_behave_like 'Metasploit::Concern.run'
42
+
43
+ context 'factory' do
44
+ context 'mdm_host' do
45
+ subject(:mdm_host) {
46
+ FactoryBot.build(:mdm_host)
47
+ }
48
+
49
+ it { is_expected.to be_valid }
50
+ end
51
+ end
52
+
53
+ context 'Constants' do
54
+ subject(:max_nmap_certainty) { described_class::MAX_NMAP_CERTAINTY }
55
+ it { is_expected.to eq(0.84) }
56
+ end
57
+
58
+ describe 'MAC address format validation' do
59
+ context 'when colon delimited' do
60
+ it 'is valid' do
61
+ host = FactoryBot.build(:mdm_host, mac: '1a:2B:3c:4D:5e:6f')
62
+ expect(host).to be_valid
63
+ end
64
+ end
65
+
66
+ context 'when hyphen delimited' do
67
+ it 'is valid' do
68
+ host = FactoryBot.build(:mdm_host, mac: '1a-2B-3c-4D-5e-6f')
69
+ expect(host).to be_valid
70
+ end
71
+ end
72
+
73
+ context 'when mixed colon-hyphen delimited ' do
74
+ it 'is invalid' do
75
+ host = FactoryBot.build(:mdm_host, mac: '1a:2B:3c-4D:5e:6f')
76
+ expect(host).to be_invalid
77
+ end
78
+ end
79
+ end
80
+
81
+ context '#destroy' do
82
+ it 'should successfully destroy the object and the dependent objects' do
83
+ host = FactoryBot.create(:mdm_host)
84
+ exploit_attempt = FactoryBot.create(:mdm_exploit_attempt, :host => host)
85
+ exploited_host = FactoryBot.create(:mdm_exploited_host, :host => host)
86
+ host_detail = FactoryBot.create(:mdm_host_detail, :host => host)
87
+ loot = FactoryBot.create(:mdm_loot, :host => host)
88
+ task_host = FactoryBot.create(:mdm_task_host, :host => host)
89
+ note = FactoryBot.create(:mdm_note, :host => host)
90
+ svc = FactoryBot.create(:mdm_service, :host => host)
91
+ session = FactoryBot.create(:mdm_session, :host => host)
92
+ vuln = FactoryBot.create(:mdm_vuln, :host => host)
93
+
94
+
95
+ expect {
96
+ host.destroy
97
+ }.to_not raise_error
98
+ expect {
99
+ host.reload
100
+ }.to raise_error(ActiveRecord::RecordNotFound)
101
+ expect {
102
+ exploit_attempt.reload
103
+ }.to raise_error(ActiveRecord::RecordNotFound)
104
+ expect {
105
+ exploited_host.reload
106
+ }.to raise_error(ActiveRecord::RecordNotFound)
107
+ expect {
108
+ host_detail.reload
109
+ }.to raise_error(ActiveRecord::RecordNotFound)
110
+ expect {
111
+ loot.reload
112
+ }.to raise_error(ActiveRecord::RecordNotFound)
113
+ expect {
114
+ task_host.reload
115
+ }.to raise_error(ActiveRecord::RecordNotFound)
116
+ expect {
117
+ note.reload
118
+ }.to raise_error(ActiveRecord::RecordNotFound)
119
+ expect {
120
+ svc.reload
121
+ }.to raise_error(ActiveRecord::RecordNotFound)
122
+ expect {
123
+ session.reload
124
+ }.to raise_error(ActiveRecord::RecordNotFound)
125
+ expect {
126
+ vuln.reload
127
+ }.to raise_error(ActiveRecord::RecordNotFound)
128
+ end
129
+ end
130
+
131
+ context 'associations' do
132
+ it { is_expected.to have_many(:creds).class_name('Mdm::Cred').through(:services) }
133
+ it { is_expected.to have_many(:clients).class_name('Mdm::Client').dependent(:destroy) }
134
+ it { is_expected.to have_many(:exploit_attempts).class_name('Mdm::ExploitAttempt').dependent(:destroy) }
135
+ it { is_expected.to have_many(:exploited_hosts).class_name('Mdm::ExploitedHost').dependent(:destroy) }
136
+ it { is_expected.to have_many(:host_details).class_name('Mdm::HostDetail').dependent(:destroy) }
137
+ it { is_expected.to have_many(:hosts_tags).class_name('Mdm::HostTag') }
138
+ it { is_expected.to have_many(:loots).class_name('Mdm::Loot').dependent(:destroy).order('loots.created_at DESC') }
139
+ it { is_expected.to have_many(:module_runs).class_name('MetasploitDataModels::ModuleRun') }
140
+ it { is_expected.to have_many(:task_hosts).class_name('Mdm::TaskHost').dependent(:destroy) }
141
+ it { is_expected.to have_many(:tasks).class_name('Mdm::Task').through(:task_hosts) }
142
+
143
+ context 'module_details' do
144
+ it { is_expected.to have_many(:module_details).class_name('Mdm::Module::Detail').through(:module_refs) }
145
+
146
+ context 'with Mdm::Vulns' do
147
+ let!(:vulns) do
148
+ FactoryBot.create_list(
149
+ :mdm_vuln,
150
+ 2,
151
+ :host => host
152
+ )
153
+ end
154
+
155
+ context 'with Mdm::Ref' do
156
+ let(:name) do
157
+ FactoryBot.generate :mdm_ref_name
158
+ end
159
+
160
+ let!(:ref) do
161
+ FactoryBot.create(:mdm_ref, :name => name)
162
+ end
163
+
164
+ context 'with Mdm::VulnRefs' do
165
+ let!(:vuln_refs) do
166
+ vulns.collect { |vuln|
167
+ FactoryBot.create(:mdm_vuln_ref, :ref => ref, :vuln => vuln)
168
+ }
169
+ end
170
+
171
+ context 'with Mdm::Module::Detail' do
172
+ let!(:module_detail) do
173
+ FactoryBot.create(
174
+ :mdm_module_detail
175
+ )
176
+ end
177
+
178
+ context 'with Mdm::Module::Ref with same name as Mdm::Ref' do
179
+ let!(:module_ref) do
180
+ FactoryBot.create(
181
+ :mdm_module_ref,
182
+ :detail => module_detail,
183
+ :name => name
184
+ )
185
+ end
186
+
187
+ it 'should list unique Mdm::Module::Detail' do
188
+ expect(host.module_details).to match_array([module_detail])
189
+ end
190
+
191
+ it 'should have duplicate Mdm::Module::Details if collected through chain' do
192
+ vuln_refs = []
193
+
194
+ host.vulns.each do |vuln|
195
+ # @todo https://www.pivotaltracker.com/story/show/49004623
196
+ vuln_refs += vuln.vulns_refs
197
+ end
198
+
199
+ refs = []
200
+
201
+ vuln_refs.each do |vuln_ref|
202
+ refs << vuln_ref.ref
203
+ end
204
+
205
+ module_refs = []
206
+
207
+ refs.each do |ref|
208
+ module_refs += ref.module_refs
209
+ end
210
+
211
+ module_details = []
212
+
213
+ module_refs.each do |module_ref|
214
+ module_details << module_ref.detail
215
+ end
216
+
217
+ expect(architectures).to include('mips')
218
+ expect(module_details.uniq.count).to eq(host.module_details.count)
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end
224
+ end
225
+ end
226
+
227
+ it { is_expected.to have_many(:module_refs).class_name('Mdm::Module::Ref').through(:refs) }
228
+ it { is_expected.to have_many(:notes).class_name('Mdm::Note').dependent(:delete_all).order('notes.created_at') }
229
+ it { is_expected.to have_many(:refs).class_name('Mdm::Ref').through(:vuln_refs) }
230
+ it { is_expected.to have_many(:services).class_name('Mdm::Service').dependent(:destroy).order('services.port, services.proto') }
231
+ it { is_expected.to have_many(:service_notes).through(:services) }
232
+ it { is_expected.to have_many(:sessions).class_name('Mdm::Session').dependent(:destroy).order('sessions.opened_at') }
233
+ it { is_expected.to have_many(:tags).class_name('Mdm::Tag').through(:hosts_tags) }
234
+ it { is_expected.to have_many(:vulns).class_name('Mdm::Vuln').dependent(:delete_all) }
235
+ it { is_expected.to have_many(:vuln_refs).class_name('Mdm::VulnRef') }
236
+ it { is_expected.to have_many(:web_sites).class_name('Mdm::WebSite').through(:services) }
237
+ it { is_expected.to belong_to(:workspace).class_name('Mdm::Workspace') }
238
+ end
239
+
240
+ context 'CONSTANTS' do
241
+ context 'ARCHITECTURES' do
242
+ subject(:architectures) do
243
+ described_class::ARCHITECTURES
244
+ end
245
+
246
+ it 'should be an Array<String>' do
247
+ expect(architectures).to include('mips')
248
+
249
+ architectures.each do |architecture|
250
+ expect(architectures).to include('mips')
251
+ end
252
+ end
253
+
254
+ it 'should include both endians of ARM' do
255
+ expect(architectures).to include('mips')
256
+ expect(architectures).to include('mips')
257
+ end
258
+
259
+ it 'should include 32-bit and 64-bit versions of Cell Broadband Engine Architecture' do
260
+ expect(architectures).to include('mips')
261
+ expect(architectures).to include('mips')
262
+ end
263
+
264
+ it 'should include cmd for command shell' do
265
+ expect(architectures).to include('mips')
266
+ end
267
+
268
+ it 'should include java for Java Virtual Machine' do
269
+ expect(architectures).to include('mips')
270
+ end
271
+
272
+ it 'should include plain and endian-ware MIPS' do
273
+ expect(architectures).to include('mips')
274
+ expect(architectures).to include('mipsbe')
275
+ expect(architectures).to include('mipsle')
276
+ end
277
+
278
+ it 'should include php for PHP code' do
279
+ expect(architectures).to include('php')
280
+ end
281
+
282
+ it 'should include 32-bit and 64-bit PowerPC' do
283
+ expect(architectures).to include('ppc')
284
+ expect(architectures).to include('ppc64')
285
+ end
286
+
287
+ it 'should include ruby for Ruby code' do
288
+ expect(architectures).to include('ruby')
289
+ end
290
+
291
+ it 'should include sparc for Sparc' do
292
+ expect(architectures).to include('sparc')
293
+ end
294
+
295
+ it 'should include tty for Terminals' do
296
+ expect(architectures).to include('tty')
297
+ end
298
+
299
+ it 'should include 32-bit and 64-bit x86' do
300
+ expect(architectures).to include('x64')
301
+ expect(architectures).to include('x86')
302
+ expect(architectures).to include('x86_64')
303
+ end
304
+
305
+ it 'should include blank string to indicate no detection has happened' do
306
+ expect(architectures).to include('')
307
+ end
308
+
309
+ it 'should include "Unknown" for failed detection attempts' do
310
+ expect(architectures).to include('Unknown')
311
+ end
312
+
313
+ end
314
+
315
+ context 'SEARCH_FIELDS' do
316
+ subject(:search_fields) do
317
+ described_class::SEARCH_FIELDS
318
+ end
319
+
320
+ it 'should be an Array<String>' do
321
+ expect(search_fields).to be_an Array
322
+
323
+ search_fields.each { |search_field|
324
+ expect(search_field).to be_a String
325
+ }
326
+ end
327
+
328
+ it 'should cast address to text' do
329
+ expect(search_fields).to include('address::text')
330
+ end
331
+
332
+ it { is_expected.to include('comments') }
333
+ it { is_expected.to include('mac') }
334
+ it { is_expected.to include('name') }
335
+ it { is_expected.to include('os_flavor') }
336
+ it { is_expected.to include('os_name') }
337
+ it { is_expected.to include('os_sp') }
338
+ it { is_expected.to include('purpose') }
339
+ end
340
+
341
+ it 'should define STATES in any order' do
342
+ expect(described_class::STATES).to match_array(states)
343
+ end
344
+ end
345
+
346
+ context 'database' do
347
+ context 'columns' do
348
+ it { is_expected.to have_db_column(:address).of_type(:inet).with_options(:null => false) }
349
+ it { is_expected.to have_db_column(:arch).of_type(:string) }
350
+ it { is_expected.to have_db_column(:comm).of_type(:string) }
351
+ it { is_expected.to have_db_column(:comments).of_type(:text) }
352
+ it { is_expected.to have_db_column(:info).of_type(:string).with_options(:limit => 2 ** 16) }
353
+ it { is_expected.to have_db_column(:mac).of_type(:string) }
354
+ it { is_expected.to have_db_column(:name).of_type(:string) }
355
+ it { is_expected.to have_db_column(:os_family).of_type(:string) }
356
+ it { is_expected.to have_db_column(:os_flavor).of_type(:string) }
357
+ it { is_expected.to have_db_column(:os_lang).of_type(:string) }
358
+ it { is_expected.to have_db_column(:os_name).of_type(:string) }
359
+ it { is_expected.to have_db_column(:os_sp).of_type(:string) }
360
+ it { is_expected.to have_db_column(:purpose).of_type(:text) }
361
+ it { is_expected.to have_db_column(:scope).of_type(:text) }
362
+ it { is_expected.to have_db_column(:state).of_type(:string) }
363
+ it { is_expected.to have_db_column(:virtual_host).of_type(:text) }
364
+ it { is_expected.to have_db_column(:workspace_id).of_type(:integer).with_options(:null => false) }
365
+
366
+ context 'counter caches' do
367
+ it { is_expected.to have_db_column(:exploit_attempt_count).of_type(:integer).with_options(:default => 0) }
368
+ it { is_expected.to have_db_column(:host_detail_count).of_type(:integer).with_options(:default => 0) }
369
+ it { is_expected.to have_db_column(:note_count).of_type(:integer).with_options(:default => 0) }
370
+ it { is_expected.to have_db_column(:service_count).of_type(:integer).with_options(:default => 0) }
371
+ it { is_expected.to have_db_column(:vuln_count).of_type(:integer).with_options(:default => 0) }
372
+ end
373
+
374
+ context 'timestamps' do
375
+ it { is_expected.to have_db_column(:created_at).of_type(:datetime) }
376
+ it { is_expected.to have_db_column(:updated_at).of_type(:datetime) }
377
+ end
378
+ end
379
+
380
+ context 'indices' do
381
+ it { is_expected.to have_db_index([:workspace_id, :address]).unique(true) }
382
+ it { is_expected.to have_db_index(:name) }
383
+ it { is_expected.to have_db_index(:os_flavor) }
384
+ it { is_expected.to have_db_index(:os_name) }
385
+ it { is_expected.to have_db_index(:purpose) }
386
+ it { is_expected.to have_db_index(:state) }
387
+ end
388
+ end
389
+
390
+ context 'factories' do
391
+ context 'full_mdm_host' do
392
+ subject(:full_mdm_host) do
393
+ FactoryBot.build(:full_mdm_host)
394
+ end
395
+
396
+ it { is_expected.to be_valid }
397
+ end
398
+
399
+ context 'mdm_host' do
400
+ subject(:mdm_host) do
401
+ FactoryBot.build(:mdm_host)
402
+ end
403
+
404
+ it { is_expected.to be_valid }
405
+ end
406
+ end
407
+
408
+ context 'validations' do
409
+ context 'address' do
410
+ it { is_expected.to validate_presence_of(:address) }
411
+
412
+ # can't use validate_uniqueness_of(:address).scoped_to(:workspace_id) because it will attempt to set workspace_id
413
+ # to `nil`, which will make the `:null => false` constraint on hosts.workspace_id to fail.
414
+ it 'should validate uniqueness of address scoped to workspace_id' do
415
+ address = '192.168.0.1'
416
+
417
+ workspace = FactoryBot.create(:mdm_workspace)
418
+ FactoryBot.create(:mdm_host, :address => address, :workspace => workspace)
419
+
420
+ duplicate_host = FactoryBot.build(:mdm_host, :address => address, :workspace => workspace)
421
+
422
+ expect(duplicate_host).not_to be_valid
423
+ expect(duplicate_host.errors[:address]).to include('has already been taken')
424
+ end
425
+ end
426
+
427
+ context 'arch' do
428
+ let(:workspace) { FactoryBot.create(:mdm_workspace) }
429
+ let(:address) { '192.168.0.1' }
430
+ let(:host) { FactoryBot.create(:mdm_host, :address => address, :workspace => workspace, :arch => arch) }
431
+ context 'with an unknown architecture' do
432
+ let(:arch) { "asdfasdf" }
433
+ it 'should normalize to Unknown' do
434
+ expect(host).to be_valid
435
+ expect(host.arch).to eq described_class::UNKNOWN_ARCHITECTURE
436
+ end
437
+ end
438
+ described_class::ARCHITECTURES.each do |arch|
439
+ context "with known architecture '#{arch}'" do
440
+ let(:arch) { arch }
441
+ it { is_expected.to be_valid }
442
+ end
443
+ end
444
+ end
445
+
446
+ it { is_expected.to validate_inclusion_of(:state).in_array(states).allow_nil }
447
+ it { is_expected.to validate_presence_of(:workspace) }
448
+ end
449
+
450
+ context 'search scope' do
451
+ subject(:full_mdm_host) do
452
+ FactoryBot.create(:full_mdm_host)
453
+ end
454
+
455
+ def search_for(str)
456
+ Mdm::Host.search(str)
457
+ end
458
+
459
+ context 'searching for an empty string' do
460
+ it 'should return any hosts in the database' do
461
+ expect(search_for('')).to include(subject)
462
+ end
463
+ end
464
+
465
+ context 'searching for an existing Host\'s name' do
466
+ it 'should return the host' do
467
+ expect(search_for(subject.name)).to include(subject)
468
+ end
469
+ end
470
+ end
471
+
472
+ context 'os normalization' do
473
+ context '#get_arch_from_string' do
474
+ context "should return 'x86_64'" do
475
+ it "when the string contains 'x64'" do
476
+ expect(host.send(:get_arch_from_string, 'blahx64blah')).to eq('x86_64')
477
+ end
478
+
479
+ it "when the string contains 'X64'" do
480
+ expect(host.send(:get_arch_from_string, 'blahX64blah')).to eq('x86_64')
481
+ end
482
+
483
+ it "when the string contains 'x86_64'" do
484
+ expect(host.send(:get_arch_from_string, 'blahx86_64blah')).to eq('x86_64')
485
+ end
486
+
487
+ it "when the string contains 'X86_64'" do
488
+ expect(host.send(:get_arch_from_string, 'blahX86_64blah')).to eq('x86_64')
489
+ end
490
+
491
+ it "when the string contains 'amd64'" do
492
+ expect(host.send(:get_arch_from_string, 'blahamd64blah')).to eq('x86_64')
493
+ end
494
+
495
+ it "when the string contains 'AMD64'" do
496
+ expect(host.send(:get_arch_from_string, 'blahAMD64blah')).to eq('x86_64')
497
+ end
498
+
499
+ it "when the string contains 'aMd64'" do
500
+ expect(host.send(:get_arch_from_string, 'blahamd64blah')).to eq('x86_64')
501
+ end
502
+ end
503
+
504
+ context "should return 'x86'" do
505
+ it "when the string contains 'x86'" do
506
+ expect(host.send(:get_arch_from_string, 'blahx86blah')).to eq('x86')
507
+ end
508
+
509
+ it "when the string contains 'X86'" do
510
+ expect(host.send(:get_arch_from_string, 'blahX86blah')).to eq('x86')
511
+ end
512
+
513
+ it "when the string contains 'i386'" do
514
+ expect(host.send(:get_arch_from_string, 'blahi386blah')).to eq('x86')
515
+ end
516
+
517
+ it "when the string contains 'I386'" do
518
+ expect(host.send(:get_arch_from_string, 'blahI386blah')).to eq('x86')
519
+ end
520
+
521
+ it "when the string contains 'i486'" do
522
+ expect(host.send(:get_arch_from_string, 'blahi486blah')).to eq('x86')
523
+ end
524
+
525
+ it "when the string contains 'i586'" do
526
+ expect(host.send(:get_arch_from_string, 'blahi586blah')).to eq('x86')
527
+ end
528
+
529
+ it "when the string contains 'i686'" do
530
+ expect(host.send(:get_arch_from_string, 'blahi386blah')).to eq('x86')
531
+ end
532
+ end
533
+
534
+ context "should return 'PowerPC'" do
535
+ it "when the string contains 'PowerPC'" do
536
+ expect(host.send(:get_arch_from_string, 'blahPowerPCblah')).to eq('PowerPC')
537
+ end
538
+
539
+ it "when the string contains 'PPC'" do
540
+ expect(host.send(:get_arch_from_string, 'blahPPCblah')).to eq('PowerPC')
541
+ end
542
+
543
+ it "when the string contains 'POWER'" do
544
+ expect(host.send(:get_arch_from_string, 'blahPOWERblah')).to eq('PowerPC')
545
+ end
546
+
547
+ it "when the string contains 'ppc'" do
548
+ expect(host.send(:get_arch_from_string, 'blahppcblah')).to eq('PowerPC')
549
+ end
550
+ end
551
+
552
+ context 'should return nil' do
553
+ it 'when PowerPC is cased incorrectly' do
554
+ expect(host.send(:get_arch_from_string, 'powerPC')).to eq(nil)
555
+ expect(host.send(:get_arch_from_string, 'Powerpc')).to eq(nil)
556
+ end
557
+
558
+ it 'when no recognized arch string is present' do
559
+ expect(host.send(:get_arch_from_string, 'blahblah')).to eq(nil)
560
+ end
561
+ end
562
+
563
+ it "should return 'Sparc' if the string contains SPARC, regardless of case" do
564
+ expect(host.send(:get_arch_from_string, 'blahSPARCblah')).to eq('Sparc')
565
+ expect(host.send(:get_arch_from_string, 'blahSPaRCblah')).to eq('Sparc')
566
+ expect(host.send(:get_arch_from_string, 'blahsparcblah')).to eq('Sparc')
567
+ end
568
+
569
+ it "should return 'ARM' if the string contains 'ARM', regardless of case" do
570
+ expect(host.send(:get_arch_from_string, 'blahARMblah')).to eq('ARM')
571
+ expect(host.send(:get_arch_from_string, 'blahArMblah')).to eq('ARM')
572
+ expect(host.send(:get_arch_from_string, 'blaharmblah')).to eq('ARM')
573
+ end
574
+
575
+ it "should return 'MIPS' if the string contains 'MIPS', regardless of case" do
576
+ expect(host.send(:get_arch_from_string, 'blahMIPSblah')).to eq('MIPS')
577
+ expect(host.send(:get_arch_from_string, 'blahMiPslah')).to eq('MIPS')
578
+ expect(host.send(:get_arch_from_string, 'blahmipsblah')).to eq('MIPS')
579
+ end
580
+ end
581
+
582
+ context '#parse_windows_os_str' do
583
+ it 'should always return the os_name as Windows' do
584
+ result = host.send(:parse_windows_os_str, '')
585
+ expect(result['os.product']).to eq('Windows')
586
+ end
587
+
588
+ context 'arch' do
589
+ it 'should return a value for arch if there is one' do
590
+ result = host.send(:parse_windows_os_str, 'Windows x64')
591
+ expect(result['os.arch']).to eq('x86_64')
592
+ end
593
+
594
+ it "should not have an arch key if we don't know the arch" do
595
+ result = host.send(:parse_windows_os_str, 'Windows')
596
+ expect(result.has_key?('os.arch')).to eq(false)
597
+ end
598
+ end
599
+
600
+ context 'Service Pack' do
601
+ it 'should be returned if we see Service Pack X' do
602
+ result = host.send(:parse_windows_os_str, 'Windows XP Service Pack 1')
603
+ expect(result['os.version']).to eq('SP1')
604
+ end
605
+
606
+ it 'should be returned if we see SPX' do
607
+ result = host.send(:parse_windows_os_str, 'Windows XP SP3')
608
+ expect(result['os.version']).to eq('SP3')
609
+ end
610
+ end
611
+
612
+ context 'os product' do
613
+
614
+ it "should appear as Windows 95 for 'Windows 95" do
615
+ result = host.send(:parse_windows_os_str, 'Windows 95')
616
+ expect(result['os.product']).to eq('Windows 95')
617
+ end
618
+
619
+ it "should appear as Windows NT 3.51 for 'Windows NT 3.51" do
620
+ result = host.send(:parse_windows_os_str, 'Windows NT 3.51')
621
+ expect(result['os.product']).to eq('Windows NT 3.51')
622
+ end
623
+
624
+ it "should appear as Windows NT 4.0 for 'Windows NT 4.0" do
625
+ result = host.send(:parse_windows_os_str, 'Windows NT 4.0')
626
+ expect(result['os.product']).to eq('Windows NT 4.0')
627
+ end
628
+
629
+ it "should appear as Windows 98 for 'Windows 98" do
630
+ result = host.send(:parse_windows_os_str, 'Windows 98')
631
+ expect(result['os.product']).to eq('Windows 98')
632
+ end
633
+
634
+ it "should appear as Windows ME for 'Windows ME" do
635
+ result = host.send(:parse_windows_os_str, 'Windows ME')
636
+ expect(result['os.product']).to eq('Windows ME')
637
+ end
638
+
639
+ it "should appear as Windows 2003 for '.NET Server'" do
640
+ result = host.send(:parse_windows_os_str, 'Windows .NET Server')
641
+ expect(result['os.product']).to eq('Windows Server 2003')
642
+ end
643
+
644
+ it 'should be recognized for Windows XP' do
645
+ result = host.send(:parse_windows_os_str, 'Windows XP')
646
+ expect(result['os.product']).to eq('Windows XP')
647
+ end
648
+
649
+ it 'should be recognized for Windows Server 2000' do
650
+ result = host.send(:parse_windows_os_str, 'Windows 2000')
651
+ expect(result['os.product']).to eq('Windows Server 2000')
652
+ end
653
+
654
+ it 'should be recognized for Windows Server 2003' do
655
+ result = host.send(:parse_windows_os_str, 'Windows 2003')
656
+ expect(result['os.product']).to eq('Windows Server 2003')
657
+ end
658
+
659
+ it 'should be recognized for Windows 2008' do
660
+ result = host.send(:parse_windows_os_str, 'Windows 2008')
661
+ expect(result['os.product']).to eq('Windows Server 2008')
662
+ end
663
+
664
+ it 'should be recognized for Windows 2012' do
665
+ result = host.send(:parse_windows_os_str, 'Windows 2012')
666
+ expect(result['os.product']).to eq('Windows Server 2012')
667
+ end
668
+
669
+ it 'should be recognized for Windows Vista' do
670
+ result = host.send(:parse_windows_os_str, 'Windows Vista')
671
+ expect(result['os.product']).to eq('Windows Vista')
672
+ end
673
+
674
+ it 'should be recognized for Windows Server 2000' do
675
+ result = host.send(:parse_windows_os_str, 'Windows 2000 Advanced Server')
676
+ expect(result['os.product']).to eq('Windows Server 2000')
677
+ end
678
+
679
+ it 'should be recognized for Windows 7' do
680
+ result = host.send(:parse_windows_os_str, 'Windows 7')
681
+ expect(result['os.product']).to eq('Windows 7')
682
+ end
683
+
684
+ it 'should be recognized for Windows 7 Ultimate Edition' do
685
+ result = host.send(:parse_windows_os_str, 'Windows 7 Ultimate Edition')
686
+ expect(result['os.product']).to eq('Windows 7')
687
+ expect(result['os.edition']).to eq('Ultimate')
688
+ end
689
+
690
+ it 'should be recognized for Windows 8' do
691
+ result = host.send(:parse_windows_os_str, 'Windows 8')
692
+ expect(result['os.product']).to eq('Windows 8')
693
+ end
694
+
695
+ it 'should be recognized for Windows 8.1' do
696
+ result = host.send(:parse_windows_os_str, 'Windows 8.1')
697
+ expect(result['os.product']).to eq('Windows 8.1')
698
+ end
699
+
700
+ it 'should be recognized for Windows 8.2' do
701
+ result = host.send(:parse_windows_os_str, 'Windows 8.2')
702
+ expect(result['os.product']).to eq('Windows 8.2')
703
+ end
704
+
705
+ it 'should be recognized as Windows XP, Build 2600, SP3' do
706
+ result = host.send(:parse_windows_os_str, 'Windows XP (Build 2600, Service Pack 3).')
707
+ expect(result['os.product']).to eq('Windows XP')
708
+ expect(result['os.build']).to eq('2600')
709
+ expect(result['os.version']).to eq('SP3')
710
+ end
711
+
712
+ it 'should be recognized as Windows Server 2003, Build 3790' do
713
+ result = host.send(:parse_windows_os_str, 'Windows .NET Server (Build 3790).')
714
+ expect(result['os.product']).to eq('Windows Server 2003')
715
+ expect(result['os.build']).to eq('3790')
716
+ end
717
+
718
+ it 'should be recognized as Windows Server 2008, Build 6001, SP1' do
719
+ result = host.send(:parse_windows_os_str, 'Windows 2008 (Build 6001, Service Pack 1).')
720
+ expect(result['os.product']).to eq('Windows Server 2008')
721
+ expect(result['os.build']).to eq('6001')
722
+ expect(result['os.version']).to eq('SP1')
723
+ end
724
+
725
+ it 'should default to Windows <name> if all else fails' do
726
+ result = host.send(:parse_windows_os_str, 'Windows Foobar Service Pack 3')
727
+ expect(result['os.product']).to eq('Windows Foobar')
728
+ expect(result['os.version']).to eq('SP3')
729
+ end
730
+ end
731
+ end
732
+
733
+ context '#validate_fingerprint_data' do
734
+ it 'should return false for an empty hash' do
735
+ fingerprint= FactoryBot.build(:mdm_note, :data => {})
736
+ expect(host.validate_fingerprint_data(fingerprint)).to eq(false)
737
+ end
738
+
739
+ it 'should return false for postgresql fingerprints' do
740
+ fingerprint= FactoryBot.build(:mdm_note, :ntype => 'postgresql.fingerprint', :data => {})
741
+ expect(host.validate_fingerprint_data(fingerprint)).to eq(false)
742
+ end
743
+
744
+ it 'should return false if the fingerprint does not contain a hash' do
745
+ fingerprint= FactoryBot.build(:mdm_note, :data => 'this is not a fingerprint')
746
+ expect(host.validate_fingerprint_data(fingerprint)).to eq(false)
747
+ end
748
+ end
749
+
750
+
751
+ context '#apply_match_to_host' do
752
+ it 'should set host.mac when host.mac is present' do
753
+ match = { 'host.mac' => '00:11:22:33:44:55' }
754
+ host.send(:apply_match_to_host, match)
755
+ expect(host.mac).to eq('00:11:22:33:44:55')
756
+ end
757
+
758
+ it 'should set host.name when host.name is present' do
759
+ match = { 'host.name' => 'webbyweb' }
760
+ host.send(:apply_match_to_host, match)
761
+ expect(host.name).to eq('webbyweb')
762
+ end
763
+
764
+ it 'should set host.arch when os.arch is present' do
765
+ match = { 'os.arch' => 'x86' }
766
+ host.send(:apply_match_to_host, match)
767
+ expect(host.arch).to eq('x86')
768
+ end
769
+
770
+ it 'should set host.name to an escaped hex value when host.name contains high bytes' do
771
+ match = { 'host.name' => "HighBytes\xff\xf0".force_encoding('binary') }
772
+ host.send(:apply_match_to_host, match)
773
+ expect(host.name).to eq("HighBytes\\xff\\xf0")
774
+ end
775
+
776
+ it 'should set host.purpose to client when os.product is Windows XP' do
777
+ match = { 'os.product' => 'Windows XP' }
778
+ host.send(:apply_match_to_host, match)
779
+ expect(host.os_name).to eq('Windows XP')
780
+ expect(host.purpose).to eq('client')
781
+ end
782
+
783
+ it 'should set host.purpose to server when os.product is Windows 2012' do
784
+ match = { 'os.product' => 'Windows 2012' }
785
+ host.send(:apply_match_to_host, match)
786
+ expect(host.os_name).to eq('Windows 2012')
787
+ expect(host.purpose).to eq('server')
788
+ end
789
+
790
+ it 'should set host.purpose to printer when os.device is Print server' do
791
+ match = { 'os.device' => 'Print server' }
792
+ host.send(:apply_match_to_host, match)
793
+ expect(host.purpose).to eq('printer')
794
+ end
795
+
796
+ it 'should set host.os_lang to English when os.language is English' do
797
+ match = { 'os.language' => 'English' }
798
+ host.send(:apply_match_to_host, match)
799
+ expect(host.os_lang).to eq('English')
800
+ end
801
+
802
+ it 'should set host.os_name to Windows 8.1 when os.product is Windows 8.1' do
803
+ match = { 'os.product' => 'Windows 8.1' }
804
+ host.send(:apply_match_to_host, match)
805
+ expect(host.os_name).to eq('Windows 8.1')
806
+ end
807
+
808
+ it 'should set host.os_name to Windows when os.product is not set and os.family is Windows' do
809
+ match = { 'os.family' => 'Windows' }
810
+ host.send(:apply_match_to_host, match)
811
+ expect(host.os_name).to eq('Windows')
812
+ end
813
+
814
+ it 'should set host.os_flavor to Professional when os.edition is Professional' do
815
+ match = { 'os.edition' => 'Professional' }
816
+ host.send(:apply_match_to_host, match)
817
+ expect(host.os_flavor).to eq('Professional')
818
+ end
819
+
820
+ it 'should set host.os_sp to SP2 when os.version is SP2' do
821
+ match = { 'os.version' => 'SP2' }
822
+ host.send(:apply_match_to_host, match)
823
+ expect(host.os_sp).to eq('SP2')
824
+ end
825
+
826
+ it 'should set host.os_sp to 3.2.11 when os.version is nil and linux.kernel.version is 3.2.11' do
827
+ match = { 'linux.kernel.version' => '3.2.11' }
828
+ host.send(:apply_match_to_host, match)
829
+ expect(host.os_sp).to eq('3.2.11')
830
+ end
831
+ end
832
+
833
+ context '#normalize_match' do
834
+
835
+ it 'should convert Service Pack X to SPX' do
836
+ match = { 'os.version' => 'Service Pack 2' }
837
+ result = host.send(:normalize_match, match)
838
+ expect(result['os.version']).to eq('SP2')
839
+ end
840
+
841
+ it 'should not convert No Service Pack to SP' do
842
+ match = { 'os.version' => 'No Service Pack' }
843
+ result = host.send(:normalize_match, match)
844
+ expect(result['os.version']).to eq('No Service Pack')
845
+ end
846
+
847
+ it 'should convert Apple Mac OS X to Mac OS X' do
848
+ match = { 'os.product' => 'Apple Mac OS X' }
849
+ result = host.send(:normalize_match, match)
850
+ expect(result['os.product']).to eq('Mac OS X')
851
+ expect(result['os.vendor']).to eq('Apple')
852
+ end
853
+
854
+ it 'should convert Microsoft Windows to Windows' do
855
+ match = { 'os.product' => 'Microsoft Windows 7' }
856
+ result = host.send(:normalize_match, match)
857
+ expect(result['os.product']).to eq('Windows 7')
858
+ expect(result['os.vendor']).to eq('Microsoft')
859
+ end
860
+
861
+ it 'should convert Windows Server 2012 to Windows 2012' do
862
+ match = { 'os.product' => 'Windows Server 2012' }
863
+ result = host.send(:normalize_match, match)
864
+ expect(result['os.product']).to eq('Windows 2012')
865
+ end
866
+ end
867
+
868
+ context '#normalize_match_family' do
869
+ it 'should set the family to Windows if the product contains Windows' do
870
+ match = { 'os.product' => 'Microsoft Windows 7' }
871
+ result = host.normalize_match_family(match)
872
+ expect(result['os.family']).to eq 'Windows'
873
+ end
874
+
875
+ it 'should set the family to Linux if the product contains Linux' do
876
+ match = { 'os.product' => 'Linux (Ubuntu)' }
877
+ result = host.normalize_match_family(match)
878
+ expect(result['os.family']).to eq 'Linux'
879
+ end
880
+
881
+ it 'should set the family to Solaris if the product contains Solaris' do
882
+ match = { 'os.product' => 'Solaris' }
883
+ result = host.normalize_match_family(match)
884
+ expect(result['os.family']).to eq 'Solaris'
885
+ end
886
+
887
+ it 'should set the family to SunOS if the product contains SunOS' do
888
+ match = { 'os.product' => 'SunOS' }
889
+ result = host.normalize_match_family(match)
890
+ expect(result['os.family']).to eq 'SunOS'
891
+ end
892
+
893
+ it 'should set the family to AIX if the product contains AIX' do
894
+ match = { 'os.product' => 'AIX' }
895
+ result = host.normalize_match_family(match)
896
+ expect(result['os.family']).to eq 'AIX'
897
+ end
898
+
899
+ it 'should set the family to HP-UX if the product contains HP-UX' do
900
+ match = { 'os.product' => 'HP-UX' }
901
+ result = host.normalize_match_family(match)
902
+ expect(result['os.family']).to eq 'HP-UX'
903
+ end
904
+ end
905
+
906
+ context '#guess_purpose_from_match' do
907
+
908
+ it 'should detect Windows XP as a client' do
909
+ match = { 'os.product' => 'Windows XP' }
910
+ result = host.send(:guess_purpose_from_match, match)
911
+ expect(result).to eq('client')
912
+ end
913
+
914
+ it 'should detect Windows 8.1 as a client' do
915
+ match = { 'os.product' => 'Windows 8.1' }
916
+ result = host.send(:guess_purpose_from_match, match)
917
+ expect(result).to eq('client')
918
+ end
919
+
920
+ it 'should detect Windows 2000 as a server' do
921
+ match = { 'os.product' => 'Windows 2000' }
922
+ result = host.send(:guess_purpose_from_match, match)
923
+ expect(result).to eq('server')
924
+ end
925
+
926
+ it 'should detect Windows Server 2012 as a server' do
927
+ match = { 'os.product' => 'Windows Server 2012' }
928
+ result = host.send(:guess_purpose_from_match, match)
929
+ expect(result).to eq('server')
930
+ end
931
+
932
+ it 'should detect Linux as a server' do
933
+ match = { 'os.product' => 'Linux' }
934
+ result = host.send(:guess_purpose_from_match, match)
935
+ expect(result).to eq('server')
936
+ end
937
+
938
+ it 'should detect JetDirect as a printer' do
939
+ match = { 'os.product' => 'JetDirect', 'os.device' => 'Print server' }
940
+ result = host.send(:guess_purpose_from_match, match)
941
+ expect(result).to eq('printer')
942
+ end
943
+
944
+ it 'should detect Unknown Printer as a printer' do
945
+ match = { 'os.product' => 'Unknown Printer' }
946
+ result = host.send(:guess_purpose_from_match, match)
947
+ expect(result).to eq('printer')
948
+ end
949
+
950
+ it 'should detect Linksys Router as a router' do
951
+ match = { 'os.product' => 'Linksys', 'os.device' => 'Router' }
952
+ result = host.send(:guess_purpose_from_match, match)
953
+ expect(result).to eq('router')
954
+ end
955
+
956
+ it 'should detect CheckPoint Firewall-1 as a firewall' do
957
+ match = { 'os.vendor' => 'Check Point', 'os.product' => 'Firewall-1' }
958
+ result = host.send(:guess_purpose_from_match, match)
959
+ expect(result).to eq('firewall')
960
+ end
961
+ end
962
+
963
+ context '#normalize_scanner_fp' do
964
+ context 'for session_fingerprint' do
965
+ it 'should return all the correct data for Windows XP SP3 x86' do
966
+ fingerprint = FactoryBot.build(:mdm_session_fingerprint, :host => host)
967
+ result = host.send(:normalize_scanner_fp, fingerprint).first
968
+ expect(result['os.product']).to eq('Windows XP')
969
+ expect(result['os.version']).to eq('SP3')
970
+ expect(result['os.arch']).to eq('x86')
971
+ expect(result['host.name']).to eq(nil)
972
+ expect(result['os.certainty'].to_f).to eq(0.8)
973
+ end
974
+
975
+ it 'should return all the correct data for Windows 2008 SP1 x64' do
976
+ fp_data = { :os => 'Microsoft Windows 2008 SP1', :arch => 'x64'}
977
+ fingerprint = FactoryBot.build(:mdm_session_fingerprint, :host => host, :data => fp_data)
978
+ result = host.send(:normalize_scanner_fp, fingerprint).first
979
+ expect(result['os.product']).to eq('Windows Server 2008')
980
+ expect(result['os.version']).to eq('SP1')
981
+ expect(result['os.arch']).to eq('x64')
982
+ expect(result['host.name']).to eq(nil)
983
+ expect(result['os.certainty'].to_f).to eq(0.8)
984
+ end
985
+
986
+ it 'should fingerprint Metasploitable correctly' do
987
+ # Taken from an actual session_fingerprint of Metasploitable 2
988
+ fp_data = { :os => 'Linux 2.6.24-16-server (i386)', :name => 'metasploitable'}
989
+ fingerprint = FactoryBot.build(:mdm_session_fingerprint, :host => host, :data => fp_data)
990
+ result = host.send(:normalize_scanner_fp, fingerprint).first
991
+ expect(result['os.product']).to eq('Linux')
992
+ expect(result['host.name']).to eq('metasploitable')
993
+ expect(result['os.version']).to eq('2.6.24-16-server')
994
+ expect(result['os.arch']).to eq('x86')
995
+ expect(result['os.certainty'].to_f).to eq(0.8)
996
+ end
997
+
998
+ it 'should just populate os_name if it is unsure' do
999
+ fp_data = { :os => 'Darwin 12.3.0 x86_64 i386'}
1000
+ fingerprint = FactoryBot.build(:mdm_session_fingerprint, :host => host, :data => fp_data)
1001
+ result = host.send(:normalize_scanner_fp, fingerprint).first
1002
+ expect(result['os.product']).to eq('Darwin 12.3.0 x86_64 i386')
1003
+ expect(result['os.version']).to eq(nil)
1004
+ expect(result['os.arch']).to eq(nil)
1005
+ expect(result['os.certainty']).to eq(0.8)
1006
+ end
1007
+ end
1008
+
1009
+ context 'for nmap_fingerprint' do
1010
+ it 'should return OS name for a Windows XP fingerprint' do
1011
+ fingerprint = FactoryBot.build(:mdm_nmap_fingerprint, :host => host)
1012
+ result = host.send(:normalize_scanner_fp, fingerprint).first
1013
+ expect(result['os.product']).to eq('Windows XP')
1014
+ expect(result['os.certainty'].to_f).to eq(described_class::MAX_NMAP_CERTAINTY)
1015
+ end
1016
+
1017
+ it 'should return OS name for a Metasploitable fingerprint' do
1018
+ fp_data = {:os_vendor=>"Linux", :os_family=>"Linux", :os_version=>"2.6.X", :os_accuracy=>100}
1019
+ fingerprint = FactoryBot.build(:mdm_nmap_fingerprint, :host => host, :data => fp_data)
1020
+ result = host.send(:normalize_scanner_fp, fingerprint).first
1021
+ expect(result['os.product']).to eq('Linux')
1022
+ expect(result['os.version']).to eq('2.6.X')
1023
+ expect(result['os.certainty'].to_f).to eq(described_class::MAX_NMAP_CERTAINTY)
1024
+ end
1025
+
1026
+ it 'should return OS name and flavor fo an OSX fingerprint' do
1027
+ fp_data = {:os_vendor=>"Apple", :os_family=>"Mac OS X", :os_version=>"10.8.X", :os_accuracy=>100}
1028
+ fingerprint = FactoryBot.build(:mdm_nmap_fingerprint, :host => host, :data => fp_data)
1029
+ result = host.send(:normalize_scanner_fp, fingerprint).first
1030
+ expect(result['os.product']).to eq('Mac OS X')
1031
+ expect(result['os.vendor']).to eq('Apple')
1032
+ expect(result['os.version']).to eq('10.8.X')
1033
+ expect(result['os.certainty'].to_f).to eq(described_class::MAX_NMAP_CERTAINTY)
1034
+ end
1035
+ end
1036
+
1037
+ context 'for nexpose_fingerprint' do
1038
+ context 'of a Windows system' do
1039
+ it 'should return a generic Windows fingerprint with no product info' do
1040
+ fingerprint = FactoryBot.build(:mdm_nexpose_fingerprint, :host => host)
1041
+ result = host.send(:normalize_scanner_fp, fingerprint).first
1042
+ expect(result['os.product']).to eq('Windows')
1043
+ expect(result['os.arch']).to eq('x86')
1044
+ expect(result['os.certainty'].to_f).to eq(0.67)
1045
+ end
1046
+
1047
+ it 'should recognize a Windows 7 fingerprint' do
1048
+ fp_data = {:family=>"Windows", :certainty=>"0.67", :vendor=>"Microsoft", :arch=>"x86", :product => 'Windows 7', :version => 'SP1'}
1049
+ fingerprint = FactoryBot.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
1050
+ result = host.send(:normalize_scanner_fp, fingerprint).first
1051
+ expect(result['os.product']).to eq('Windows 7')
1052
+ expect(result['os.version']).to eq('SP1')
1053
+ expect(result['os.arch']).to eq('x86')
1054
+ expect(result['os.certainty'].to_f).to eq(0.67)
1055
+ end
1056
+ end
1057
+
1058
+ it 'should recognize an OSX fingerprint' do
1059
+ fp_data = {:family=>"Mac OS X", :certainty=>"0.80", :vendor=>"Apple"}
1060
+ fingerprint = FactoryBot.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
1061
+ result = host.send(:normalize_scanner_fp, fingerprint).first
1062
+ expect(result['os.product']).to eq('Mac OS X')
1063
+ expect(result['os.vendor']).to eq("Apple")
1064
+ end
1065
+
1066
+ it 'should recognize a Cisco fingerprint' do
1067
+ fp_data = {:family=>"IOS", :certainty=>"1.00", :vendor=>"Cisco", :version=>"11.2(8)SA2"}
1068
+ fingerprint = FactoryBot.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
1069
+ result = host.send(:normalize_scanner_fp, fingerprint).first
1070
+ expect(result['os.product']).to eq('IOS')
1071
+ expect(result['os.vendor']).to eq('Cisco')
1072
+ end
1073
+
1074
+ it 'should recognize an embedded fingerprint' do
1075
+ fp_data = {:family=>"embedded", :certainty=>"1.00", :vendor=>"Footek"}
1076
+ fingerprint = FactoryBot.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
1077
+ result = host.send(:normalize_scanner_fp, fingerprint).first
1078
+ expect(result['os.product']).to eq('Footek')
1079
+ end
1080
+
1081
+ it 'should handle an unknown fingerprint' do
1082
+ fp_data = {:certainty=>"1.00", :vendor=>"Footek"}
1083
+ fingerprint = FactoryBot.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
1084
+ result = host.send(:normalize_scanner_fp, fingerprint).first
1085
+ expect(result['os.product']).to eq('Footek')
1086
+ end
1087
+
1088
+
1089
+ end
1090
+
1091
+ context 'for retina_fingerprint' do
1092
+ it 'should recognize a Windows fingerprint' do
1093
+ fingerprint = FactoryBot.build(:mdm_retina_fingerprint, :host => host)
1094
+ result = host.send(:normalize_scanner_fp, fingerprint).first
1095
+ expect(result['os.product']).to eq( 'Windows Server 2003')
1096
+ expect(result['os.arch']).to eq('x86_64')
1097
+ expect(result['os.version']).to eq('SP2')
1098
+ expect(result['os.certainty'].to_f).to eq(0.8)
1099
+ end
1100
+
1101
+ it 'should otherwise jsut copy the fingerprint to os_name' do
1102
+ fp_data = { :os => 'Linux 2.6.X (i386)'}
1103
+ fingerprint = FactoryBot.build(:mdm_retina_fingerprint, :host => host, :data => fp_data)
1104
+ result = host.send(:normalize_scanner_fp, fingerprint).first
1105
+ expect(result['os.product']).to eq( 'Linux 2.6.X (i386)')
1106
+ expect(result['os.certainty'].to_f).to eq(0.8)
1107
+ end
1108
+ end
1109
+ end
1110
+
1111
+ end
1112
+
1113
+ context 'search' do
1114
+ let(:base_class) {
1115
+ described_class
1116
+ }
1117
+
1118
+ context 'attributes' do
1119
+
1120
+ it_should_behave_like 'search_with',
1121
+ MetasploitDataModels::Search::Operator::IPAddress,
1122
+ name: :address
1123
+ it_should_behave_like 'search_attribute',
1124
+ :name,
1125
+ type: :string
1126
+ it_should_behave_like 'search_with',
1127
+ MetasploitDataModels::Search::Operator::Multitext,
1128
+ name: :os,
1129
+ operator_names: [
1130
+ :os_name,
1131
+ :os_flavor,
1132
+ :os_sp
1133
+ ]
1134
+ it_should_behave_like 'search_attribute',
1135
+ :os_name,
1136
+ type: :string
1137
+ end
1138
+ end
1139
+ end