Skip to content

Commit

Permalink
feat: add time format conversion process
Browse files Browse the repository at this point in the history
  • Loading branch information
fukusuket committed Dec 1, 2024
1 parent 8412beb commit e311ead
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 23 deletions.
2 changes: 1 addition & 1 deletion src/detections/configs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1133,7 +1133,7 @@ pub struct DefaultProfileOption {
pub profile: Option<String>,
}

#[derive(Args, Clone, Debug)]
#[derive(Args, Clone, Debug, Default)]
pub struct TimeFormatOptions {
/// Output timestamp in European time format (ex: 22-02-2022 22:00:00.123 +02:00)
#[arg(help_heading = Some("Time Format"), long = "European-time", display_order = 50)]
Expand Down
6 changes: 1 addition & 5 deletions src/detections/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,7 @@ pub fn get_serde_number_to_string(
) -> Option<CompactString> {
if value.is_string() {
let val_str = value.as_str().unwrap_or("");
if val_str.ends_with(',') {
Some(CompactString::from(val_str))
} else {
Option::Some(CompactString::from(val_str))
}
Some(CompactString::from(val_str))
} else if value.is_object() && search_flag {
let map: Map<String, Value> = Map::new();
let val_obj = value.as_object().unwrap_or(&map);
Expand Down
43 changes: 28 additions & 15 deletions src/timeline/extract_base64.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use crate::detections::configs::TimeFormatOptions;
use crate::detections::detection::EvtxRecordInfo;
use crate::detections::utils::{get_writable_color, write_color_buffer};
use crate::detections::message::get_event_time;
use crate::detections::utils::{format_time, get_writable_color, write_color_buffer};
use base64::prelude::{BASE64_STANDARD, BASE64_STANDARD_NO_PAD};
use base64::Engine;
use chrono::{TimeZone, Utc};
use comfy_table::modifiers::UTF8_ROUND_CORNERS;
use comfy_table::presets::UTF8_FULL;
use comfy_table::{Cell, CellAlignment, ContentArrangement, Table};
Expand All @@ -28,16 +31,15 @@ struct EvtxInfo {
}

impl EvtxInfo {
fn new(val: &Value, file_name: String, event: Event) -> Self {
fn new(val: &Value, file_name: String, event: Event, ts_fmt_opt: &TimeFormatOptions) -> Self {
let default_time = Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap();
let ts = get_event_time(val, false).unwrap_or(default_time);
let ts = format_time(&ts, false, ts_fmt_opt);
let d = &val["Event"]["System"];
let ts = d["TimeCreated_attributes"]["SystemTime"]
.as_str()
.unwrap_or_default()
.to_string();
let computer = d["Computer"].as_str().unwrap_or_default().to_string();
let rec_id = d["EventRecordID"].as_i64().unwrap().to_string();
Self {
ts,
ts: ts.to_string(),
computer,
rec_id,
file_name,
Expand Down Expand Up @@ -265,8 +267,9 @@ fn create_base64_extracted_record(
possible_base64: &str,
data: &Value,
event: Event,
ts_fmt_opt: &TimeFormatOptions,
) -> Vec<Vec<String>> {
let evtx = EvtxInfo::new(data, file.to_string_lossy().to_string(), event);
let evtx = EvtxInfo::new(data, file.to_string_lossy().to_string(), event, ts_fmt_opt);
let mut records = Vec::new();
for token in tokenize(possible_base64) {
if is_base64(token) {
Expand All @@ -284,7 +287,7 @@ fn create_base64_extracted_record(
}
let original = possible_base64.replace(b64.base64_str().as_str(), "<Base64String>");
let row = vec![
evtx.ts.clone(),
evtx.ts.to_string(),
evtx.computer.clone(),
b64.base64_str(),
b64.decoded_str(),
Expand All @@ -304,22 +307,25 @@ fn create_base64_extracted_record(
records
}

fn process_record(data: &Value, file: &Path) -> Vec<Vec<String>> {
fn process_record(data: &Value, file: &Path, opt: &TimeFormatOptions) -> Vec<Vec<String>> {
let mut records = Vec::new();
let payloads = extract_payload(data);
for (payload, event) in payloads {
let possible_base64 = payload.as_str().unwrap_or_default();
let extracted = create_base64_extracted_record(file, possible_base64, data, event);
let extracted = create_base64_extracted_record(file, possible_base64, data, event, opt);
records.extend(extracted);
}
records
}

pub fn process_evtx_record_infos(records: &[EvtxRecordInfo]) -> Vec<Vec<String>> {
pub fn process_evtx_record_infos(
records: &[EvtxRecordInfo],
opt: &TimeFormatOptions,
) -> Vec<Vec<String>> {
let mut all_records = Vec::new();
for record in records {
let file = PathBuf::from(&record.evtx_filepath);
let extracted = process_record(&record.record, &file);
let extracted = process_record(&record.record, &file, opt);
all_records.extend(extracted);
}
all_records
Expand Down Expand Up @@ -445,7 +451,7 @@ mod tests {
});

let expected = vec![vec![
"2021-12-23T00:00:00.000Z".to_string(),
"2021-12-23T00:00:00Z".to_string(),
"HAYABUSA-DESKTOP".to_string(),
"dGVzdCBjb21tYW5k".to_string(),
"test command".to_string(),
Expand All @@ -462,7 +468,14 @@ mod tests {
"test.evtx".to_string(),
]];

let result = process_record(&data, Path::new("test.evtx"));
let result = process_record(
&data,
Path::new("test.evtx"),
&TimeFormatOptions {
iso_8601: true,
..Default::default()
},
);
assert_eq!(result, expected);
}
}
6 changes: 4 additions & 2 deletions src/timeline/timelines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,10 @@ impl Timeline {
stored_static,
);
} else if stored_static.extract_base64_flag {
let records = process_evtx_record_infos(records);
self.extracted_base64_records.extend(records);
if let Action::ExtractBase64(opt) = &stored_static.config.action.as_ref().unwrap() {
let records = process_evtx_record_infos(records, &opt.time_format_options);
self.extracted_base64_records.extend(records);
}
}
}

Expand Down

0 comments on commit e311ead

Please sign in to comment.