From: Victor Julien Date: Thu, 15 Mar 2018 15:50:38 +0000 (+0100) Subject: smb1: extract rename info from TRANS2 X-Git-Tag: suricata-4.1.0-beta1~41 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F3289%2Fhead;p=thirdparty%2Fsuricata.git smb1: extract rename info from TRANS2 Exclude TRANS2 from generic TX lookup bypass. --- diff --git a/rust/src/smb/smb1.rs b/rust/src/smb/smb1.rs index f39c2e6bad..c33a91ee18 100644 --- a/rust/src/smb/smb1.rs +++ b/rust/src/smb/smb1.rs @@ -133,6 +133,18 @@ pub fn smb1_create_new_tx(cmd: u8) -> bool { } } +// see if we're going to do a lookup for a TX. +// related to smb1_create_new_tx(), however it +// excludes the 'maybe' commands like TRANS2 +pub fn smb1_check_tx(cmd: u8) -> bool { + match cmd { + SMB1_COMMAND_READ_ANDX | + SMB1_COMMAND_WRITE_ANDX | + SMB1_COMMAND_TRANS => { false }, + _ => { true }, + } +} + fn smb1_close_file(state: &mut SMBState, fid: &Vec) { // we can have created 2 txs for a FID: one for reads @@ -199,7 +211,79 @@ pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 { }, } }, - + SMB1_COMMAND_TRANS2 => { + match parse_smb_trans2_request_record(r.data) { + IResult::Done(_, rd) => { + SCLogDebug!("TRANS2 DONE {:?}", rd); + + if rd.subcmd == 8 { + match parse_trans2_request_params_set_file_info(rd.setup_blob) { + IResult::Done(_, pd) => { + SCLogDebug!("TRANS2 SET_FILE_INFO PARAMS DONE {:?}", pd); + + if pd.loi == 1010 { + match parse_trans2_request_data_set_file_info_rename(rd.data_blob) { + IResult::Done(_, ren) => { + SCLogDebug!("TRANS2 SET_FILE_INFO DATA RENAME DONE {:?}", ren); + let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); + let mut newname = ren.newname.to_vec(); + newname.retain(|&i|i != 0x00); + + let mut frankenfid = pd.fid.to_vec(); + frankenfid.extend_from_slice(&u32_as_bytes(r.ssn_id)); + + let oldname = match state.guid2name_map.get(&frankenfid) { + Some(n) => n.to_vec(), + None => b"".to_vec(), + }; + let tx = state.new_rename_tx(pd.fid.to_vec(), oldname, newname); + tx.hdr = tx_hdr; + tx.request_done = true; + tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); + true + }, + IResult::Incomplete(n) => { + SCLogDebug!("TRANS2 SET_FILE_INFO DATA RENAME INCOMPLETE {:?}", n); + events.push(SMBEvent::MalformedData); + false + }, + IResult::Error(e) => { + SCLogDebug!("TRANS2 SET_FILE_INFO DATA RENAME ERROR {:?}", e); + events.push(SMBEvent::MalformedData); + false + }, + } + } else { + false + } + }, + IResult::Incomplete(n) => { + SCLogDebug!("TRANS2 SET_FILE_INFO PARAMS INCOMPLETE {:?}", n); + events.push(SMBEvent::MalformedData); + false + }, + IResult::Error(e) => { + SCLogDebug!("TRANS2 SET_FILE_INFO PARAMS ERROR {:?}", e); + events.push(SMBEvent::MalformedData); + false + }, + } + } else { + false + } + }, + IResult::Incomplete(n) => { + SCLogDebug!("TRANS2 INCOMPLETE {:?}", n); + events.push(SMBEvent::MalformedData); + false + }, + IResult::Error(e) => { + SCLogDebug!("TRANS2 ERROR {:?}", e); + events.push(SMBEvent::MalformedData); + false + }, + } + }, SMB1_COMMAND_READ_ANDX => { match parse_smb_read_andx_request_record(r.data) { IResult::Done(_, rr) => { @@ -355,8 +439,7 @@ pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 { false }, _ => { - if r.command == SMB1_COMMAND_TRANS2 || - r.command == SMB1_COMMAND_LOGOFF_ANDX || + if r.command == SMB1_COMMAND_LOGOFF_ANDX || r.command == SMB1_COMMAND_TREE_DISCONNECT || r.command == SMB1_COMMAND_NT_TRANS || r.command == SMB1_COMMAND_NT_CANCEL || @@ -577,7 +660,7 @@ pub fn smb1_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 }, _ => {}, } - } else if !have_tx && smb1_create_new_tx(r.command) { + } else if !have_tx && smb1_check_tx(r.command) { let tx_key = SMBCommonHdr::new(SMBHDR_TYPE_GENERICTX, key_ssn_id as u64, key_tree_id as u32, key_multiplex_id as u64); let _have_tx2 = match state.get_generic_tx(1, r.command as u16, &tx_key) { diff --git a/rust/src/smb/smb1_records.rs b/rust/src/smb/smb1_records.rs index ed37ff481c..baceac64e7 100644 --- a/rust/src/smb/smb1_records.rs +++ b/rust/src/smb/smb1_records.rs @@ -564,6 +564,79 @@ named!(pub parse_smb_create_andx_request_record, })) ); +#[derive(Debug,PartialEq)] +pub struct Trans2RecordParamSetFileInfo<'a> { + pub fid: &'a[u8], + pub loi: u16, +} + +named!(pub parse_trans2_request_params_set_file_info, + do_parse!( + fid: take!(2) + >> loi: le_u16 + >> (Trans2RecordParamSetFileInfo { + fid:fid, + loi:loi, + }) +)); + +#[derive(Debug,PartialEq)] +pub struct Trans2RecordParamSetFileInfoRename<'a> { + pub replace: bool, + pub newname: &'a[u8], +} + +named!(pub parse_trans2_request_data_set_file_info_rename, + do_parse!( + replace: le_u8 + >> _reserved: take!(3) + >> root_dir: take!(4) + >> newname_len: le_u32 + >> newname: take!(newname_len) + >> (Trans2RecordParamSetFileInfoRename { + replace: replace==1, + newname: newname, + }) +)); + +#[derive(Debug,PartialEq)] +pub struct SmbRequestTrans2Record<'a> { + pub subcmd: u16, + pub setup_blob: &'a[u8], + pub data_blob: &'a[u8], +} + +named!(pub parse_smb_trans2_request_record, + do_parse!( + wct: le_u8 + >> total_param_cnt: le_u16 + >> total_data_cnt: le_u16 + >> max_param_cnt: le_u16 + >> max_data_cnt: le_u16 + >> max_setup_cnt: le_u8 + >> _reserved1: take!(1) + >> flags: le_u16 + >> timeout: le_u32 + >> _reserved2: take!(2) + >> param_cnt: le_u16 + >> param_offset: le_u16 + >> data_cnt: le_u16 + >> data_offset: le_u16 + >> setup_cnt: le_u8 + >> _reserved3: take!(1) + >> subcmd: le_u16 + >> bcc: le_u16 + >> _padding: take!(3) + >> setup_blob: take!(param_cnt) + >> data_blob: take!(data_cnt) + + >> (SmbRequestTrans2Record { + subcmd: subcmd, + setup_blob: setup_blob, + data_blob: data_blob, + })) +); + #[derive(Debug,PartialEq)] pub struct SmbResponseCreateAndXRecord<'a> { pub fid: &'a[u8],