From: Victor Julien Date: Fri, 9 Mar 2018 09:27:13 +0000 (+0100) Subject: smb2: parse and log timestamps in CREATE X-Git-Tag: suricata-4.1.0-beta1~86 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0e05ef7369e3f7204cbac728e2670abea607f9ca;p=thirdparty%2Fsuricata.git smb2: parse and log timestamps in CREATE --- diff --git a/rust/src/smb/log.rs b/rust/src/smb/log.rs index 774e4a98e2..d6fd44920e 100644 --- a/rust/src/smb/log.rs +++ b/rust/src/smb/log.rs @@ -193,6 +193,13 @@ fn smb_common_header(state: &SMBState, tx: &SMBTransaction) -> Json } else { js.set_string("access", "normal"); } + + // field names inspired by Bro + js.set_integer("created", x.create_ts as u64); + js.set_integer("accessed", x.last_access_ts as u64); + js.set_integer("modified", x.last_write_ts as u64); + js.set_integer("changed", x.last_change_ts as u64); + js.set_integer("size", x.size); }, Some(SMBTransactionTypeData::NEGOTIATE(ref x)) => { if x.smb_ver == 1 { diff --git a/rust/src/smb/smb.rs b/rust/src/smb/smb.rs index 2dab57447e..64883785ac 100644 --- a/rust/src/smb/smb.rs +++ b/rust/src/smb/smb.rs @@ -304,6 +304,32 @@ impl SMBVerCmdStat { } } +/// "The FILETIME structure is a 64-bit value that represents the number of +/// 100-nanosecond intervals that have elapsed since January 1, 1601, +/// Coordinated Universal Time (UTC)." +#[derive(Eq, PartialEq, Debug, Clone)] +pub struct SMBFiletime { + ts: u64, +} + +impl SMBFiletime { + pub fn new(raw: u64) -> SMBFiletime { + SMBFiletime { + ts: raw, + } + } + + /// inspired by Bro, convert FILETIME to secs since unix epoch + pub fn as_unix(&self) -> u32 { + if self.ts > 116_444_736_000_000_000_u64 { + let ts = self.ts / 10000000 - 11644473600; + ts as u32 + } else { + 0 + } + } +} + #[derive(Debug)] pub enum SMBTransactionTypeData { FILE(SMBTransactionFile), @@ -320,6 +346,13 @@ pub struct SMBTransactionCreate { pub delete_on_close: bool, pub directory: bool, pub filename: Vec, + + pub create_ts: u32, + pub last_access_ts: u32, + pub last_write_ts: u32, + pub last_change_ts: u32, + + pub size: u64, } impl SMBTransactionCreate { @@ -329,6 +362,11 @@ impl SMBTransactionCreate { delete_on_close: del, directory: dir, filename: filename, + create_ts: 0, + last_access_ts: 0, + last_write_ts: 0, + last_change_ts: 0, + size: 0, } } } diff --git a/rust/src/smb/smb2.rs b/rust/src/smb/smb2.rs index bd068f3469..f1462c79ea 100644 --- a/rust/src/smb/smb2.rs +++ b/rust/src/smb/smb2.rs @@ -597,22 +597,37 @@ pub fn smb2_response_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>) SCLogDebug!("SMBv2: Create response => {:?}", cr); let guid_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_FILENAME); - match state.ssn2vec_map.remove(&guid_key) { - Some(mut p) => { - p.retain(|&i|i != 0x00); - state.guid2name_map.insert(cr.guid.to_vec(), p); - }, - _ => { - SCLogDebug!("SMBv2 response: GUID NOT FOUND"); - }, + if let Some(mut p) = state.ssn2vec_map.remove(&guid_key) { + p.retain(|&i|i != 0x00); + state.guid2name_map.insert(cr.guid.to_vec(), p); + } else { + SCLogDebug!("SMBv2 response: GUID NOT FOUND"); + } + + let tx_hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); + if let Some(tx) = state.get_generic_tx(2, r.command, &tx_hdr) { + SCLogDebug!("tx {} with {}/{} marked as done", + tx.id, r.command, &smb2_command_string(r.command)); + tx.set_status(r.nt_status, false); + tx.response_done = true; + + if let Some(SMBTransactionTypeData::CREATE(ref mut tdn)) = tx.type_data { + tdn.create_ts = cr.create_ts.as_unix(); + tdn.last_access_ts = cr.last_access_ts.as_unix(); + tdn.last_write_ts = cr.last_write_ts.as_unix(); + tdn.last_change_ts = cr.last_change_ts.as_unix(); + tdn.size = cr.size; + } } } _ => { events.push(SMBEvent::MalformedData); }, } + true + } else { + false } - false }, SMB2_COMMAND_TREE_DISCONNECT => { // normally removed when processing request, diff --git a/rust/src/smb/smb2_records.rs b/rust/src/smb/smb2_records.rs index c750e3939b..2283b2a907 100644 --- a/rust/src/smb/smb2_records.rs +++ b/rust/src/smb/smb2_records.rs @@ -16,6 +16,7 @@ */ use nom::{rest, le_u8, le_u16, le_u32, le_u64, AsBytes}; +use smb::smb::*; #[derive(Debug,PartialEq)] pub struct Smb2SecBlobRecord<'a> { @@ -339,15 +340,36 @@ named!(pub parse_smb2_response_read, #[derive(Debug,PartialEq)] pub struct Smb2CreateResponseRecord<'a> { pub guid: &'a[u8], + pub create_ts: SMBFiletime, + pub last_access_ts: SMBFiletime, + pub last_write_ts: SMBFiletime, + pub last_change_ts: SMBFiletime, + pub size: u64, } named!(pub parse_smb2_response_create, do_parse!( - skip1: take!(64) + ssize: le_u16 + >> oplock: le_u8 + >> resp_flags: le_u8 + >> create_action: le_u32 + >> create_ts: le_u64 + >> last_access_ts: le_u64 + >> last_write_ts: le_u64 + >> last_change_ts: le_u64 + >> alloc_size: le_u64 + >> eof: le_u64 + >> attrs: le_u32 + >> padding: take!(4) >> guid: take!(16) >> skip2: take!(8) >> (Smb2CreateResponseRecord { guid : guid, + create_ts: SMBFiletime::new(create_ts), + last_access_ts: SMBFiletime::new(last_access_ts), + last_write_ts: SMBFiletime::new(last_write_ts), + last_change_ts: SMBFiletime::new(last_change_ts), + size: eof, }) ));