attack/domain/
technique.rs1use serde::{Deserialize, Serialize};
2use stix_rs::{CommonProperties, StixObject, KillChainPhase};
3use crate::domain::AttackObject;
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7pub struct Technique {
8 #[serde(flatten)]
9 pub common: CommonProperties,
10
11 pub name: String,
12 pub description: Option<String>,
13
14 #[serde(default, rename = "x_mitre_is_subtechnique")]
15 pub is_subtechnique: bool,
16
17 #[serde(default, rename = "x_mitre_platforms")]
18 pub platforms: Vec<String>,
19
20 #[serde(default)]
21 pub kill_chain_phases: Vec<KillChainPhase>,
22
23 #[serde(default, rename = "x_mitre_version")]
25 pub version: Option<String>,
26
27 #[serde(default, rename = "x_mitre_detection")]
28 pub detection: Option<String>,
29
30 #[serde(default, rename = "x_mitre_permissions_required")]
31 pub permissions_required: Vec<String>,
32
33 #[serde(default, rename = "x_mitre_effective_permissions")]
34 pub effective_permissions: Vec<String>,
35
36 #[serde(default, rename = "x_mitre_defense_bypassed")]
37 pub defense_bypassed: Vec<String>,
38
39 #[serde(default, rename = "x_mitre_system_requirements")]
40 pub system_requirements: Vec<String>,
41
42 #[serde(default, rename = "x_mitre_network_requirements")]
43 pub network_requirements: Option<bool>,
44
45 #[serde(default, rename = "x_mitre_remote_support")]
46 pub remote_support: Option<bool>,
47
48 #[serde(default, rename = "x_mitre_data_sources")]
49 pub data_sources_legacy: Vec<String>,
50
51 #[serde(default, rename = "x_mitre_impact_type")]
52 pub impact_type: Vec<String>,
53
54 #[serde(default, rename = "x_mitre_contributors")]
55 pub contributors: Vec<String>,
56
57 #[serde(default, rename = "x_mitre_domains")]
58 pub domains: Vec<String>,
59}
60
61impl Technique {
62 pub fn tcode(&self) -> Option<&str> {
64 self.common.external_references.as_ref()?
65 .iter()
66 .find(|r| r.source_name == "mitre-attack" || r.source_name == "mitre-mobile-attack" || r.source_name == "mitre-ics-attack")?
67 .external_id.as_deref()
68 }
69
70 pub fn tactics(&self) -> Vec<&str> {
72 self.kill_chain_phases.iter()
73 .filter(|phase| phase.name == "mitre-attack" || phase.name == "mitre-mobile-attack" || phase.name == "mitre-ics-attack")
74 .map(|phase| phase.phase_name.as_str())
75 .collect()
76 }
77}
78
79impl StixObject for Technique {
80 fn id(&self) -> &str {
81 &self.common.id
82 }
83
84 fn type_(&self) -> &str {
85 &self.common.r#type
86 }
87
88 fn created(&self) -> chrono::DateTime<chrono::Utc> {
89 self.common.created
90 }
91}
92
93impl AttackObject for Technique {
94 fn name(&self) -> &str {
95 &self.name
96 }
97
98 fn description(&self) -> Option<&str> {
99 self.description.as_deref()
100 }
101
102 fn revoked(&self) -> bool {
103 self.common.revoked.unwrap_or(false)
104 }
105
106 fn deprecated(&self) -> bool {
107 self.common.custom_properties.get("x_mitre_deprecated").and_then(|v| v.as_bool()).unwrap_or(false)
108 }
109}