From: Philippe Antoine Date: Tue, 14 Apr 2020 08:30:33 +0000 (+0200) Subject: smb: adds file overlap event against evasions X-Git-Tag: suricata-6.0.0~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=caa7946888c509ca7e46a26fdbe30aaaa5382fc4;p=thirdparty%2Fsuricata.git smb: adds file overlap event against evasions Evasion scenario is - a first dummy write of one byte at offset 0 is done - the second full write of EICAR at offset 0 is then done and does not trigger detection The last write had the final value, and as we cannot "cancel" the previous write, we set an event which is then transformed into an app-layer decoder alert --- 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/smb/events.rs b/rust/src/smb/events.rs index 31256d3912..1b29da7d43 100644 --- a/rust/src/smb/events.rs +++ b/rust/src/smb/events.rs @@ -27,6 +27,7 @@ pub enum SMBEvent { MalformedNtlmsspResponse = 4, DuplicateNegotiate = 5, NegotiateMalformedDialects = 6, + FileOverlap = 7, } impl SMBEvent { @@ -39,6 +40,7 @@ impl SMBEvent { 4 => Some(SMBEvent::MalformedNtlmsspResponse), 5 => Some(SMBEvent::DuplicateNegotiate), 6 => Some(SMBEvent::NegotiateMalformedDialects), + 7 => Some(SMBEvent::FileOverlap), _ => None, } } @@ -54,6 +56,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 8071d50ca8..bbb6685e1d 100644 --- a/rust/src/smb/smb.rs +++ b/rust/src/smb/smb.rs @@ -2131,6 +2131,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 1c80912a0d..274a8246ab 100644 --- a/rust/src/smb/smb1.rs +++ b/rust/src/smb/smb1.rs @@ -906,10 +906,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); @@ -935,6 +939,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); @@ -943,6 +950,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()); @@ -989,11 +999,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); @@ -1007,6 +1021,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); @@ -1014,6 +1031,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 b75f2e1131..fcf968e823 100644 --- a/rust/src/smb/smb2.rs +++ b/rust/src/smb/smb2.rs @@ -143,11 +143,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); @@ -207,6 +211,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); @@ -218,6 +225,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()); } _ => { @@ -247,10 +257,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); @@ -306,6 +320,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); @@ -315,6 +332,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()); }, _ => {