diff --git a/rust/src/smb/log.rs b/rust/src/smb/log.rs index 0a277566be..e3d9aa0cee 100644 --- a/rust/src/smb/log.rs +++ b/rust/src/smb/log.rs @@ -329,6 +329,18 @@ fn smb_common_header(state: &SMBState, tx: &SMBTransaction) -> Json let gs = fuid_to_string(&x.fuid); js.set_string("fuid", &gs); }, + Some(SMBTransactionTypeData::RENAME(ref x)) => { + let jsd = Json::object(); + jsd.set_string("class", "FILE_INFO"); + jsd.set_string("info_level", "SMB2_FILE_RENAME_INFO"); + let file_name = String::from_utf8_lossy(&x.oldname); + jsd.set_string("from", &file_name); + let file_name = String::from_utf8_lossy(&x.newname); + jsd.set_string("to", &file_name); + js.set("set_info", jsd); + let gs = fuid_to_string(&x.fuid); + js.set_string("fuid", &gs); + }, Some(SMBTransactionTypeData::DCERPC(ref x)) => { let jsd = Json::object(); jsd.set_string("request", &dcerpc_type_string(x.req_cmd)); diff --git a/rust/src/smb/smb.rs b/rust/src/smb/smb.rs index 9fcf4ba808..5a57188c0b 100644 --- a/rust/src/smb/smb.rs +++ b/rust/src/smb/smb.rs @@ -363,6 +363,40 @@ pub enum SMBTransactionTypeData { CREATE(SMBTransactionCreate), SESSIONSETUP(SMBTransactionSessionSetup), IOCTL(SMBTransactionIoctl), + RENAME(SMBTransactionRename), +} + +#[derive(Debug)] +pub struct SMBTransactionRename { + pub oldname: Vec, + pub newname: Vec, + pub fuid: Vec, +} + +impl SMBTransactionRename { + pub fn new(fuid: Vec, oldname: Vec, newname: Vec) -> SMBTransactionRename { + return SMBTransactionRename { + fuid: fuid, oldname: oldname, newname: newname, + } + } +} + +impl SMBState { + pub fn new_rename_tx(&mut self, fuid: Vec, oldname: Vec, newname: Vec) + -> (&mut SMBTransaction) + { + let mut tx = self.new_tx(); + + tx.type_data = Some(SMBTransactionTypeData::RENAME( + SMBTransactionRename::new(fuid, oldname, newname))); + tx.request_done = true; + tx.response_done = self.tc_trunc; // no response expected if tc is truncated + + SCLogNotice!("SMB: TX RENAME created: ID {}", tx.id); + self.transactions.push(tx); + let tx_ref = self.transactions.last_mut(); + return tx_ref.unwrap(); + } } #[derive(Debug)] diff --git a/rust/src/smb/smb2.rs b/rust/src/smb/smb2.rs index 83094ddf94..3c2cd9142e 100644 --- a/rust/src/smb/smb2.rs +++ b/rust/src/smb/smb2.rs @@ -276,6 +276,42 @@ pub fn smb2_request_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>) let mut events : Vec = Vec::new(); let have_tx = match r.command { + SMB2_COMMAND_SET_INFO => { + SCLogDebug!("SMB2_COMMAND_SET_INFO: {:?}", r); + let have_si_tx = match parse_smb2_request_setinfo(r.data) { + IResult::Done(_, rd) => { + SCLogDebug!("SMB2_COMMAND_SET_INFO: {:?}", rd); + + if let Some(ref ren) = rd.rename { + let tx_hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); + let mut newname = ren.name.to_vec(); + newname.retain(|&i|i != 0x00); + let oldname = match state.guid2name_map.get(rd.guid) { + Some(n) => { n.to_vec() }, + None => { b"".to_vec() }, + }; + let tx = state.new_rename_tx(rd.guid.to_vec(), oldname, newname); + tx.hdr = tx_hdr; + tx.request_done = true; + tx.vercmd.set_smb2_cmd(SMB2_COMMAND_SET_INFO); + true + } else { + false + } + }, + IResult::Incomplete(_n) => { + SCLogDebug!("SMB2_COMMAND_SET_INFO: {:?}", _n); + events.push(SMBEvent::MalformedData); + false + }, + IResult::Error(_e) => { + SCLogDebug!("SMB2_COMMAND_SET_INFO: {:?}", _e); + events.push(SMBEvent::MalformedData); + false + }, + }; + have_si_tx + }, SMB2_COMMAND_IOCTL => { smb2_ioctl_request_record(state, r); true diff --git a/rust/src/smb/smb2_records.rs b/rust/src/smb/smb2_records.rs index 3b299e4901..ce0fac97b0 100644 --- a/rust/src/smb/smb2_records.rs +++ b/rust/src/smb/smb2_records.rs @@ -300,6 +300,50 @@ named!(pub parse_smb2_request_close, }) )); +#[derive(Debug)] +pub struct Smb2SetInfoRequestRenameRecord<'a> { + pub name: &'a[u8], +} + +named!(pub parse_smb2_request_setinfo_rename, + do_parse!( + replace: le_u8 + >> _reserved: take!(7) + >> _root_handle: take!(8) + >> name_len: le_u32 + >> name: take!(name_len) + >> (Smb2SetInfoRequestRenameRecord { + name: name, + }) +)); + +#[derive(Debug)] +pub struct Smb2SetInfoRequestRecord<'a> { + pub guid: &'a[u8], + pub class: u8, + pub infolvl: u8, + pub rename: Option>, +} + +named!(pub parse_smb2_request_setinfo, + do_parse!( + struct_size: le_u16 + >> class: le_u8 + >> infolvl: le_u8 + >> setinfo_size: le_u32 + >> setinfo_offset: le_u16 + >> _reserved: take!(2) + >> additional_info: le_u32 + >> guid: take!(16) + >> rename: cond!(class == 1 && infolvl == 10, flat_map!(take!(setinfo_size),parse_smb2_request_setinfo_rename)) + >> (Smb2SetInfoRequestRecord { + guid: guid, + class: class, + infolvl: infolvl, + rename: rename, + }) +)); + #[derive(Debug,PartialEq)] pub struct Smb2WriteRequestRecord<'a> { pub wr_len: u32,