assemblyline_models/datastore/
badlist.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use serde_with::{DeserializeFromStr, SerializeDisplay};
4use struct_metadata::Described;
5use crate::types::classification::unrestricted_classification_string;
6use crate::types::{ClassificationString, ExpandingClassification, SSDeepHash, Sha1, Sha256, UpperString, MD5};
7use crate::{ElasticMeta, Readable};
8
9// Classification = forge.get_classification()
10#[derive(SerializeDisplay, DeserializeFromStr, Clone, Copy, strum::Display, strum::EnumString, Described, Debug, PartialEq, Eq)]
11#[metadata_type(ElasticMeta)]
12#[strum(serialize_all = "lowercase")]
13pub enum BadhashTypes {
14    File,
15    Tag,
16}
17
18#[derive(SerializeDisplay, DeserializeFromStr, Clone, Copy, strum::Display, strum::EnumString, Described, Debug, PartialEq, Eq)]
19#[metadata_type(ElasticMeta)]
20#[strum(serialize_all = "lowercase")]
21pub enum SourceTypes {
22    User,
23    External,
24}
25
26/// Attribution Tag Model
27#[derive(Debug, Serialize, Deserialize, Clone, Described, Default, PartialEq, Eq)]
28#[serde(default)]
29#[metadata_type(ElasticMeta)]
30#[metadata(index=true, store=false)]
31pub struct Attribution {
32    /// Attribution Actor
33    #[metadata(copyto="__text__")]
34    pub actor: Option<Vec<UpperString>>,
35    /// Attribution Campaign
36    #[metadata(copyto="__text__")]
37    pub campaign: Option<Vec<UpperString>>,
38    /// Attribution Category
39    #[metadata(copyto="__text__")]
40    pub category: Option<Vec<UpperString>>,
41    /// Attribution Exploit
42    #[metadata(copyto="__text__")]
43    pub exploit: Option<Vec<UpperString>>,
44    /// Attribution Implant
45    #[metadata(copyto="__text__")]
46    pub implant: Option<Vec<UpperString>>,
47    /// Attribution Family
48    #[metadata(copyto="__text__")]
49    pub family: Option<Vec<UpperString>>,
50    /// Attribution Network
51    #[metadata(copyto="__text__")]
52    pub network: Option<Vec<UpperString>>,
53}
54
55impl Attribution {
56    pub fn update(&mut self, mut other: Attribution) {
57        macro_rules! update_field {($self: ident, $other: ident, $key: ident) => {
58            match &mut $self.$key {
59                Some(data) => {
60                    data.append(&mut $other.$key.take().unwrap_or_default());
61                    data.sort_unstable();
62                    data.dedup();                    
63                },
64                None => {
65                    $self.$key = $other.$key;
66                }
67            }; 
68        };}
69
70        update_field!(self, other, actor);
71        update_field!(self, other, campaign);
72        update_field!(self, other, category);
73        update_field!(self, other, exploit);
74        update_field!(self, other, implant);
75        update_field!(self, other, family);
76        update_field!(self, other, network);
77    }
78}
79
80/// Hashes of a badlisted file
81#[derive(Debug, Serialize, Deserialize, Clone, Described, Default, PartialEq, Eq)]
82#[serde(default)]
83#[metadata_type(ElasticMeta)]
84#[metadata(index=true, store=true)]
85pub struct Hashes {
86    /// MD5
87    #[metadata(copyto="__text__")]
88    pub md5: Option<MD5>,
89    /// SHA1
90    #[metadata(copyto="__text__")]
91    pub sha1: Option<Sha1>,
92    /// SHA256
93    #[metadata(copyto="__text__")]
94    pub sha256: Option<Sha256>,
95    /// SSDEEP
96    #[metadata(copyto="__text__")]
97    pub ssdeep: Option<SSDeepHash>,
98    /// TLSH
99    #[metadata(copyto="__text__")]
100    pub tlsh: Option<String>,
101}
102
103impl Hashes {
104    pub fn update(&mut self, other: Hashes) {
105        macro_rules! update_field {($self: ident, $other: ident, $key: ident) => {
106            $self.$key = $other.$key.or($self.$key.take())
107        };}
108
109        update_field!(self, other, md5);
110        update_field!(self, other, sha1);
111        update_field!(self, other, sha256);
112        update_field!(self, other, ssdeep);
113        update_field!(self, other, tlsh);
114    }
115
116    pub fn label_hash(&self) -> Option<String> {
117        macro_rules! read_field {($self: ident, $key: ident) => {
118            if let Some(val) = &($self.$key) {
119                return Some(val.to_string());
120            }
121        };}
122
123        read_field!(self, sha256);
124        read_field!(self, sha1);
125        read_field!(self, md5);
126        read_field!(self, tlsh);
127        read_field!(self, ssdeep);
128        None
129    }
130}
131
132/// File Details
133#[derive(Debug, Serialize, Deserialize, Clone, Described, Default, PartialEq, Eq)]
134#[serde(default)]
135#[metadata_type(ElasticMeta)]
136#[metadata(index=true, store=false)]
137pub struct File {
138    /// List of names seen for that file
139    #[metadata(store=true, copyto="__text__")]
140    pub name: Vec<String>,
141    /// Size of the file in bytes
142    pub size: Option<i64>,
143    /// Type of file as identified by Assemblyline
144    #[serde(rename="type")]
145    pub file_type: Option<String>,
146}
147
148
149/// Badlist source
150#[derive(Debug, Serialize, Deserialize, Clone, Described, PartialEq, Eq)]
151#[metadata_type(ElasticMeta)]
152#[metadata(index=true, store=false)]
153pub struct Source {
154    /// Classification of the source
155    #[serde(default="unrestricted_classification_string")]
156    pub classification: ClassificationString,
157    /// Name of the source
158    #[metadata(store=true)]
159    pub name: String,
160    /// Reason for why file was badlisted
161    pub reason: Vec<String>,
162    /// Type of badlisting source
163    #[serde(rename="type")]
164    pub source_type: SourceTypes,
165}
166
167/// Tag associated to file
168#[derive(Debug, Serialize, Deserialize, Clone, Described, PartialEq, Eq)]
169#[metadata_type(ElasticMeta)]
170#[metadata(index=true, store=true)]
171pub struct Tag {
172    /// Tag type
173    #[serde(rename="type")]    
174    pub tag_type: String,
175    /// Tag value
176    #[metadata(copyto="__text__")]
177    pub value: String,
178}
179
180
181/// Badlist Model
182#[derive(Debug, Serialize, Deserialize, Clone, Described, PartialEq, Eq)]
183#[metadata_type(ElasticMeta)]
184#[metadata(index=true, store=true)]
185pub struct Badlist {
186    /// Date when the badlisted hash was added
187    #[serde(default="chrono::Utc::now")]
188    pub added: DateTime<Utc>,
189    /// Attribution related to the bad hash
190    #[serde(default)]
191    pub attribution: Option<Attribution>,
192    /// Computed max classification for the bad hash
193    #[serde(flatten)]
194    pub classification: ExpandingClassification,
195    /// Is bad hash enabled or not?
196    #[serde(default="default_true")]
197    pub enabled: bool,
198    /// When does this item expire from the list?
199    #[serde(default)]
200    pub expiry_ts: Option<DateTime<Utc>>,
201    /// List of hashes related to the bad hash
202    #[serde(default)]
203    pub hashes: Hashes,
204    /// Information about the file
205    #[serde(default)]
206    pub file: Option<File>,
207    /// List of reasons why hash is badlisted
208    pub sources: Vec<Source>,
209    /// Information about the tag
210    #[serde(default)]
211    pub tag: Option<Tag>,
212    /// Type of bad hash
213    #[serde(rename="type")]
214    pub hash_type: BadhashTypes,
215    /// Last date when sources were added to the bad hash
216    #[serde(default="chrono::Utc::now")]
217    pub updated: DateTime<Utc>,
218}
219
220fn default_true() -> bool { true }
221
222impl Readable for Badlist {
223    fn set_from_archive(&mut self, _from_archive: bool) {}
224}
225
226// if __name__ == "__main__":
227//     from pprint import pprint
228//     from assemblyline.odm.randomizer import random_model_obj
229//     pprint(random_model_obj(Badlist, as_json=True))