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.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/.github/workflows/verify.yml +68 -0
- data/.gitignore +29 -0
- data/.rspec +3 -0
- data/.simplecov +38 -0
- data/.yardopts +4 -0
- data/CHANGELOG.md +6 -0
- data/CONTRIBUTING.md +133 -0
- data/Gemfile +46 -0
- data/LICENSE +27 -0
- data/README.md +65 -0
- data/RELEASING.md +82 -0
- data/Rakefile +72 -0
- data/UPGRADING.md +1 -0
- data/app/models/mdm/api_key.rb +61 -0
- data/app/models/mdm/async_callback.rb +64 -0
- data/app/models/mdm/client.rb +50 -0
- data/app/models/mdm/cred.rb +205 -0
- data/app/models/mdm/event.rb +83 -0
- data/app/models/mdm/exploit_attempt.rb +105 -0
- data/app/models/mdm/exploited_host.rb +42 -0
- data/app/models/mdm/host.rb +619 -0
- data/app/models/mdm/host_detail.rb +62 -0
- data/app/models/mdm/host_tag.rb +49 -0
- data/app/models/mdm/listener.rb +82 -0
- data/app/models/mdm/loot.rb +161 -0
- data/app/models/mdm/macro.rb +62 -0
- data/app/models/mdm/mod_ref.rb +24 -0
- data/app/models/mdm/module/action.rb +33 -0
- data/app/models/mdm/module/arch.rb +28 -0
- data/app/models/mdm/module/author.rb +34 -0
- data/app/models/mdm/module/detail.rb +388 -0
- data/app/models/mdm/module/mixin.rb +31 -0
- data/app/models/mdm/module/platform.rb +29 -0
- data/app/models/mdm/module/ref.rb +42 -0
- data/app/models/mdm/module/target.rb +37 -0
- data/app/models/mdm/nexpose_console.rb +121 -0
- data/app/models/mdm/note.rb +125 -0
- data/app/models/mdm/payload.rb +103 -0
- data/app/models/mdm/profile.rb +45 -0
- data/app/models/mdm/ref.rb +48 -0
- data/app/models/mdm/route.rb +28 -0
- data/app/models/mdm/service.rb +267 -0
- data/app/models/mdm/session.rb +203 -0
- data/app/models/mdm/session_event.rb +44 -0
- data/app/models/mdm/tag.rb +114 -0
- data/app/models/mdm/task.rb +168 -0
- data/app/models/mdm/task_cred.rb +45 -0
- data/app/models/mdm/task_host.rb +41 -0
- data/app/models/mdm/task_service.rb +41 -0
- data/app/models/mdm/task_session.rb +41 -0
- data/app/models/mdm/user.rb +230 -0
- data/app/models/mdm/vuln.rb +204 -0
- data/app/models/mdm/vuln_attempt.rb +76 -0
- data/app/models/mdm/vuln_detail.rb +156 -0
- data/app/models/mdm/vuln_ref.rb +21 -0
- data/app/models/mdm/web_form.rb +53 -0
- data/app/models/mdm/web_page.rb +92 -0
- data/app/models/mdm/web_site.rb +113 -0
- data/app/models/mdm/web_vuln.rb +193 -0
- data/app/models/mdm/wmap_request.rb +101 -0
- data/app/models/mdm/wmap_target.rb +56 -0
- data/app/models/mdm/workspace.rb +286 -0
- data/app/models/metasploit_data_models/automatic_exploitation/match.rb +43 -0
- data/app/models/metasploit_data_models/automatic_exploitation/match_result.rb +71 -0
- data/app/models/metasploit_data_models/automatic_exploitation/match_set.rb +40 -0
- data/app/models/metasploit_data_models/automatic_exploitation/run.rb +29 -0
- data/app/models/metasploit_data_models/ip_address/v4/cidr.rb +14 -0
- data/app/models/metasploit_data_models/ip_address/v4/nmap.rb +14 -0
- data/app/models/metasploit_data_models/ip_address/v4/range.rb +12 -0
- data/app/models/metasploit_data_models/ip_address/v4/segment/nmap/list.rb +125 -0
- data/app/models/metasploit_data_models/ip_address/v4/segment/nmap/range.rb +12 -0
- data/app/models/metasploit_data_models/ip_address/v4/segment/single.rb +123 -0
- data/app/models/metasploit_data_models/ip_address/v4/segmented.rb +200 -0
- data/app/models/metasploit_data_models/ip_address/v4/single.rb +53 -0
- data/app/models/metasploit_data_models/module_run.rb +213 -0
- data/app/models/metasploit_data_models/search/operation/ip_address.rb +60 -0
- data/app/models/metasploit_data_models/search/operation/port/number.rb +25 -0
- data/app/models/metasploit_data_models/search/operation/port/range.rb +79 -0
- data/app/models/metasploit_data_models/search/operation/range.rb +56 -0
- data/app/models/metasploit_data_models/search/operator/ip_address.rb +33 -0
- data/app/models/metasploit_data_models/search/operator/multitext.rb +73 -0
- data/app/models/metasploit_data_models/search/operator/port/list.rb +67 -0
- data/app/models/metasploit_data_models/search/visitor/attribute.rb +17 -0
- data/app/models/metasploit_data_models/search/visitor/includes.rb +47 -0
- data/app/models/metasploit_data_models/search/visitor/joins.rb +67 -0
- data/app/models/metasploit_data_models/search/visitor/method.rb +16 -0
- data/app/models/metasploit_data_models/search/visitor/relation.rb +91 -0
- data/app/models/metasploit_data_models/search/visitor/where.rb +128 -0
- data/config/initializers/arel_helper.rb +5 -0
- data/config/initializers/ipaddr.rb +29 -0
- data/config/locales/en.yml +94 -0
- data/console_db.yml +9 -0
- data/db/migrate/000_create_tables.rb +79 -0
- data/db/migrate/001_add_wmap_tables.rb +35 -0
- data/db/migrate/002_add_workspaces.rb +36 -0
- data/db/migrate/003_move_notes.rb +20 -0
- data/db/migrate/004_add_events_table.rb +16 -0
- data/db/migrate/005_expand_info.rb +58 -0
- data/db/migrate/006_add_timestamps.rb +26 -0
- data/db/migrate/007_add_loots.rb +20 -0
- data/db/migrate/008_create_users.rb +16 -0
- data/db/migrate/009_add_loots_ctype.rb +10 -0
- data/db/migrate/010_add_alert_fields.rb +16 -0
- data/db/migrate/011_add_reports.rb +19 -0
- data/db/migrate/012_add_tasks.rb +24 -0
- data/db/migrate/013_add_tasks_result.rb +10 -0
- data/db/migrate/014_add_loots_fields.rb +12 -0
- data/db/migrate/015_rename_user.rb +16 -0
- data/db/migrate/016_add_host_purpose.rb +10 -0
- data/db/migrate/017_expand_info2.rb +58 -0
- data/db/migrate/018_add_workspace_user_info.rb +29 -0
- data/db/migrate/019_add_workspace_desc.rb +23 -0
- data/db/migrate/020_add_user_preferences.rb +11 -0
- data/db/migrate/021_standardize_info_and_data.rb +18 -0
- data/db/migrate/022_enlarge_event_info.rb +10 -0
- data/db/migrate/023_add_report_downloaded_at.rb +10 -0
- data/db/migrate/024_convert_service_info_to_text.rb +12 -0
- data/db/migrate/025_add_user_admin.rb +19 -0
- data/db/migrate/026_add_creds_table.rb +19 -0
- data/db/migrate/20100819123300_migrate_cred_data.rb +154 -0
- data/db/migrate/20100824151500_add_exploited_table.rb +16 -0
- data/db/migrate/20100908001428_add_owner_to_workspaces.rb +9 -0
- data/db/migrate/20100911122000_add_report_templates.rb +18 -0
- data/db/migrate/20100916151530_require_admin_flag.rb +15 -0
- data/db/migrate/20100916175000_add_campaigns_and_templates.rb +61 -0
- data/db/migrate/20100920012100_add_generate_exe_column.rb +8 -0
- data/db/migrate/20100926214000_add_template_prefs.rb +11 -0
- data/db/migrate/20101001000000_add_web_tables.rb +57 -0
- data/db/migrate/20101002000000_add_query.rb +10 -0
- data/db/migrate/20101007000000_add_vuln_info.rb +15 -0
- data/db/migrate/20101008111800_add_clients_to_campaigns.rb +10 -0
- data/db/migrate/20101009023300_add_campaign_attachments.rb +15 -0
- data/db/migrate/20101104135100_add_imported_creds.rb +17 -0
- data/db/migrate/20101203000000_fix_web_tables.rb +34 -0
- data/db/migrate/20101203000001_expand_host_comment.rb +12 -0
- data/db/migrate/20101206212033_add_limit_to_network_to_workspaces.rb +9 -0
- data/db/migrate/20110112154300_add_module_uuid_to_tasks.rb +9 -0
- data/db/migrate/20110204112800_add_host_tags.rb +28 -0
- data/db/migrate/20110317144932_add_session_table.rb +110 -0
- data/db/migrate/20110414180600_add_local_id_to_session_table.rb +11 -0
- data/db/migrate/20110415175705_add_routes_table.rb +18 -0
- data/db/migrate/20110422000000_convert_binary.rb +73 -0
- data/db/migrate/20110425095900_add_last_seen_to_sessions.rb +8 -0
- data/db/migrate/20110513143900_track_successful_exploits.rb +31 -0
- data/db/migrate/20110517160800_rename_and_prune_nessus_vulns.rb +26 -0
- data/db/migrate/20110527000000_add_task_id_to_reports_table.rb +11 -0
- data/db/migrate/20110527000001_add_api_keys_table.rb +12 -0
- data/db/migrate/20110606000001_add_macros_table.rb +16 -0
- data/db/migrate/20110622000000_add_settings_to_tasks_table.rb +12 -0
- data/db/migrate/20110624000001_add_listeners_table.rb +19 -0
- data/db/migrate/20110625000001_add_macro_to_listeners_table.rb +12 -0
- data/db/migrate/20110630000001_add_nexpose_consoles_table.rb +21 -0
- data/db/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb +12 -0
- data/db/migrate/20110717000001_add_profiles_table.rb +15 -0
- data/db/migrate/20110727163801_expand_cred_ptype_column.rb +9 -0
- data/db/migrate/20110730000001_add_initial_indexes.rb +85 -0
- data/db/migrate/20110812000001_prune_indexes.rb +23 -0
- data/db/migrate/20110922000000_expand_notes.rb +9 -0
- data/db/migrate/20110928101300_add_mod_ref_table.rb +17 -0
- data/db/migrate/20111011110000_add_display_name_to_reports_table.rb +24 -0
- data/db/migrate/20111203000000_inet_columns.rb +13 -0
- data/db/migrate/20111204000000_more_inet_columns.rb +17 -0
- data/db/migrate/20111210000000_add_scope_to_hosts.rb +9 -0
- data/db/migrate/20120126110000_add_virtual_host_to_hosts.rb +9 -0
- data/db/migrate/20120411173220_rename_workspace_members.rb +9 -0
- data/db/migrate/20120601152442_add_counter_caches_to_hosts.rb +21 -0
- data/db/migrate/20120625000000_add_vuln_details.rb +34 -0
- data/db/migrate/20120625000001_add_host_details.rb +16 -0
- data/db/migrate/20120625000002_expand_details.rb +16 -0
- data/db/migrate/20120625000003_expand_details2.rb +24 -0
- data/db/migrate/20120625000004_add_vuln_attempts.rb +19 -0
- data/db/migrate/20120625000005_add_vuln_and_host_counter_caches.rb +14 -0
- data/db/migrate/20120625000006_add_module_details.rb +118 -0
- data/db/migrate/20120625000007_add_exploit_attempts.rb +26 -0
- data/db/migrate/20120625000008_add_fail_message.rb +12 -0
- data/db/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb +13 -0
- data/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb +19 -0
- data/db/migrate/20130412154159_change_foreign_key_in_module_actions.rb +25 -0
- data/db/migrate/20130412171844_change_foreign_key_in_module_archs.rb +25 -0
- data/db/migrate/20130412173121_change_foreign_key_in_module_authors.rb +25 -0
- data/db/migrate/20130412173640_change_foreign_key_in_module_mixins.rb +25 -0
- data/db/migrate/20130412174254_change_foreign_key_in_module_platforms.rb +25 -0
- data/db/migrate/20130412174719_change_foreign_key_in_module_refs.rb +25 -0
- data/db/migrate/20130412175040_change_foreign_key_in_module_targets.rb +25 -0
- data/db/migrate/20130423211152_add_creds_counter_cache.rb +24 -0
- data/db/migrate/20130430151353_change_required_columns_to_null_false_in_hosts.rb +11 -0
- data/db/migrate/20130430162145_enforce_address_uniqueness_in_workspace_in_hosts.rb +101 -0
- data/db/migrate/20130510021637_remove_campaigns.rb +11 -0
- data/db/migrate/20130515164311_change_web_vulns_confidence_to_integer.rb +48 -0
- data/db/migrate/20130515172727_valid_mdm_web_vuln_params.rb +30 -0
- data/db/migrate/20130516204810_making_vulns_refs_a_real_ar_model.rb +5 -0
- data/db/migrate/20130522001343_create_task_creds.rb +9 -0
- data/db/migrate/20130522032517_create_task_hosts.rb +9 -0
- data/db/migrate/20130522041110_create_task_services.rb +9 -0
- data/db/migrate/20130525015035_remove_campaign_id_from_clients.rb +9 -0
- data/db/migrate/20130525212420_drop_table_imported_creds.rb +14 -0
- data/db/migrate/20130531144949_making_host_tags_a_real_ar_model.rb +6 -0
- data/db/migrate/20130604145732_create_task_sessions.rb +9 -0
- data/db/migrate/20130717150737_remove_pname_validation.rb +7 -0
- data/db/migrate/20131002004641_create_automatic_exploitation_matches.rb +13 -0
- data/db/migrate/20131002164449_create_automatic_exploitation_match_sets.rb +12 -0
- data/db/migrate/20131008213344_create_automatic_exploitation_runs.rb +11 -0
- data/db/migrate/20131011184338_module_detail_on_automatic_exploitation_match.rb +10 -0
- data/db/migrate/20131017150735_create_automatic_exploitation_match_results.rb +11 -0
- data/db/migrate/20131021185657_make_match_polymorphic.rb +11 -0
- data/db/migrate/20140905031549_add_detected_arch_to_host.rb +5 -0
- data/db/migrate/20150112203945_remove_duplicate_services.rb +17 -0
- data/db/migrate/20150205192745_drop_service_uniqueness_index.rb +5 -0
- data/db/migrate/20150209195939_add_vuln_id_to_note.rb +6 -0
- data/db/migrate/20150212214222_remove_duplicate_services2.rb +17 -0
- data/db/migrate/20150219173821_create_module_runs.rb +23 -0
- data/db/migrate/20150219215039_add_module_run_to_session.rb +8 -0
- data/db/migrate/20150226151459_add_module_run_fk_to_loot.rb +8 -0
- data/db/migrate/20150312155312_add_module_full_name_to_match.rb +6 -0
- data/db/migrate/20150317145455_rename_module_indices.rb +29 -0
- data/db/migrate/20150326183742_add_missing_ae_indices.rb +13 -0
- data/db/migrate/20150421211719_rename_automatic_exploitation_index.rb +16 -0
- data/db/migrate/20150514182921_add_origin_to_mdm_vuln.rb +13 -0
- data/db/migrate/20160415153312_remove_not_null_from_web_vuln_p_arams.rb +5 -0
- data/db/migrate/20161004165612_add_fingerprinted_to_workspace.rb +5 -0
- data/db/migrate/20161227212223_add_os_family_to_hosts.rb +5 -0
- data/db/migrate/20180904120211_create_payloads.rb +21 -0
- data/db/migrate/20190308134512_create_async_callbacks.rb +13 -0
- data/db/migrate/20190507120211_remove_payload_workspaces.rb +5 -0
- data/lib/mdm/host/operating_system_normalization.rb +942 -0
- data/lib/mdm/module.rb +13 -0
- data/lib/mdm.rb +57 -0
- data/lib/metasploit_data_models/automatic_exploitation.rb +25 -0
- data/lib/metasploit_data_models/base64_serializer.rb +99 -0
- data/lib/metasploit_data_models/change_required_columns_to_null_false.rb +21 -0
- data/lib/metasploit_data_models/engine.rb +32 -0
- data/lib/metasploit_data_models/ip_address/cidr.rb +174 -0
- data/lib/metasploit_data_models/ip_address/range.rb +181 -0
- data/lib/metasploit_data_models/ip_address/v4/segment/nmap.rb +7 -0
- data/lib/metasploit_data_models/ip_address/v4/segment.rb +7 -0
- data/lib/metasploit_data_models/ip_address/v4.rb +11 -0
- data/lib/metasploit_data_models/ip_address.rb +9 -0
- data/lib/metasploit_data_models/match/child.rb +48 -0
- data/lib/metasploit_data_models/match/parent.rb +103 -0
- data/lib/metasploit_data_models/match.rb +8 -0
- data/lib/metasploit_data_models/search/operation/port.rb +9 -0
- data/lib/metasploit_data_models/search/operation.rb +9 -0
- data/lib/metasploit_data_models/search/operator/port.rb +6 -0
- data/lib/metasploit_data_models/search/operator.rb +8 -0
- data/lib/metasploit_data_models/search/visitor.rb +11 -0
- data/lib/metasploit_data_models/search.rb +8 -0
- data/lib/metasploit_data_models/serialized_prefs.rb +27 -0
- data/lib/metasploit_data_models/version.rb +13 -0
- data/lib/metasploit_data_models.rb +56 -0
- data/metasploit_data_models.gemspec +65 -0
- data/script/rails +8 -0
- data/spec/app/models/mdm/api_key_spec.rb +3 -0
- data/spec/app/models/mdm/client_spec.rb +43 -0
- data/spec/app/models/mdm/cred_spec.rb +346 -0
- data/spec/app/models/mdm/event_spec.rb +90 -0
- data/spec/app/models/mdm/exploit_attempt_spec.rb +59 -0
- data/spec/app/models/mdm/exploited_host_spec.rb +44 -0
- data/spec/app/models/mdm/host_detail_spec.rb +48 -0
- data/spec/app/models/mdm/host_spec.rb +1139 -0
- data/spec/app/models/mdm/host_tag_spec.rb +69 -0
- data/spec/app/models/mdm/listener_spec.rb +107 -0
- data/spec/app/models/mdm/loot_spec.rb +84 -0
- data/spec/app/models/mdm/macro_spec.rb +3 -0
- data/spec/app/models/mdm/mod_ref_spec.rb +3 -0
- data/spec/app/models/mdm/module/action_spec.rb +34 -0
- data/spec/app/models/mdm/module/arch_spec.rb +34 -0
- data/spec/app/models/mdm/module/author_spec.rb +52 -0
- data/spec/app/models/mdm/module/detail_spec.rb +746 -0
- data/spec/app/models/mdm/module/mixin_spec.rb +34 -0
- data/spec/app/models/mdm/module/platform_spec.rb +34 -0
- data/spec/app/models/mdm/module/ref_spec.rb +58 -0
- data/spec/app/models/mdm/module/target_spec.rb +36 -0
- data/spec/app/models/mdm/nexpose_console_spec.rb +146 -0
- data/spec/app/models/mdm/note_spec.rb +91 -0
- data/spec/app/models/mdm/profile_spec.rb +3 -0
- data/spec/app/models/mdm/ref_spec.rb +71 -0
- data/spec/app/models/mdm/route_spec.rb +35 -0
- data/spec/app/models/mdm/service_spec.rb +232 -0
- data/spec/app/models/mdm/session_event_spec.rb +42 -0
- data/spec/app/models/mdm/session_spec.rb +118 -0
- data/spec/app/models/mdm/tag_spec.rb +116 -0
- data/spec/app/models/mdm/task_cred_spec.rb +51 -0
- data/spec/app/models/mdm/task_host_spec.rb +50 -0
- data/spec/app/models/mdm/task_service_spec.rb +50 -0
- data/spec/app/models/mdm/task_session_spec.rb +46 -0
- data/spec/app/models/mdm/task_spec.rb +71 -0
- data/spec/app/models/mdm/user_spec.rb +50 -0
- data/spec/app/models/mdm/vuln_attempt_spec.rb +53 -0
- data/spec/app/models/mdm/vuln_detail_spec.rb +65 -0
- data/spec/app/models/mdm/vuln_ref_spec.rb +46 -0
- data/spec/app/models/mdm/vuln_spec.rb +299 -0
- data/spec/app/models/mdm/web_form_spec.rb +46 -0
- data/spec/app/models/mdm/web_page_spec.rb +101 -0
- data/spec/app/models/mdm/web_site_spec.rb +85 -0
- data/spec/app/models/mdm/web_vuln_spec.rb +312 -0
- data/spec/app/models/mdm/wmap_request_spec.rb +5 -0
- data/spec/app/models/mdm/wmap_target_spec.rb +5 -0
- data/spec/app/models/mdm/workspace_spec.rb +500 -0
- data/spec/app/models/metasploit_data_models/automatic_exploitation/match_result_spec.rb +86 -0
- data/spec/app/models/metasploit_data_models/automatic_exploitation/match_set_spec.rb +46 -0
- data/spec/app/models/metasploit_data_models/automatic_exploitation/match_spec.rb +37 -0
- data/spec/app/models/metasploit_data_models/automatic_exploitation/run_spec.rb +38 -0
- data/spec/app/models/metasploit_data_models/ip_address/v4/cidr_spec.rb +119 -0
- data/spec/app/models/metasploit_data_models/ip_address/v4/nmap_spec.rb +149 -0
- data/spec/app/models/metasploit_data_models/ip_address/v4/range_spec.rb +298 -0
- data/spec/app/models/metasploit_data_models/ip_address/v4/segment/nmap/list_spec.rb +276 -0
- data/spec/app/models/metasploit_data_models/ip_address/v4/segment/nmap/range_spec.rb +302 -0
- data/spec/app/models/metasploit_data_models/ip_address/v4/segment/segmented_spec.rb +27 -0
- data/spec/app/models/metasploit_data_models/ip_address/v4/segment/single_spec.rb +324 -0
- data/spec/app/models/metasploit_data_models/ip_address/v4/single_spec.rb +181 -0
- data/spec/app/models/metasploit_data_models/module_run_spec.rb +134 -0
- data/spec/app/models/metasploit_data_models/search/operation/ip_address_spec.rb +180 -0
- data/spec/app/models/metasploit_data_models/search/operation/port/number_spec.rb +39 -0
- data/spec/app/models/metasploit_data_models/search/operation/port/range_spec.rb +138 -0
- data/spec/app/models/metasploit_data_models/search/operation/range_spec.rb +233 -0
- data/spec/app/models/metasploit_data_models/search/operator/ip_address_spec.rb +17 -0
- data/spec/app/models/metasploit_data_models/search/operator/multitext_spec.rb +160 -0
- data/spec/app/models/metasploit_data_models/search/operator/port/list_spec.rb +162 -0
- data/spec/app/models/metasploit_data_models/search/visitor/attribute_spec.rb +96 -0
- data/spec/app/models/metasploit_data_models/search/visitor/includes_spec.rb +175 -0
- data/spec/app/models/metasploit_data_models/search/visitor/joins_spec.rb +396 -0
- data/spec/app/models/metasploit_data_models/search/visitor/method_spec.rb +49 -0
- data/spec/app/models/metasploit_data_models/search/visitor/relation_spec.rb +925 -0
- data/spec/app/models/metasploit_data_models/search/visitor/where_spec.rb +187 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/config/manifest.js +1 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config/application.rb +61 -0
- data/spec/dummy/config/boot.rb +4 -0
- data/spec/dummy/config/database.yml.example +22 -0
- data/spec/dummy/config/database.yml.github_actions +21 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +78 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/active_record_migrations.rb +4 -0
- data/spec/dummy/config/initializers/assets.rb +8 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +2 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/structure.sql +3430 -0
- data/spec/dummy/db/structure.sql.from_rails_3 +3403 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/factories/mdm/addresses.rb +12 -0
- data/spec/factories/mdm/clients.rb +8 -0
- data/spec/factories/mdm/creds.rb +17 -0
- data/spec/factories/mdm/events.rb +15 -0
- data/spec/factories/mdm/exploit_attempts.rb +8 -0
- data/spec/factories/mdm/exploited_hosts.rb +7 -0
- data/spec/factories/mdm/fingerprints/nessus_fingerprints.rb +6 -0
- data/spec/factories/mdm/fingerprints/nexpose_fingerprints.rb +6 -0
- data/spec/factories/mdm/fingerprints/nmap_fingerprints.rb +6 -0
- data/spec/factories/mdm/fingerprints/retina_fingerprints.rb +6 -0
- data/spec/factories/mdm/fingerprints/session_fingerprints.rb +6 -0
- data/spec/factories/mdm/host_details.rb +8 -0
- data/spec/factories/mdm/host_tags.rb +9 -0
- data/spec/factories/mdm/hosts.rb +85 -0
- data/spec/factories/mdm/listeners.rb +12 -0
- data/spec/factories/mdm/loots.rb +11 -0
- data/spec/factories/mdm/module/actions.rb +14 -0
- data/spec/factories/mdm/module/archs.rb +14 -0
- data/spec/factories/mdm/module/authors.rb +22 -0
- data/spec/factories/mdm/module/details.rb +73 -0
- data/spec/factories/mdm/module/mixins.rb +14 -0
- data/spec/factories/mdm/module/platforms.rb +14 -0
- data/spec/factories/mdm/module/refs.rb +14 -0
- data/spec/factories/mdm/module/targets.rb +19 -0
- data/spec/factories/mdm/nexpose_consoles.rb +15 -0
- data/spec/factories/mdm/notes.rb +12 -0
- data/spec/factories/mdm/refs.rb +9 -0
- data/spec/factories/mdm/routes.rb +36 -0
- data/spec/factories/mdm/services.rb +41 -0
- data/spec/factories/mdm/session_events.rb +8 -0
- data/spec/factories/mdm/sessions.rb +13 -0
- data/spec/factories/mdm/tags.rb +14 -0
- data/spec/factories/mdm/task.rb +16 -0
- data/spec/factories/mdm/task_creds.rb +9 -0
- data/spec/factories/mdm/task_hosts.rb +9 -0
- data/spec/factories/mdm/task_services.rb +8 -0
- data/spec/factories/mdm/task_sessions.rb +8 -0
- data/spec/factories/mdm/users.rb +22 -0
- data/spec/factories/mdm/vuln_attempts.rb +8 -0
- data/spec/factories/mdm/vuln_details.rb +8 -0
- data/spec/factories/mdm/vuln_refs.rb +4 -0
- data/spec/factories/mdm/vulns.rb +20 -0
- data/spec/factories/mdm/web_forms.rb +33 -0
- data/spec/factories/mdm/web_pages.rb +64 -0
- data/spec/factories/mdm/web_sites.rb +8 -0
- data/spec/factories/mdm/web_vulns.rb +64 -0
- data/spec/factories/mdm/workspaces.rb +23 -0
- data/spec/factories/metasploit_data_models/automatic_exploitation/match_results.rb +7 -0
- data/spec/factories/metasploit_data_models/automatic_exploitation/match_sets.rb +8 -0
- data/spec/factories/metasploit_data_models/automatic_exploitation/matches.rb +7 -0
- data/spec/factories/metasploit_data_models/automatic_exploitation/runs.rb +6 -0
- data/spec/factories/module_runs.rb +40 -0
- data/spec/lib/base64_serializer_spec.rb +172 -0
- data/spec/lib/ipaddr_spec.rb +29 -0
- data/spec/lib/metasploit_data_models/ip_address/cidr_spec.rb +356 -0
- data/spec/lib/metasploit_data_models/ip_address/range_spec.rb +75 -0
- data/spec/lib/metasploit_data_models/match/child_spec.rb +59 -0
- data/spec/lib/metasploit_data_models/match/parent_spec.rb +153 -0
- data/spec/lib/metasploit_data_models_spec.rb +13 -0
- data/spec/spec_helper.rb +148 -0
- data/spec/support/matchers/match_regex_exactly.rb +28 -0
- data/spec/support/shared/contexts/rex/text.rb +15 -0
- data/spec/support/shared/examples/coerces_inet_column_type_to_string.rb +15 -0
- data/spec/support/shared/examples/mdm/module/detail/does_not_support_stance_with_mtype.rb +20 -0
- data/spec/support/shared/examples/mdm/module/detail/supports_stance_with_mtype.rb +36 -0
- data/spec/support/shared/examples/metasploit_data_models/search/operation/ipaddress/match.rb +109 -0
- data/spec/support/shared/examples/metasploit_data_models/search/visitor/includes/visit/with_children.rb +38 -0
- data/spec/support/shared/examples/metasploit_data_models/search/visitor/includes/visit/with_metasploit_model_search_operation_base.rb +26 -0
- data/spec/support/shared/examples/metasploit_data_models/search/visitor/relation/visit/matching_record.rb +50 -0
- data/spec/support/shared/examples/metasploit_data_models/search/visitor/where/visit/with_equality.rb +34 -0
- data/spec/support/shared/examples/metasploit_data_models/search/visitor/where/visit/with_metasploit_model_search_group_base.rb +51 -0
- 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
|