Skip to content

Commit

Permalink
Merge branch 'main' into feature/deb
Browse files Browse the repository at this point in the history
  • Loading branch information
Bitbee0 committed Feb 6, 2024
2 parents bd58570 + b9cf06c commit c0db118
Show file tree
Hide file tree
Showing 13 changed files with 193 additions and 32 deletions.
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dfir-toolkit"
version = "0.9.0"
version = "0.10.0"
edition = "2021"
authors = ["Jan Starke <jan.starke@posteo.de>", "Deborah Mahn <deborah.mahn@dfir-dd.de>"]
description = "CLI tools for digital forensics and incident response"
Expand Down Expand Up @@ -113,6 +113,7 @@ log = {version = "0.4", features = [ "release_max_level_info" ]}
serde = { version = "1.0", features = ["derive"] }
simplelog = "0.12"
winstructs = "0.3.0"
lazy_static = "1.4"
regex = {version = "1", optional=true}

clap-markdown = "0.1.3"
Expand Down
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,39 @@ mactime2 --autocomplete bash | sudo tee /etc/bash_completion.d/mactime2

would install a autocompletion script in `/etc/bash_completion.d/mactime2`.

# Usage

## Configuring the global timestamp format

Per default, the DFIR toolkit uses an RFC3339-compliant data format. If you want to, you can change the data format
being used by setting the `DFIR_DATE` environment variable. Let's look at an example:

```shell
$ mac2time2 -b tests/data/mactime2/sample.bodyfile -d | head
1970-01-01T00:00:00+00:00,0,macb,V/V---------,0,0,62447617,"/$OrphanFiles"
2022-04-18T10:28:59+00:00,4096,m...,d/drwxr-xr-x,0,0,42729473,"/proc"
2022-04-18T10:28:59+00:00,4096,m...,d/drwxr-xr-x,0,0,36306945,"/sys"
2022-04-21T00:57:50+00:00,7,m...,l/lrwxrwxrwx,0,0,12,"/bin -> usr/bin"
2022-04-21T00:57:50+00:00,7,m...,l/lrwxrwxrwx,0,0,13,"/lib -> usr/lib"
2022-04-21T00:57:50+00:00,9,m...,l/lrwxrwxrwx,0,0,14,"/lib32 -> usr/lib32"
2022-04-21T00:57:50+00:00,9,m...,l/lrwxrwxrwx,0,0,15,"/lib64 -> usr/lib64"
2022-04-21T00:57:50+00:00,10,m...,l/lrwxrwxrwx,0,0,16,"/libx32 -> usr/libx32"
2022-04-21T00:57:50+00:00,8,m...,l/lrwxrwxrwx,0,0,17,"/sbin -> usr/sbin"
2022-04-21T00:57:51+00:00,4096,m...,d/drwxr-xr-x,0,0,38010881,"/srv"
```

```shell
$ DFIR_DATE="%F %T (%Z)" mac2time2 -b tests/data/mactime2/sample.bodyfile -d | head
1970-01-01 00:00:00 (UTC),0,macb,V/V---------,0,0,62447617,"/$OrphanFiles"
2022-04-18 10:28:59 (UTC),4096,m...,d/drwxr-xr-x,0,0,42729473,"/proc"
2022-04-18 10:28:59 (UTC),4096,m...,d/drwxr-xr-x,0,0,36306945,"/sys"
2022-04-21 00:57:50 (UTC),7,m...,l/lrwxrwxrwx,0,0,12,"/bin -> usr/bin"
2022-04-21 00:57:50 (UTC),7,m...,l/lrwxrwxrwx,0,0,13,"/lib -> usr/lib"
2022-04-21 00:57:50 (UTC),9,m...,l/lrwxrwxrwx,0,0,14,"/lib32 -> usr/lib32"
2022-04-21 00:57:50 (UTC),9,m...,l/lrwxrwxrwx,0,0,15,"/lib64 -> usr/lib64"
2022-04-21 00:57:50 (UTC),10,m...,l/lrwxrwxrwx,0,0,16,"/libx32 -> usr/libx32"
2022-04-21 00:57:50 (UTC),8,m...,l/lrwxrwxrwx,0,0,17,"/sbin -> usr/sbin"
2022-04-21 00:57:51 (UTC),4096,m...,d/drwxr-xr-x,0,0,38010881,"/srv"
```

The value of `DFIR_DATE` can be any format string which can also be used in `DateTime::strftime` (<https://docs.rs/chrono/latest/chrono/format/strftime/index.html>)
42 changes: 40 additions & 2 deletions scripts/update-md.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ cat >README.md <<'EOF'
- [Tools](#tools)
- [x] [`cleanhive`](https://github.com/dfir-dd/dfir-toolkit/blob/main/doc/cleanhive.md)
- [x] [`evtx2bodyfile`](https://github.com/dfir-dd/dfir-toolkit/blob/main/doc/evtx2bodyfile.md)
- [x] [`evtxanalyze`](https://github.com/dfir-dd/dfir-toolkit/blob/main/doc/avtxanalyze.md)
- [x] [`evtxanalyze`](https://github.com/dfir-dd/dfir-toolkit/blob/main/doc/evtxanalyze.md)
- [x] [`evtxscan`](https://github.com/dfir-dd/dfir-toolkit/blob/main/doc/evtxscan.md)
- [x] [`evtxcat`](https://github.com/dfir-dd/dfir-toolkit/blob/main/doc/evtxcat.md)
- [x] [`evtxls`](https://github.com/dfir-dd/dfir-toolkit/blob/main/doc/evtxls.md)
Expand Down Expand Up @@ -58,8 +58,46 @@ mactime2 --autocomplete bash | sudo tee /etc/bash_completion.d/mactime2
would install a autocompletion script in `/etc/bash_completion.d/mactime2`.
# Usage
## Configuring the global timestamp format
Per default, the DFIR toolkit uses an RFC3339-compliant data format. If you want to, you can change the data format
being used by setting the `DFIR_DATE` environment variable. Let's look at an example:
```shell
$ mac2time2 -b tests/data/mactime2/sample.bodyfile -d | head
1970-01-01T00:00:00+00:00,0,macb,V/V---------,0,0,62447617,"/$OrphanFiles"
2022-04-18T10:28:59+00:00,4096,m...,d/drwxr-xr-x,0,0,42729473,"/proc"
2022-04-18T10:28:59+00:00,4096,m...,d/drwxr-xr-x,0,0,36306945,"/sys"
2022-04-21T00:57:50+00:00,7,m...,l/lrwxrwxrwx,0,0,12,"/bin -> usr/bin"
2022-04-21T00:57:50+00:00,7,m...,l/lrwxrwxrwx,0,0,13,"/lib -> usr/lib"
2022-04-21T00:57:50+00:00,9,m...,l/lrwxrwxrwx,0,0,14,"/lib32 -> usr/lib32"
2022-04-21T00:57:50+00:00,9,m...,l/lrwxrwxrwx,0,0,15,"/lib64 -> usr/lib64"
2022-04-21T00:57:50+00:00,10,m...,l/lrwxrwxrwx,0,0,16,"/libx32 -> usr/libx32"
2022-04-21T00:57:50+00:00,8,m...,l/lrwxrwxrwx,0,0,17,"/sbin -> usr/sbin"
2022-04-21T00:57:51+00:00,4096,m...,d/drwxr-xr-x,0,0,38010881,"/srv"
```
```shell
$ DFIR_DATE="%F %T (%Z)" mac2time2 -b tests/data/mactime2/sample.bodyfile -d | head
1970-01-01 00:00:00 (UTC),0,macb,V/V---------,0,0,62447617,"/$OrphanFiles"
2022-04-18 10:28:59 (UTC),4096,m...,d/drwxr-xr-x,0,0,42729473,"/proc"
2022-04-18 10:28:59 (UTC),4096,m...,d/drwxr-xr-x,0,0,36306945,"/sys"
2022-04-21 00:57:50 (UTC),7,m...,l/lrwxrwxrwx,0,0,12,"/bin -> usr/bin"
2022-04-21 00:57:50 (UTC),7,m...,l/lrwxrwxrwx,0,0,13,"/lib -> usr/lib"
2022-04-21 00:57:50 (UTC),9,m...,l/lrwxrwxrwx,0,0,14,"/lib32 -> usr/lib32"
2022-04-21 00:57:50 (UTC),9,m...,l/lrwxrwxrwx,0,0,15,"/lib64 -> usr/lib64"
2022-04-21 00:57:50 (UTC),10,m...,l/lrwxrwxrwx,0,0,16,"/libx32 -> usr/libx32"
2022-04-21 00:57:50 (UTC),8,m...,l/lrwxrwxrwx,0,0,17,"/sbin -> usr/sbin"
2022-04-21 00:57:51 (UTC),4096,m...,d/drwxr-xr-x,0,0,38010881,"/srv"
```
The value of `DFIR_DATE` can be any format string which can also be used in `DateTime::strftime` (<https://docs.rs/chrono/latest/chrono/format/strftime/index.html>)
EOF

for B in $(cd src/bin; echo *); do
cargo run --bin $B -- --markdown-help >>doc/$B.md
done
done
2 changes: 1 addition & 1 deletion src/bin/evtxanalyze/pstree/unique_pid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl Ord for UniquePid {
}
}

#[allow(clippy::incorrect_partial_ord_impl_on_ord_type)]
#[allow(clippy::non_canonical_partial_ord_impl)]
impl PartialOrd for UniquePid {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
if self.pid != other.pid {
Expand Down
1 change: 0 additions & 1 deletion src/bin/evtxanalyze/sessions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ mod active_directory_domain_name;
pub use session::*;
pub use session_store::*;
pub use session_event::*;
pub use session_event_templates::*;
pub use session_event_error::*;
pub use session_as_json::*;
pub use session_as_csv::*;
Expand Down
2 changes: 1 addition & 1 deletion src/bin/evtxcat/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use record_list_formatter::RecordListFormatter;
fn main() -> Result<()> {
let cli = Cli::parse_cli();

let path = PathBuf::try_from(&cli.evtx_file)?;
let path = PathBuf::from(&cli.evtx_file);

let parser = EvtxParser::from_path(path)?;

Expand Down
18 changes: 5 additions & 13 deletions src/bin/evtxls/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use evtx::{EvtxParser, ParserSettings, SerializedEvtxRecord};
use highlighted_string::HighlightedStringBuilder;
use serde_json::Value;

use dfir_toolkit::common::FancyParser;
use dfir_toolkit::common::{FancyParser, FormattableDatetime};

use crate::system_field::FilterBySystemField;

Expand All @@ -37,7 +37,7 @@ impl EvtxLs {
let mut records = Vec::new();

for f_name in self.cli.evtx_files.iter() {
let path = PathBuf::try_from(&f_name)?;
let path = PathBuf::from(&f_name);

let settings = ParserSettings::default().num_threads(0);
let parser = EvtxParser::from_path(path)?.with_configuration(settings);
Expand Down Expand Up @@ -145,18 +145,10 @@ impl EvtxLs {
.unwrap_or_else(|| "".to_owned())
.replace("\\u001b", "\u{001b}");

let output = match self.cli.delimiter {
None => format!(
"{} {system_fields}{event_data}",
record.timestamp.format("%FT%T%.3f")
),
Some(d) => format!(
"{}{d}{system_fields}{event_data}",
record.timestamp.to_rfc3339()
),
}
.normal();
let timestamp = FormattableDatetime::from(&record.timestamp);
let delimiter = self.cli.delimiter.unwrap_or(' ');

let output=format!("{timestamp}{delimiter}{system_fields}{event_data}").normal();
println!("{output}");

Ok(())
Expand Down
2 changes: 1 addition & 1 deletion src/bin/evtxscan/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ fn main() -> Result<()> {
let mut record_ids: Vec<EventId> = Vec::new();
let mut records: HashMap<EventId, SerializedEvtxRecord<serde_json::Value>> = HashMap::new();

let path = PathBuf::try_from(&cli.evtx_file)?;
let path = PathBuf::from(&cli.evtx_file);

let mut parser = EvtxParser::from_path(path)?;
for record in parser.records_json_value() {
Expand Down
4 changes: 2 additions & 2 deletions src/bin/regdump/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::{bail, Result};

use dfir_toolkit::common::bodyfile::Bodyfile3Line;
use dfir_toolkit::common::FancyParser;
use dfir_toolkit::common::{FancyParser, FormattableDatetime};
use nt_hive2::*;
use simplelog::{Config, SimpleLogger};
use std::fs::File;
Expand Down Expand Up @@ -80,7 +80,7 @@ where
if cli.hide_timestamps {
println!("\n[{}]", &current_path);
} else {
println!("\n[{}]; {}", &current_path, keynode.timestamp());
println!("\n[{}]; {}", &current_path, FormattableDatetime::from(keynode.timestamp()));
}

print_values(keynode);
Expand Down
60 changes: 51 additions & 9 deletions src/common/forensics_timestamp.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,35 @@
use std::fmt::Display;

use chrono::{NaiveDateTime, LocalResult};
use chrono_tz::Tz;
use chrono::format::StrftimeItems;
use chrono::offset::TimeZone;
use chrono::{DateTime, FixedOffset, LocalResult, NaiveDateTime};
use chrono_tz::Tz;
use lazy_static::lazy_static;

lazy_static! {
static ref TIMESTAMP_FORMAT: Option<String> = {
if let Ok(format) = std::env::var("DFIR_DATE") {
if StrftimeItems::new(&format).any(|i| i == chrono::format::Item::Error) {
eprintln!();
eprintln!("ERROR: invalid date format: '{format}' stored in environment variable $DFIR_DATE!");
eprintln!();
eprintln!("Please take a look at");
eprintln!();
eprintln!(" <https://docs.rs/chrono/latest/chrono/format/strftime/index.html>");
eprintln!();
eprintln!("to see which format strings are accepted.");
eprintln!();
std::process::exit(-1);
} else {
Some(format)
}
} else {
None
}
};
static ref ZERO: DateTime<FixedOffset> =
DateTime::<FixedOffset>::parse_from_rfc3339("0000-00-00T00:00:00+00:00").unwrap();
}

pub struct ForensicsTimestamp {
unix_ts: i64,
Expand All @@ -11,18 +38,33 @@ pub struct ForensicsTimestamp {
}

impl ForensicsTimestamp {

pub fn new(unix_ts: i64, src_zone: Tz, dst_zone: Tz) -> Self {
Self {
unix_ts, src_zone, dst_zone
unix_ts,
src_zone,
dst_zone,
}
}

fn display_datetime<TZ: TimeZone>(
dt: &DateTime<TZ>,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result
where
<TZ as TimeZone>::Offset: std::fmt::Display,
{
match &*TIMESTAMP_FORMAT {
Some(format) => dt.format(format).fmt(f),
None => dt.to_rfc3339().fmt(f),
}
}
}

impl Display for ForensicsTimestamp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.unix_ts >= 0 {
let src_timestamp = match self.src_zone
let src_timestamp = match self
.src_zone
.from_local_datetime(&NaiveDateTime::from_timestamp_opt(self.unix_ts, 0).unwrap())
{
LocalResult::None => {
Expand All @@ -31,10 +73,10 @@ impl Display for ForensicsTimestamp {
LocalResult::Single(t) => t,
LocalResult::Ambiguous(t1, _t2) => t1,
};
let dst_timestamp = src_timestamp.with_timezone(&self.dst_zone);
write!(f, "{}", dst_timestamp.to_rfc3339())

Self::display_datetime(&src_timestamp.with_timezone(&self.dst_zone), f)
} else {
write!(f, "0000-00-00T00:00:00+00:00")
Self::display_datetime(&*ZERO, f)
}
}
}
}
50 changes: 50 additions & 0 deletions src/common/formattable_datetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use std::fmt::Display;

use chrono::{DateTime, FixedOffset, TimeZone};
use lazy_static::lazy_static;

lazy_static! {
static ref TIMESTAMP_FORMAT: Option<String> = std::env::var("DFIR_DATE").ok();
static ref ZERO: DateTime<FixedOffset> =
DateTime::<FixedOffset>::parse_from_rfc3339("0000-00-00T00:00:00+00:00").unwrap();
}

/// Wrapper around [`DateTime`] to allow customization of the timestamp output
/// using the `DFIR_DATE` environment variable
///
pub struct FormattableDatetime<TZ: TimeZone>(DateTime<TZ>)
where
<TZ as TimeZone>::Offset: std::fmt::Display;

impl<TZ> From<DateTime<TZ>> for FormattableDatetime<TZ>
where
TZ: TimeZone,
<TZ as TimeZone>::Offset: std::fmt::Display,
{
fn from(value: DateTime<TZ>) -> Self {
Self(value)
}
}

impl<TZ> From<&DateTime<TZ>> for FormattableDatetime<TZ>
where
TZ: TimeZone,
<TZ as TimeZone>::Offset: std::fmt::Display,
{
fn from(value: &DateTime<TZ>) -> Self {
Self(value.clone())
}
}

impl<TZ> Display for FormattableDatetime<TZ>
where
TZ: TimeZone,
<TZ as TimeZone>::Offset: std::fmt::Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &*TIMESTAMP_FORMAT {
Some(format) => self.0.format(format).fmt(f),
None => self.0.to_rfc3339().fmt(f),
}
}
}
2 changes: 2 additions & 0 deletions src/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ mod parse_cli;
mod rfc3339_datetime;
mod tzargument;
mod file_input;
mod formattable_datetime;

pub use forensics_timestamp::*;
pub use parse_cli::*;
pub use rfc3339_datetime::*;
pub use tzargument::*;
pub use formattable_datetime::*;

pub use file_input::*;

0 comments on commit c0db118

Please sign in to comment.