]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
smb: adds file overlap event against evasions
authorPhilippe Antoine <contact@catenacyber.fr>
Tue, 14 Apr 2020 08:30:33 +0000 (10:30 +0200)
committerJason Ish <jason.ish@oisf.net>
Wed, 7 Oct 2020 15:40:38 +0000 (09:40 -0600)
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

rules/smb-events.rules
rust/src/smb/events.rs
rust/src/smb/smb.rs
rust/src/smb/smb1.rs
rust/src/smb/smb2.rs

index 486323beb9684b31a6b45b0490a8e0292a862c8e..97fc675cb1741ef74a5187206bab8cfc235fa088 100644 (file)
@@ -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;)
index 31256d3912c082c73060bb62d1c0e27fd2da350d..1b29da7d4394b3a7d295a10a17708a1ba8f6cc5f 100644 (file)
@@ -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,
     }
 }
index 8071d50ca89f0b02a356e605db1959f07430d8df..bbb6685e1d66de661691bf8c0991337b281c2f9a 100644 (file)
@@ -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;
index 1c80912a0da456ae8d47b5b7b063f0a960a119ec..274a8246ab197291658a5d392329a792039ee20b 100644 (file)
@@ -906,10 +906,14 @@ pub fn smb1_write_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
                 Some(n) => n.to_vec(),
                 None => b"<unknown>".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);
index b75f2e11310454472ecd36c568fa7c37a49fbe62..fcf968e82389e241f8e7de868b98d5cbeab03d3b 100644 (file)
@@ -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());
         },
         _ => {