diff --git a/rules/smb-events.rules b/rules/smb-events.rules index 486323beb9..97fc675cb1 100644 --- a/rules/smb-events.rules +++ b/rules/smb-events.rules @@ -14,3 +14,5 @@ alert smb any any -> any any (msg:"SURICATA SMB malformed response data"; flow:t alert smb any any -> any any (msg:"SURICATA SMB malformed NTLMSSP record"; flow:to_server; app-layer-event:smb.malformed_ntlmssp_request; classtype:protocol-command-decode; sid:2225004; rev:1;) alert smb any any -> any any (msg:"SURICATA SMB malformed request dialects"; flow:to_server; app-layer-event:smb.negotiate_malformed_dialects; classtype:protocol-command-decode; sid:2225005; rev:1;) + +alert smb any any -> any any (msg:"SURICATA SMB file overlap"; app-layer-event:smb.file_overlap; classtype:protocol-command-decode; sid:2225006; rev:1;) diff --git a/rust/src/filetracker.rs b/rust/src/filetracker.rs index 233eefbedf..1981b54e00 100644 --- a/rust/src/filetracker.rs +++ b/rust/src/filetracker.rs @@ -52,7 +52,7 @@ impl FileChunk { #[derive(Debug)] pub struct FileTransferTracker { file_size: u64, - tracked: u64, + pub tracked: u64, cur_ooo: u64, // how many bytes do we have queued from ooo chunks track_id: u32, chunk_left: u32, diff --git a/rust/src/smb/events.rs b/rust/src/smb/events.rs index 3d3ec6adca..3093d08e2f 100644 --- a/rust/src/smb/events.rs +++ b/rust/src/smb/events.rs @@ -28,6 +28,7 @@ pub enum SMBEvent { MalformedNtlmsspResponse = 4, DuplicateNegotiate = 5, NegotiateMalformedDialects = 6, + FileOverlap = 7, } impl SMBEvent { @@ -40,6 +41,7 @@ impl SMBEvent { 4 => Some(SMBEvent::MalformedNtlmsspResponse), 5 => Some(SMBEvent::DuplicateNegotiate), 6 => Some(SMBEvent::NegotiateMalformedDialects), + 7 => Some(SMBEvent::FileOverlap), _ => None, } } @@ -55,6 +57,7 @@ pub fn smb_str_to_event(instr: &str) -> i32 { "malformed_ntlmssp_response" => SMBEvent::MalformedNtlmsspResponse as i32, "duplicate_negotiate" => SMBEvent::DuplicateNegotiate as i32, "negotiate_malformed_dialects" => SMBEvent::NegotiateMalformedDialects as i32, + "file_overlap" => SMBEvent::FileOverlap as i32, _ => -1, } } diff --git a/rust/src/smb/smb.rs b/rust/src/smb/smb.rs index 0200bf0105..def2b23b67 100644 --- a/rust/src/smb/smb.rs +++ b/rust/src/smb/smb.rs @@ -2164,6 +2164,7 @@ pub extern "C" fn rs_smb_state_get_event_info_by_id(event_id: std::os::raw::c_in SMBEvent::MalformedNtlmsspResponse => { "malformed_ntlmssp_response\0" }, SMBEvent::DuplicateNegotiate => { "duplicate_negotiate\0" }, SMBEvent::NegotiateMalformedDialects => { "netogiate_malformed_dialects\0" }, + SMBEvent::FileOverlap => { "file_overlap\0" }, }; unsafe{ *event_name = estr.as_ptr() as *const std::os::raw::c_char; diff --git a/rust/src/smb/smb1.rs b/rust/src/smb/smb1.rs index b4262cf0cc..47e2d90dd4 100644 --- a/rust/src/smb/smb1.rs +++ b/rust/src/smb/smb1.rs @@ -907,10 +907,14 @@ pub fn smb1_write_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) Some(n) => n.to_vec(), None => b"".to_vec(), }; + let mut set_event_fileoverlap = false; let found = match state.get_file_tx_by_fuid(&file_fid, STREAM_TOSERVER) { Some((tx, files, flags)) => { let file_id : u32 = tx.id as u32; if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { + if rd.offset < tdf.file_tracker.tracked { + set_event_fileoverlap = true; + } filetracker_newchunk(&mut tdf.file_tracker, files, flags, &file_name, rd.data, rd.offset, rd.len, 0, false, &file_id); @@ -936,6 +940,9 @@ pub fn smb1_write_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { let file_id : u32 = tx.id as u32; SCLogDebug!("FID {:?} found at tx {}", file_fid, tx.id); + if rd.offset < tdf.file_tracker.tracked { + set_event_fileoverlap = true; + } filetracker_newchunk(&mut tdf.file_tracker, files, flags, &file_name, rd.data, rd.offset, rd.len, 0, false, &file_id); @@ -944,6 +951,9 @@ pub fn smb1_write_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) tx.vercmd.set_smb1_cmd(SMB1_COMMAND_WRITE_ANDX); } } + if set_event_fileoverlap { + state.set_event(SMBEvent::FileOverlap); + } state.set_file_left(STREAM_TOSERVER, rd.len, rd.data.len() as u32, file_fid.to_vec()); @@ -990,11 +1000,15 @@ pub fn smb1_read_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) Some(n) => n.to_vec(), None => Vec::new(), }; + let mut set_event_fileoverlap = false; let found = match state.get_file_tx_by_fuid(&file_fid, STREAM_TOCLIENT) { Some((tx, files, flags)) => { if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { let file_id : u32 = tx.id as u32; SCLogDebug!("FID {:?} found at tx {}", file_fid, tx.id); + if offset < tdf.file_tracker.tracked { + set_event_fileoverlap = true; + } filetracker_newchunk(&mut tdf.file_tracker, files, flags, &file_name, rd.data, offset, rd.len, 0, false, &file_id); @@ -1008,6 +1022,9 @@ pub fn smb1_read_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { let file_id : u32 = tx.id as u32; SCLogDebug!("FID {:?} found at tx {}", file_fid, tx.id); + if offset < tdf.file_tracker.tracked { + set_event_fileoverlap = true; + } filetracker_newchunk(&mut tdf.file_tracker, files, flags, &file_name, rd.data, offset, rd.len, 0, false, &file_id); @@ -1015,6 +1032,9 @@ pub fn smb1_read_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) } tx.vercmd.set_smb1_cmd(SMB1_COMMAND_READ_ANDX); } + if set_event_fileoverlap { + state.set_event(SMBEvent::FileOverlap); + } } else { SCLogDebug!("SMBv1 READ response from PIPE"); let hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER); diff --git a/rust/src/smb/smb2.rs b/rust/src/smb/smb2.rs index 2fd611482e..e5219dfebe 100644 --- a/rust/src/smb/smb2.rs +++ b/rust/src/smb/smb2.rs @@ -144,11 +144,15 @@ pub fn smb2_read_response_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>) }; SCLogDebug!("SMBv2 READ: GUID {:?} offset {}", file_guid, offset); + let mut set_event_fileoverlap = false; // look up existing tracker and if we have it update it let found = match state.get_file_tx_by_fuid(&file_guid, STREAM_TOCLIENT) { Some((tx, files, flags)) => { if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { let file_id : u32 = tx.id as u32; + if offset < tdf.file_tracker.tracked { + set_event_fileoverlap = true; + } filetracker_newchunk(&mut tdf.file_tracker, files, flags, &tdf.file_name, rd.data, offset, rd.len, 0, false, &file_id); @@ -208,6 +212,9 @@ pub fn smb2_read_response_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>) let (tx, files, flags) = state.new_file_tx(&file_guid, &file_name, STREAM_TOCLIENT); if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { let file_id : u32 = tx.id as u32; + if offset < tdf.file_tracker.tracked { + set_event_fileoverlap = true; + } filetracker_newchunk(&mut tdf.file_tracker, files, flags, &file_name, rd.data, offset, rd.len, 0, false, &file_id); @@ -219,6 +226,9 @@ pub fn smb2_read_response_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>) } } + if set_event_fileoverlap { + state.set_event(SMBEvent::FileOverlap); + } state.set_file_left(STREAM_TOCLIENT, rd.len, rd.data.len() as u32, file_guid.to_vec()); } _ => { @@ -248,10 +258,14 @@ pub fn smb2_write_request_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>) None => Vec::new(), }; + let mut set_event_fileoverlap = false; let found = match state.get_file_tx_by_fuid(&file_guid, STREAM_TOSERVER) { Some((tx, files, flags)) => { if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { let file_id : u32 = tx.id as u32; + if wr.wr_offset < tdf.file_tracker.tracked { + set_event_fileoverlap = true; + } filetracker_newchunk(&mut tdf.file_tracker, files, flags, &file_name, wr.data, wr.wr_offset, wr.wr_len, 0, false, &file_id); @@ -307,6 +321,9 @@ pub fn smb2_write_request_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>) let (tx, files, flags) = state.new_file_tx(&file_guid, &file_name, STREAM_TOSERVER); if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { let file_id : u32 = tx.id as u32; + if wr.wr_offset < tdf.file_tracker.tracked { + set_event_fileoverlap = true; + } filetracker_newchunk(&mut tdf.file_tracker, files, flags, &file_name, wr.data, wr.wr_offset, wr.wr_len, 0, false, &file_id); @@ -316,6 +333,10 @@ pub fn smb2_write_request_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>) r.session_id, r.tree_id, 0); // TODO move into new_file_tx } } + + if set_event_fileoverlap { + state.set_event(SMBEvent::FileOverlap); + } state.set_file_left(STREAM_TOSERVER, wr.wr_len, wr.data.len() as u32, file_guid.to_vec()); }, _ => {