active_stix 0.1.21
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +32 -0
- data/app/assets/config/active_stix_manifest.js +2 -0
- data/app/assets/javascripts/active_stix/application.js +15 -0
- data/app/assets/javascripts/active_stix/artifacts.js +2 -0
- data/app/assets/javascripts/active_stix/attack_patterns.js +2 -0
- data/app/assets/javascripts/active_stix/bcc_refs.js +2 -0
- data/app/assets/javascripts/active_stix/bundled_objects.js +2 -0
- data/app/assets/javascripts/active_stix/bundles.js +2 -0
- data/app/assets/javascripts/active_stix/campaigns.js +2 -0
- data/app/assets/javascripts/active_stix/course_of_actions.js +2 -0
- data/app/assets/javascripts/active_stix/cyber_observables.js +2 -0
- data/app/assets/javascripts/active_stix/email_messages.js +2 -0
- data/app/assets/javascripts/active_stix/external_references.js +2 -0
- data/app/assets/javascripts/active_stix/files.js +2 -0
- data/app/assets/javascripts/active_stix/identities.js +2 -0
- data/app/assets/javascripts/active_stix/indicator_labels.js +2 -0
- data/app/assets/javascripts/active_stix/indicators.js +2 -0
- data/app/assets/javascripts/active_stix/intrusion_sets.js +2 -0
- data/app/assets/javascripts/active_stix/kill_chain_phases.js +2 -0
- data/app/assets/javascripts/active_stix/kill_chains.js +2 -0
- data/app/assets/javascripts/active_stix/malwares.js +2 -0
- data/app/assets/javascripts/active_stix/marking_definitions.js +2 -0
- data/app/assets/javascripts/active_stix/observed_data.js +2 -0
- data/app/assets/javascripts/active_stix/open_vocabularies.js +2 -0
- data/app/assets/javascripts/active_stix/phases.js +2 -0
- data/app/assets/javascripts/active_stix/recipients.js +2 -0
- data/app/assets/javascripts/active_stix/relationships.js +2 -0
- data/app/assets/javascripts/active_stix/reports.js +2 -0
- data/app/assets/javascripts/active_stix/threat_actors.js +2 -0
- data/app/assets/javascripts/active_stix/tools.js +2 -0
- data/app/assets/javascripts/active_stix/urls.js +2 -0
- data/app/assets/javascripts/active_stix/users.js +2 -0
- data/app/assets/stylesheets/active_stix/application.css +15 -0
- data/app/assets/stylesheets/active_stix/artifacts.css +4 -0
- data/app/assets/stylesheets/active_stix/attack_patterns.css +4 -0
- data/app/assets/stylesheets/active_stix/bcc_refs.css +4 -0
- data/app/assets/stylesheets/active_stix/bundled_objects.css +4 -0
- data/app/assets/stylesheets/active_stix/bundles.css +4 -0
- data/app/assets/stylesheets/active_stix/campaigns.css +4 -0
- data/app/assets/stylesheets/active_stix/course_of_actions.css +4 -0
- data/app/assets/stylesheets/active_stix/cyber_observables.css +4 -0
- data/app/assets/stylesheets/active_stix/email_messages.css +4 -0
- data/app/assets/stylesheets/active_stix/external_references.css +4 -0
- data/app/assets/stylesheets/active_stix/files.css +4 -0
- data/app/assets/stylesheets/active_stix/identities.css +4 -0
- data/app/assets/stylesheets/active_stix/indicator_labels.css +4 -0
- data/app/assets/stylesheets/active_stix/indicators.css +4 -0
- data/app/assets/stylesheets/active_stix/intrusion_sets.css +4 -0
- data/app/assets/stylesheets/active_stix/kill_chain_phases.css +4 -0
- data/app/assets/stylesheets/active_stix/kill_chains.css +4 -0
- data/app/assets/stylesheets/active_stix/malwares.css +4 -0
- data/app/assets/stylesheets/active_stix/marking_definitions.css +4 -0
- data/app/assets/stylesheets/active_stix/observed_data.css +4 -0
- data/app/assets/stylesheets/active_stix/open_vocabularies.css +4 -0
- data/app/assets/stylesheets/active_stix/phases.css +4 -0
- data/app/assets/stylesheets/active_stix/recipients.css +4 -0
- data/app/assets/stylesheets/active_stix/relationships.css +4 -0
- data/app/assets/stylesheets/active_stix/reports.css +4 -0
- data/app/assets/stylesheets/active_stix/threat_actors.css +4 -0
- data/app/assets/stylesheets/active_stix/tools.css +4 -0
- data/app/assets/stylesheets/active_stix/urls.css +4 -0
- data/app/assets/stylesheets/active_stix/users.css +4 -0
- data/app/assets/stylesheets/scaffold.css +80 -0
- data/app/controllers/active_stix/application_controller.rb +5 -0
- data/app/controllers/active_stix/artifacts_controller.rb +62 -0
- data/app/controllers/active_stix/attack_patterns_controller.rb +27 -0
- data/app/controllers/active_stix/bcc_refs_controller.rb +62 -0
- data/app/controllers/active_stix/bundled_objects_controller.rb +62 -0
- data/app/controllers/active_stix/bundles_controller.rb +11 -0
- data/app/controllers/active_stix/campaigns_controller.rb +74 -0
- data/app/controllers/active_stix/course_of_actions_controller.rb +62 -0
- data/app/controllers/active_stix/cyber_observables_controller.rb +62 -0
- data/app/controllers/active_stix/email_addresses_controller.rb +74 -0
- data/app/controllers/active_stix/email_messages_controller.rb +26 -0
- data/app/controllers/active_stix/external_references_controller.rb +62 -0
- data/app/controllers/active_stix/files_controller.rb +74 -0
- data/app/controllers/active_stix/identities_controller.rb +128 -0
- data/app/controllers/active_stix/indicator_labels_controller.rb +62 -0
- data/app/controllers/active_stix/indicators_controller.rb +62 -0
- data/app/controllers/active_stix/intrusion_sets_controller.rb +62 -0
- data/app/controllers/active_stix/kill_chain_phases_controller.rb +62 -0
- data/app/controllers/active_stix/kill_chains_controller.rb +62 -0
- data/app/controllers/active_stix/malwares_controller.rb +62 -0
- data/app/controllers/active_stix/marking_definitions_controller.rb +62 -0
- data/app/controllers/active_stix/observed_data_controller.rb +62 -0
- data/app/controllers/active_stix/open_vocabularies_controller.rb +62 -0
- data/app/controllers/active_stix/phases_controller.rb +62 -0
- data/app/controllers/active_stix/recipients_controller.rb +62 -0
- data/app/controllers/active_stix/relationships_controller.rb +62 -0
- data/app/controllers/active_stix/reports_controller.rb +62 -0
- data/app/controllers/active_stix/threat_actors_controller.rb +75 -0
- data/app/controllers/active_stix/tools_controller.rb +62 -0
- data/app/controllers/active_stix/urls_controller.rb +62 -0
- data/app/controllers/active_stix/user_accounts_controller.rb +74 -0
- data/app/controllers/active_stix/users_controller.rb +62 -0
- data/app/helpers/active_stix/application_helper.rb +4 -0
- data/app/helpers/active_stix/artifacts_helper.rb +4 -0
- data/app/helpers/active_stix/attack_patterns_helper.rb +4 -0
- data/app/helpers/active_stix/bcc_refs_helper.rb +4 -0
- data/app/helpers/active_stix/bundled_objects_helper.rb +4 -0
- data/app/helpers/active_stix/bundles_helper.rb +4 -0
- data/app/helpers/active_stix/campaigns_helper.rb +4 -0
- data/app/helpers/active_stix/course_of_actions_helper.rb +4 -0
- data/app/helpers/active_stix/cyber_observables_helper.rb +4 -0
- data/app/helpers/active_stix/email_messages_helper.rb +4 -0
- data/app/helpers/active_stix/external_references_helper.rb +4 -0
- data/app/helpers/active_stix/files_helper.rb +4 -0
- data/app/helpers/active_stix/identities_helper.rb +4 -0
- data/app/helpers/active_stix/indicator_labels_helper.rb +4 -0
- data/app/helpers/active_stix/indicators_helper.rb +4 -0
- data/app/helpers/active_stix/intrusion_sets_helper.rb +4 -0
- data/app/helpers/active_stix/kill_chain_phases_helper.rb +4 -0
- data/app/helpers/active_stix/kill_chains_helper.rb +4 -0
- data/app/helpers/active_stix/malwares_helper.rb +4 -0
- data/app/helpers/active_stix/marking_definitions_helper.rb +4 -0
- data/app/helpers/active_stix/observed_data_helper.rb +4 -0
- data/app/helpers/active_stix/open_vocabularies_helper.rb +4 -0
- data/app/helpers/active_stix/phases_helper.rb +4 -0
- data/app/helpers/active_stix/recipients_helper.rb +4 -0
- data/app/helpers/active_stix/relationships_helper.rb +4 -0
- data/app/helpers/active_stix/reports_helper.rb +4 -0
- data/app/helpers/active_stix/threat_actors_helper.rb +4 -0
- data/app/helpers/active_stix/tools_helper.rb +4 -0
- data/app/helpers/active_stix/urls_helper.rb +4 -0
- data/app/helpers/active_stix/users_helper.rb +4 -0
- data/app/jobs/active_stix/application_job.rb +4 -0
- data/app/mailers/active_stix/application_mailer.rb +6 -0
- data/app/models/active_stix/application_record.rb +5 -0
- data/app/models/active_stix/artifact.rb +23 -0
- data/app/models/active_stix/attack_pattern.rb +150 -0
- data/app/models/active_stix/bcc_ref.rb +6 -0
- data/app/models/active_stix/bundle.rb +108 -0
- data/app/models/active_stix/bundled_object.rb +4 -0
- data/app/models/active_stix/campaign.rb +65 -0
- data/app/models/active_stix/cc_ref.rb +6 -0
- data/app/models/active_stix/course_of_action.rb +54 -0
- data/app/models/active_stix/cyber_observable.rb +4 -0
- data/app/models/active_stix/email_address.rb +27 -0
- data/app/models/active_stix/email_message.rb +339 -0
- data/app/models/active_stix/external_reference.rb +48 -0
- data/app/models/active_stix/file.rb +2 -0
- data/app/models/active_stix/identity.rb +141 -0
- data/app/models/active_stix/indicator.rb +58 -0
- data/app/models/active_stix/indicator_label.rb +4 -0
- data/app/models/active_stix/intrusion_set.rb +69 -0
- data/app/models/active_stix/kill_chain.rb +7 -0
- data/app/models/active_stix/kill_chain_phase.rb +6 -0
- data/app/models/active_stix/label.rb +17 -0
- data/app/models/active_stix/label_malware.rb +4 -0
- data/app/models/active_stix/label_report.rb +4 -0
- data/app/models/active_stix/label_tool.rb +4 -0
- data/app/models/active_stix/malware.rb +98 -0
- data/app/models/active_stix/marking_definition.rb +21 -0
- data/app/models/active_stix/markup.rb +6 -0
- data/app/models/active_stix/object_marking.rb +11 -0
- data/app/models/active_stix/observed_datum.rb +67 -0
- data/app/models/active_stix/open_vocabulary.rb +8 -0
- data/app/models/active_stix/phase.rb +41 -0
- data/app/models/active_stix/recipient.rb +4 -0
- data/app/models/active_stix/reference_item.rb +4 -0
- data/app/models/active_stix/relationship.rb +95 -0
- data/app/models/active_stix/report.rb +93 -0
- data/app/models/active_stix/report_object.rb +9 -0
- data/app/models/active_stix/threat_actor.rb +139 -0
- data/app/models/active_stix/to_ref.rb +6 -0
- data/app/models/active_stix/tool.rb +112 -0
- data/app/models/active_stix/url.rb +15 -0
- data/app/models/active_stix/user.rb +4 -0
- data/app/models/active_stix/user_account.rb +3 -0
- data/app/views/active_stix/artifacts/_form.html.erb +57 -0
- data/app/views/active_stix/artifacts/edit.html.erb +6 -0
- data/app/views/active_stix/artifacts/index.html.erb +41 -0
- data/app/views/active_stix/artifacts/new.html.erb +5 -0
- data/app/views/active_stix/artifacts/show.html.erb +44 -0
- data/app/views/active_stix/attack_patterns/_form.html.erb +37 -0
- data/app/views/active_stix/attack_patterns/edit.html.erb +2 -0
- data/app/views/active_stix/attack_patterns/index.html.erb +2 -0
- data/app/views/active_stix/attack_patterns/new.html.erb +2 -0
- data/app/views/active_stix/attack_patterns/show.html.erb +140 -0
- data/app/views/active_stix/bcc_refs/_form.html.erb +27 -0
- data/app/views/active_stix/bcc_refs/edit.html.erb +6 -0
- data/app/views/active_stix/bcc_refs/index.html.erb +29 -0
- data/app/views/active_stix/bcc_refs/new.html.erb +5 -0
- data/app/views/active_stix/bcc_refs/show.html.erb +14 -0
- data/app/views/active_stix/bundles/index.html.erb +1 -0
- data/app/views/active_stix/bundles/show.html.erb +7 -0
- data/app/views/active_stix/campaigns/_form.html.erb +42 -0
- data/app/views/active_stix/campaigns/_stix_campaign.json.jbuilder +2 -0
- data/app/views/active_stix/campaigns/edit.html.erb +6 -0
- data/app/views/active_stix/campaigns/index.html.erb +35 -0
- data/app/views/active_stix/campaigns/index.json.jbuilder +1 -0
- data/app/views/active_stix/campaigns/new.html.erb +5 -0
- data/app/views/active_stix/campaigns/show.html.erb +29 -0
- data/app/views/active_stix/campaigns/show.json.jbuilder +1 -0
- data/app/views/active_stix/email_messages/_form.html.erb +62 -0
- data/app/views/active_stix/email_messages/_stix_email_message.json.jbuilder +2 -0
- data/app/views/active_stix/email_messages/edit.html.erb +6 -0
- data/app/views/active_stix/email_messages/index.html.erb +43 -0
- data/app/views/active_stix/email_messages/index.json.jbuilder +1 -0
- data/app/views/active_stix/email_messages/new.html.erb +5 -0
- data/app/views/active_stix/email_messages/show.html.erb +165 -0
- data/app/views/active_stix/email_messages/show.json.jbuilder +1 -0
- data/app/views/active_stix/files/_form.html.erb +92 -0
- data/app/views/active_stix/files/_stix_file.json.jbuilder +2 -0
- data/app/views/active_stix/files/edit.html.erb +6 -0
- data/app/views/active_stix/files/index.html.erb +55 -0
- data/app/views/active_stix/files/index.json.jbuilder +1 -0
- data/app/views/active_stix/files/new.html.erb +5 -0
- data/app/views/active_stix/files/show.html.erb +79 -0
- data/app/views/active_stix/files/show.json.jbuilder +1 -0
- data/app/views/active_stix/identities/_form.html.erb +27 -0
- data/app/views/active_stix/identities/_individual.html.erb +100 -0
- data/app/views/active_stix/identities/_organization.html.erb +72 -0
- data/app/views/active_stix/identities/_received_email_messages.html.erb +27 -0
- data/app/views/active_stix/identities/_sent_email_messages.html.erb +27 -0
- data/app/views/active_stix/identities/_threat_icons.html.erb +3 -0
- data/app/views/active_stix/identities/edit.html.erb +2 -0
- data/app/views/active_stix/identities/index.html.erb +37 -0
- data/app/views/active_stix/identities/new.html.erb +5 -0
- data/app/views/active_stix/identities/show.html.erb +15 -0
- data/app/views/active_stix/layouts/active_stix/application.html.erb +16 -0
- data/app/views/active_stix/recipients/_form.html.erb +27 -0
- data/app/views/active_stix/recipients/edit.html.erb +6 -0
- data/app/views/active_stix/recipients/index.html.erb +29 -0
- data/app/views/active_stix/recipients/new.html.erb +5 -0
- data/app/views/active_stix/recipients/show.html.erb +14 -0
- data/app/views/active_stix/threat_actors/_form.html.erb +32 -0
- data/app/views/active_stix/threat_actors/_stix_threat_actor.json.jbuilder +2 -0
- data/app/views/active_stix/threat_actors/edit.html.erb +6 -0
- data/app/views/active_stix/threat_actors/flags.html.erb +184 -0
- data/app/views/active_stix/threat_actors/index.html.erb +26 -0
- data/app/views/active_stix/threat_actors/index.json.jbuilder +1 -0
- data/app/views/active_stix/threat_actors/new.html.erb +5 -0
- data/app/views/active_stix/threat_actors/show.html.erb +4 -0
- data/app/views/active_stix/threat_actors/show.json.jbuilder +1 -0
- data/app/views/layouts/active_stix/application.html.erb +16 -0
- data/config/routes.rb +39 -0
- data/db/migrate/20191204200025_create_active_stix_bundled_objects.rb +11 -0
- data/db/migrate/20191204213707_create_active_stix_bundles.rb +10 -0
- data/db/migrate/20191204213802_create_active_stix_campaigns.rb +15 -0
- data/db/migrate/20191204213926_create_active_stix_course_of_actions.rb +12 -0
- data/db/migrate/20191204214020_create_active_stix_cyber_observables.rb +11 -0
- data/db/migrate/20191204214955_create_active_stix_email_messages.rb +20 -0
- data/db/migrate/20191204215029_create_active_stix_external_references.rb +12 -0
- data/db/migrate/20191204215302_create_active_stix_files.rb +23 -0
- data/db/migrate/20191204215419_create_active_stix_identities.rb +13 -0
- data/db/migrate/20191204215542_create_active_stix_indicator_labels.rb +10 -0
- data/db/migrate/20191204215637_create_active_stix_indicators.rb +16 -0
- data/db/migrate/20191204215849_create_active_stix_intrusion_sets.rb +15 -0
- data/db/migrate/20191204215929_create_active_stix_kill_chain_phases.rb +10 -0
- data/db/migrate/20191204215951_create_active_stix_kill_chains.rb +9 -0
- data/db/migrate/20191204220149_create_active_stix_malwares.rb +12 -0
- data/db/migrate/20191204220539_create_active_stix_marking_definitions.rb +12 -0
- data/db/migrate/20191204220853_create_active_stix_observed_data.rb +12 -0
- data/db/migrate/20191204220917_create_active_stix_open_vocabularies.rb +9 -0
- data/db/migrate/20191204220952_create_active_stix_phases.rb +11 -0
- data/db/migrate/20191204221129_create_active_stix_recipients.rb +10 -0
- data/db/migrate/20191204221227_create_active_stix_relationships.rb +16 -0
- data/db/migrate/20191204221323_create_active_stix_report_objects.rb +11 -0
- data/db/migrate/20191204221359_create_active_stix_reports.rb +14 -0
- data/db/migrate/20191204221425_create_active_stix_threat_actors.rb +11 -0
- data/db/migrate/20191204221454_create_active_stix_tools.rb +12 -0
- data/db/migrate/20191204221639_create_active_stix_urls.rb +9 -0
- data/db/migrate/20191204221849_create_active_stix_users.rb +22 -0
- data/db/migrate/20191205182234_create_active_stix_bcc_refs.rb +10 -0
- data/db/migrate/20191205182255_create_active_stix_cc_refs.rb +10 -0
- data/db/migrate/20191205182316_create_active_stix_to_refs.rb +10 -0
- data/db/migrate/20191212203611_add_spec_version_to_bundles.rb +5 -0
- data/db/migrate/20191212215136_create_active_stix_attack_patterns.rb +12 -0
- data/db/migrate/20191212220222_create_active_stix_reference_items.rb +11 -0
- data/db/migrate/20191213135204_create_active_stix_labels.rb +10 -0
- data/db/migrate/20191213140951_create_active_stix_markups.rb +11 -0
- data/db/migrate/20191221210537_fix_observed_data.rb +6 -0
- data/db/migrate/20191221223602_create_active_stix_artifacts.rb +16 -0
- data/db/migrate/20191223075550_change_artifact_ref_to_string.rb +5 -0
- data/db/migrate/20191223154000_add_stix_id_to_email_messages.rb +5 -0
- data/db/migrate/20200114162245_add_labels_to_active_stix_identities.rb +5 -0
- data/db/migrate/20200404223006_add_aliases_to_tools.rb +5 -0
- data/db/migrate/20200404223047_add_aliases_to_attack_patterns.rb +5 -0
- data/db/migrate/20200404223158_add_aliases_to_malwares.rb +5 -0
- data/db/migrate/20200404223210_add_aliases_to_threat_actors.rb +5 -0
- data/lib/active_stix.rb +8 -0
- data/lib/active_stix/engine.rb +13 -0
- data/lib/active_stix/version.rb +3 -0
- data/lib/tasks/active_stix_tasks.rake +4 -0
- metadata +358 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
class ActiveStix::Campaign < ApplicationRecord
|
2
|
+
has_many :source_relationships, class_name: 'ActiveStix::Relationship', primary_key: 'stix_id', foreign_key: 'source_ref' #relationships where this class is the source
|
3
|
+
has_many :target_relationships, class_name: 'ActiveStix::Relationship', primary_key: 'stix_id', foreign_key: 'target_ref' #relationships where this class is the target
|
4
|
+
|
5
|
+
def self.ingest_json(obj)
|
6
|
+
camp = find_or_create_by(stix_id: obj['id'], name: obj['name'], description: obj['description'], first_seen: obj['first_seen'], last_seen: obj['last_seen'])
|
7
|
+
camp
|
8
|
+
end
|
9
|
+
|
10
|
+
before_create do
|
11
|
+
self.stix_id = "#{type}--#{SecureRandom.uuid}" if stix_id.blank?
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def type
|
16
|
+
'campaign'
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def attack_patterns
|
21
|
+
attack_pattern_relationships.map(&:target)
|
22
|
+
end
|
23
|
+
|
24
|
+
def attack_pattern_relationships
|
25
|
+
relationships = []
|
26
|
+
ActiveStix::Relationship.where(source: self, relationship_type: "uses", target_type: "ActiveStix::AttackPattern").each do |rel|
|
27
|
+
relationships << rel
|
28
|
+
end
|
29
|
+
relationships
|
30
|
+
end
|
31
|
+
|
32
|
+
def indicator_relationships
|
33
|
+
relationships = []
|
34
|
+
ActiveStix::Relationship.where(source_type: "ActiveStix::Indicator", relationship_type: "indicates", target: self).each do |rel|
|
35
|
+
relationships << rel
|
36
|
+
end
|
37
|
+
relationships
|
38
|
+
end
|
39
|
+
|
40
|
+
def as_stix
|
41
|
+
as_json(only: []).tap do |hash|
|
42
|
+
hash["id"] = stix_id
|
43
|
+
hash["type"] = type
|
44
|
+
hash["created"] = created_at.rfc3339(3)
|
45
|
+
hash["modified"] = updated_at.rfc3339(3)
|
46
|
+
hash["first_seen"] = created_at.rfc3339(3)
|
47
|
+
hash["last_seen"] = updated_at.rfc3339(3)
|
48
|
+
hash["name"] = name
|
49
|
+
hash["description"] = description
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def convert_to_json
|
54
|
+
{
|
55
|
+
:type => "campaign",
|
56
|
+
:id => stix_id,
|
57
|
+
:created => created_at.to_s,
|
58
|
+
:modified => updated_at.to_s,
|
59
|
+
:name => name,
|
60
|
+
:description => description,
|
61
|
+
:first_seen => first_seen,
|
62
|
+
:last_seen => last_seen
|
63
|
+
}
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module ActiveStix
|
2
|
+
class CourseOfAction < ApplicationRecord
|
3
|
+
has_many :reference_items, as: 'referrer'
|
4
|
+
has_many :external_references, class_name: 'ActiveStix::ExternalReference', through: :reference_items
|
5
|
+
|
6
|
+
has_many :reference_object_marking_courses, class_name: 'ActiveStix::ReferenceObjectMarkingCourse', foreign_key: 'stix_course_of_action_id'
|
7
|
+
has_many :marking_definitions, class_name: 'ActiveStix::MarkingDefinition', through: :reference_object_marking_courses, primary_key: 'id'
|
8
|
+
|
9
|
+
has_many :source_relationships, class_name: 'ActiveStix::Relationship', primary_key: 'stix_id', foreign_key: 'source_ref' #relationships where this class is the source
|
10
|
+
has_many :target_relationships, class_name: 'ActiveStix::Relationship', primary_key: 'stix_id', foreign_key: 'target_ref' #relationships where this class is the target
|
11
|
+
|
12
|
+
def self.ingest_json(obj)
|
13
|
+
course_of_action = find_or_create_by(stix_id: obj['id'], name: obj['name'], description: obj['description'])
|
14
|
+
if obj.has_key?('external_references')
|
15
|
+
obj['external_references'].each do |er|
|
16
|
+
external_reference = ExternalReference.ingest_json(er, obj['id'])
|
17
|
+
course_of_action.external_references << external_reference unless ActiveStix::ReferenceItem.find_by(external_reference:external_reference, referrer: course_of_action)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
if obj.has_key?('object_marking_refs')
|
21
|
+
# TODO
|
22
|
+
# obj['object_marking_refs'].each do |mr|
|
23
|
+
# marking_definition = MarkingDefinition.create_by_id(mr)
|
24
|
+
# course_of_action.marking_definitions << marking_definition unless ActiveStix::ReferenceObjectMarkingCourse.find_by(stix_marking_definition_id:marking_definition.id, stix_course_of_action_id:course_of_action.id)
|
25
|
+
# end
|
26
|
+
end
|
27
|
+
course_of_action.save
|
28
|
+
course_of_action
|
29
|
+
end
|
30
|
+
|
31
|
+
def convert_to_json
|
32
|
+
external_refs_arr = []
|
33
|
+
external_references.each do | x |
|
34
|
+
external_refs_arr << x.convert_to_json
|
35
|
+
end
|
36
|
+
|
37
|
+
marking_def_arr = []
|
38
|
+
marking_definitions.each do | x |
|
39
|
+
marking_def_arr << x.convert_to_json
|
40
|
+
end
|
41
|
+
|
42
|
+
{
|
43
|
+
:external_references => external_refs_arr,
|
44
|
+
:object_marking_refs => marking_def_arr,
|
45
|
+
:id => stix_id,
|
46
|
+
:name => name,
|
47
|
+
:type => "course-of-action",
|
48
|
+
:modified => updated_at.to_s,
|
49
|
+
:created => created_at.to_s,
|
50
|
+
:description => description
|
51
|
+
}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,4 @@
|
|
1
|
+
class ActiveStix::CyberObservable < ApplicationRecord
|
2
|
+
belongs_to :observed_datum, :class_name => 'ActiveStix::ObservedDatum', foreign_key: :observed_datum_ref, primary_key: :stix_id
|
3
|
+
belongs_to :cyber_observable_object, polymorphic: true, foreign_key: :observable_object_id
|
4
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ActiveStix
|
2
|
+
class EmailAddress < ApplicationRecord
|
3
|
+
|
4
|
+
has_many :to_refs, foreign_key: 'stix_email_address_id'
|
5
|
+
has_many :email_messages, foreign_key: :from_ref
|
6
|
+
belongs_to :identity, class_name: 'ActiveStix::Identity'
|
7
|
+
|
8
|
+
# after_create_commit do
|
9
|
+
# assign_iddentity_to_group
|
10
|
+
# end
|
11
|
+
|
12
|
+
def self.from_eml(eml)
|
13
|
+
eml.correspondences.all.collect do |c|
|
14
|
+
{
|
15
|
+
"type": "email-address",
|
16
|
+
"value": c.email.address,
|
17
|
+
"display_name": c.email.alias,
|
18
|
+
"from_ref": c.agent.id
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def assign_identity_to_group
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,339 @@
|
|
1
|
+
module ActiveStix
|
2
|
+
class EmailMessage < ApplicationRecord
|
3
|
+
has_many :to_refs, foreign_key: 'email_message_id'
|
4
|
+
has_many :cc_refs, foreign_key: 'email_message_id'
|
5
|
+
has_many :bcc_refs, foreign_key: 'email_message_id'
|
6
|
+
has_many :recipients, foreign_key: 'email_message_id'
|
7
|
+
has_many :cyber_observables, :class_name => 'ActiveStix::CyberObservable', foreign_key: :observable_object_id, as: :cyber_observable_object
|
8
|
+
has_many :observed_data, through: :cyber_observables
|
9
|
+
belongs_to :from, class_name: 'ActiveStix::EmailAddress', foreign_key: 'from_ref'
|
10
|
+
belongs_to :raw_email_artifact, foreign_key: :raw_email_ref, class_name: 'ActiveStix::Artifact', primary_key: :stix_id
|
11
|
+
|
12
|
+
|
13
|
+
before_create do
|
14
|
+
self.stix_id = "#{type}--#{SecureRandom.uuid}" if stix_id.blank?
|
15
|
+
end
|
16
|
+
|
17
|
+
after_create do
|
18
|
+
ActiveStix::ObservedDatum.wrap_object(self)
|
19
|
+
end
|
20
|
+
|
21
|
+
def primary_observed_datum
|
22
|
+
observed_data.first
|
23
|
+
end
|
24
|
+
|
25
|
+
def from_identity
|
26
|
+
from.identity
|
27
|
+
end
|
28
|
+
|
29
|
+
def identities
|
30
|
+
ids = [from.identity]
|
31
|
+
to_refs.each do |tr|
|
32
|
+
ids << tr.email_address.identity
|
33
|
+
end
|
34
|
+
|
35
|
+
cc_refs.each do |ccr|
|
36
|
+
ids << ccr.email_address.identity
|
37
|
+
end
|
38
|
+
|
39
|
+
bcc_refs.each do |bccr|
|
40
|
+
ids << bccr.email_address.identity
|
41
|
+
end
|
42
|
+
ids.uniq
|
43
|
+
end
|
44
|
+
|
45
|
+
def mail_server
|
46
|
+
Mail.new(raw_email_artifact.payload_bin).message_id.split(/[@\.]/)[-3..-1]
|
47
|
+
end
|
48
|
+
|
49
|
+
def readable
|
50
|
+
eml.readable
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.from_eml(eml)
|
54
|
+
eml = eml.encode(Encoding.find('UTF-8'), {invalid: :replace, undef: :replace, replace: ''}).sub("\xEF\xBB\xBF".force_encoding('UTF-8'), "").gsub("\r", "").unicode_normalize(:nfkc)
|
55
|
+
mail = Mail.new(eml)
|
56
|
+
|
57
|
+
#TODO Add details for cc_refs, bcc_refs etc. from the email message object
|
58
|
+
|
59
|
+
is_multipart = mail.multipart?
|
60
|
+
date = mail.date
|
61
|
+
content_type = mail.content_type
|
62
|
+
from = create_from(mail, eml)
|
63
|
+
sender_ref = create_sender(mail, eml)
|
64
|
+
subject = mail.header["Subject"] ? mail.header["Subject"].value : ""
|
65
|
+
received_lines = mail.header["Received"]
|
66
|
+
|
67
|
+
#TODO add the appropriate details here later
|
68
|
+
#TODO late make additional header fields more specific, check stix spec
|
69
|
+
email_message = EmailMessage.create(
|
70
|
+
"is_multipart": is_multipart,
|
71
|
+
"date": date,
|
72
|
+
"content_type": content_type,
|
73
|
+
"from": from,
|
74
|
+
"sender_ref": sender_ref,
|
75
|
+
"subject": subject,
|
76
|
+
"received_lines": received_lines,
|
77
|
+
"additional_header_fields": mail.header,
|
78
|
+
"body": mail.body,
|
79
|
+
"body_multipart": body_multipart(mail),
|
80
|
+
"raw_email_ref": raw_email_artifact(mail).stix_id
|
81
|
+
)
|
82
|
+
create_recipients(mail, eml, email_message)
|
83
|
+
|
84
|
+
email_message
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.raw_email_artifact(eml)
|
88
|
+
artifact = Artifact.create_from_eml(eml)
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.body_multipart(mail)
|
92
|
+
if mail.multipart?
|
93
|
+
mail.parts.collect {|part| part.mime_type}
|
94
|
+
else
|
95
|
+
nil
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def type
|
100
|
+
return "email-message"
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.extract_info_from_address_header(descriptive_name)
|
104
|
+
descriptive_name = descriptive_name.to_s
|
105
|
+
descriptive_name.gsub!('\"', '')
|
106
|
+
temp = descriptive_name.split(' via ')
|
107
|
+
fullname = temp[0].to_s
|
108
|
+
if temp.size > 1
|
109
|
+
medium = temp[1]
|
110
|
+
end
|
111
|
+
if not fullname.lstrip().start_with?('<')
|
112
|
+
name_parts = fullname.split(',')
|
113
|
+
if name_parts.size > 1
|
114
|
+
last_name = name_parts[0]
|
115
|
+
first_name = name_parts[1].lstrip()
|
116
|
+
else
|
117
|
+
name_parts = fullname.split(' ')
|
118
|
+
if name_parts.size > 1
|
119
|
+
first_name = name_parts[0]
|
120
|
+
last_name = name_parts[1]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
return first_name, last_name, medium
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.create_recipients(mail, eml, email_message)
|
128
|
+
if mail.header["To"]
|
129
|
+
get_recipients_by_type("To", mail, eml, email_message)
|
130
|
+
end
|
131
|
+
|
132
|
+
if mail.header["CC"]
|
133
|
+
get_recipients_by_type("CC", mail, eml, email_message)
|
134
|
+
end
|
135
|
+
|
136
|
+
if mail.header["BCC"]
|
137
|
+
get_recipients_by_type("BCC", mail, eml, email_message)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
#TODO The two methods below can definitely be consolidated to one. Make sure to do so.
|
142
|
+
def self.create_from(mail, eml)
|
143
|
+
if mail.header["From"]
|
144
|
+
mail.header["From"].address_list.addresses.each do |address|
|
145
|
+
user_account = UserAccount.where("lower(user_id) = ?", address.address.downcase).first
|
146
|
+
fname, lname, medium = extract_info_from_address_header(address.display_name)
|
147
|
+
#TODO Create an identity here so it can be linked to the user account and email address
|
148
|
+
if user_account.nil?
|
149
|
+
identity = create_identity(address.address.downcase, address.name)
|
150
|
+
user_account = UserAccount.create(user_id: address.address.downcase, account_login: get_name_from_address(address.address), display_name: address.name, is_service_account: false, is_privileged: false, can_escalate_privs: false, is_disabled: false, identity_id: identity.id)
|
151
|
+
identity.user_accounts << user_account
|
152
|
+
else
|
153
|
+
identity = user_account.identity
|
154
|
+
end
|
155
|
+
email_address = EmailAddress.where("lower(value) = ?", address.address.downcase).first
|
156
|
+
if email_address.nil?
|
157
|
+
email_address = EmailAddress.create(value: address.address.downcase, display_name: address.name, belongs_to_ref: user_account.id, identity_id: identity.id)
|
158
|
+
end
|
159
|
+
|
160
|
+
return email_address
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.create_sender(mail, eml)
|
167
|
+
if mail.from.any?
|
168
|
+
address = mail.from.first
|
169
|
+
user_account = UserAccount.where("lower(user_id) = ?", address.downcase).first
|
170
|
+
#TODO Create an identity here so it can be linked to the user account and email address
|
171
|
+
if user_account.nil?
|
172
|
+
identity = create_identity(address, address)
|
173
|
+
user_account = UserAccount.create(user_id: address, account_login: get_name_from_address(address), display_name: address, is_service_account: false, is_privileged: false, can_escalate_privs: false, is_disabled: false, identity_id: identity.id)
|
174
|
+
identity.users_accounts << user_account
|
175
|
+
else
|
176
|
+
identity = user_account.identity
|
177
|
+
end
|
178
|
+
email_address = EmailAddress.where("lower(value) = ?", address.downcase).first
|
179
|
+
if email_address.nil?
|
180
|
+
email_address = EmailAddress.create(value: address, display_name: address, belongs_to_ref: user_account.id, identity_id: identity.id)
|
181
|
+
end
|
182
|
+
return email_address
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.get_recipients_by_type(recipient_type, mail, eml, email_message)
|
187
|
+
return if mail.header[recipient_type].errors.any? # todo we should throw and catch an exception here
|
188
|
+
mail.header[recipient_type].each do |address|
|
189
|
+
# TODO this will be the user account
|
190
|
+
user_account = UserAccount.where("lower(user_id) = ?", address.address.downcase).first
|
191
|
+
|
192
|
+
fname, lname, medium = extract_info_from_address_header(address.display_name)
|
193
|
+
|
194
|
+
#TODO Create an identity here so it can be linked to the user account and email address
|
195
|
+
if user_account.nil?
|
196
|
+
identity = create_identity(address.address.downcase, address.name)
|
197
|
+
user_account = identity.user_accounts.create(user_id: address.address, account_login: get_name_from_address(address.address), display_name: address.name, is_service_account: false, is_privileged: false, can_escalate_privs: false, is_disabled: false)
|
198
|
+
else
|
199
|
+
identity = user_account.identity
|
200
|
+
end
|
201
|
+
|
202
|
+
# TODO this will be the email address
|
203
|
+
email_address = EmailAddress.where("lower(value) = ?", address.address.downcase).first
|
204
|
+
if email_address.nil?
|
205
|
+
email_address = EmailAddress.create(value: address.address.downcase, display_name: address.name, belongs_to_ref: user_account.id, identity_id: identity.id)
|
206
|
+
end
|
207
|
+
|
208
|
+
# Create header specific refs
|
209
|
+
create_recipient_type_ref(recipient_type, email_message, email_address)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.create_recipient_type_ref(recipient_type, email_message, email_address)
|
214
|
+
|
215
|
+
case recipient_type
|
216
|
+
when "To"
|
217
|
+
ToRef.create(email_message: email_message, email_address: email_address)
|
218
|
+
when "CC"
|
219
|
+
CcRef.create(email_message: email_message, email_address: email_address)
|
220
|
+
when "BCC"
|
221
|
+
BccRef.create(email_message: email_message, email_address: email_address)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def self.create_identity(address, display_name)
|
226
|
+
#TODO figure out where to get the details for whether for identity_class, description etc.
|
227
|
+
identity = Identity.create(name: display_name || Mail::Address.new(address).local, contact_information: {email_addresses: [address]}, identity_class: 'individual')
|
228
|
+
|
229
|
+
organization = from_domain_identity(address)
|
230
|
+
ActiveStix::Identity.employ(identity, organization)
|
231
|
+
|
232
|
+
return identity
|
233
|
+
end
|
234
|
+
|
235
|
+
#NOTE Instance method created for the class to use
|
236
|
+
def self.from_domain_identity(address)
|
237
|
+
org_name = Organization.company_from_email_address(address)
|
238
|
+
public_suffix = Organization.public_suffix_from_email_address(address)
|
239
|
+
|
240
|
+
organization = ActiveStix::Identity.find_or_create_by(name: org_name + public_suffix, identity_class: "organization")
|
241
|
+
|
242
|
+
if organization.contact_information.nil?
|
243
|
+
organization.update_attribute("contact_information", {domain: org_name, public_suffix: public_suffix})
|
244
|
+
else
|
245
|
+
contact_information = organization.contact_information
|
246
|
+
contact_information["public_suffix"] = public_suffix
|
247
|
+
organization.contact_information = contact_information
|
248
|
+
organization.save
|
249
|
+
end
|
250
|
+
|
251
|
+
freemail = ActiveStix::AttackPattern.find_by(name: "Free email")
|
252
|
+
if freemail and freemail.targets?(organization)
|
253
|
+
personal_organization = ActiveStix::Identity.find_or_create_by(name: address, identity_class: "organization")
|
254
|
+
ActiveStix::Identity.employ(identity, personal_organization)
|
255
|
+
end
|
256
|
+
organization
|
257
|
+
end
|
258
|
+
|
259
|
+
def from_domain_identity
|
260
|
+
ActiveStix::EmailMessage.from_domain_identity(from.value)
|
261
|
+
end
|
262
|
+
|
263
|
+
def self.get_name_from_address(address)
|
264
|
+
return address.split('@')[0]
|
265
|
+
end
|
266
|
+
|
267
|
+
def self.find_or_create_user_account(email, aliasname)
|
268
|
+
if email.agent.nil?
|
269
|
+
agent = Agent.create
|
270
|
+
agent.emails << email
|
271
|
+
else
|
272
|
+
agent = email.agent
|
273
|
+
unless agent.emails.where(alias: aliasname).any?
|
274
|
+
agent.emails << email
|
275
|
+
end
|
276
|
+
end
|
277
|
+
return agent
|
278
|
+
end
|
279
|
+
|
280
|
+
def stix_references
|
281
|
+
object_refs = {}
|
282
|
+
object_index = 1
|
283
|
+
[to_refs, cc_refs, bcc_refs].each do |field|
|
284
|
+
field.each do |ref|
|
285
|
+
object_refs[{
|
286
|
+
|
287
|
+
"type": "email-addr",
|
288
|
+
"value": ref.email_address.value.to_s,
|
289
|
+
"display_name": ref.email_address.display_name.to_s
|
290
|
+
}] = object_index.to_s
|
291
|
+
object_index += 1
|
292
|
+
end
|
293
|
+
end
|
294
|
+
object_refs[{
|
295
|
+
|
296
|
+
"type": "email-addr",
|
297
|
+
"value": from.value.to_s,
|
298
|
+
"display_name": from.display_name.to_s
|
299
|
+
}] = object_index.to_s
|
300
|
+
object_refs
|
301
|
+
end
|
302
|
+
|
303
|
+
|
304
|
+
def mail
|
305
|
+
Mail.new(eml.raw_source)
|
306
|
+
end
|
307
|
+
|
308
|
+
def as_stix
|
309
|
+
|
310
|
+
as_json(only: []).tap do |hash|
|
311
|
+
# hash["x_panacea_id"] = "<#{id}>".force_encoding("utf-8")
|
312
|
+
hash["type"] = "email-message"
|
313
|
+
|
314
|
+
mail = Mail.new(raw_email_artifact.payload_bin)
|
315
|
+
hash["date"] = mail.date.utc.iso8601(3)
|
316
|
+
|
317
|
+
# todo fix this when jpl turns on stix
|
318
|
+
hash["is_multipart"] = false
|
319
|
+
|
320
|
+
# if mail.multipart?
|
321
|
+
# stix_parts = mail.parts.collect do |part|
|
322
|
+
# {
|
323
|
+
# "content_type" => part.content_type.to_s,
|
324
|
+
# "content_disposition" => part.content_transfer_encoding.to_s,
|
325
|
+
# "body" => Digest::SHA1.hexdigest(part.to_s)
|
326
|
+
# }
|
327
|
+
# end.to_a
|
328
|
+
# hash["body_multipart"] = stix_parts
|
329
|
+
# else
|
330
|
+
# hash["body"] = eml.readable
|
331
|
+
# end
|
332
|
+
|
333
|
+
hash
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
|
338
|
+
end
|
339
|
+
end
|