]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
smb: protocol detection on pattern without midstream
authorJason Ish <jason.ish@oisf.net>
Thu, 31 Mar 2022 18:45:07 +0000 (12:45 -0600)
committerShivani Bhardwaj <shivanib134@gmail.com>
Thu, 21 Apr 2022 07:31:56 +0000 (13:01 +0530)
To recognize a protocol, Suricata first looks for
patterns, which can be confirmed by a probing parser.
If this does not work, Suricata can try to run
some probing parsers on some ports.

This is the case for SMB.

This commit makes handling the confirming and the probing
paser differently even if they share much code.

The confirmation parser knows that a pattern has been found.
So, it must not do the midstream case of looking for this
pattern in the whole buffer, but only check it at the beginning.
But it must reverse direction if needed.

Ticket #4849

Backported manually by jason.ish@oisf.net.

(cherry picked from commit 464ff80c6a8efd1212b617a80c726173573caf42)

rust/src/smb/smb.rs
src/app-layer-smb.c

index 8e094c9d58884581b3b88eddff9bc70fdac45899..f26fb13167d75030d2e3ebb3c32ae803226d2b61 100644 (file)
@@ -58,6 +58,8 @@ pub static mut SMB_CFG_MAX_WRITE_SIZE: u32 = 0;
 pub static mut SMB_CFG_MAX_WRITE_QUEUE_SIZE: u32 = 0;
 pub static mut SMB_CFG_MAX_WRITE_QUEUE_CNT: u32 = 0;
 
+pub const MIN_REC_SIZE: u16 = 32 + 4; // SMB hdr + nbss hdr
+
 pub static mut SURICATA_SMB_FILE_CONFIG: Option<&'static SuricataFileContext> = None;
 
 #[no_mangle]
@@ -1940,9 +1942,18 @@ pub extern "C" fn rs_smb_parse_response_tcp_gap(
     state.parse_tcp_data_tc_gap(input_len as u32)
 }
 
-fn rs_smb_probe_tcp_midstream(direction: u8, slice: &[u8], rdir: *mut u8) -> i8
+fn smb_probe_tcp(direction: u8, slice: &[u8], rdir: *mut u8, begins: bool) -> i8
 {
-    match search_smb_record(slice) {
+    let r = if begins {
+        if slice[0] == NBSS_MSGTYPE_SESSION_MESSAGE {
+            Ok((&slice[..4], &slice[4..]))
+        } else {
+            Err(nom::Err::Error(error_position!(slice, nom::error::ErrorKind::Eof)))
+        }
+    } else {
+        search_smb_record(slice)
+    };
+    match r {
         Ok((_, ref data)) => {
             SCLogDebug!("smb found");
             match parse_smb_version(data) {
@@ -2003,53 +2014,30 @@ fn rs_smb_probe_tcp_midstream(direction: u8, slice: &[u8], rdir: *mut u8) -> i8
     return 0;
 }
 
-// probing parser
+// probing confirmation parser
 // return 1 if found, 0 is not found
 #[no_mangle]
-pub extern "C" fn rs_smb_probe_tcp(flags: u8,
-        input: *const u8, len: u32,
-        rdir: *mut u8)
+pub extern "C" fn rs_smb_probe_begins_tcp(direction: u8, input: *const u8, len: u32, rdir: *mut u8)
     -> i8
 {
+    if len < MIN_REC_SIZE as u32 {
+        return 0;
+    }
     let slice = build_slice!(input, len as usize);
-    if flags & STREAM_MIDSTREAM == STREAM_MIDSTREAM {
-        if rs_smb_probe_tcp_midstream(flags, slice, rdir) == 1 {
-            return 1;
-        }
-    }
-    match parse_nbss_record_partial(slice) {
-        Ok((_, ref hdr)) => {
-            if hdr.is_smb() {
-                SCLogDebug!("smb found");
-                return 1;
-            } else if hdr.needs_more(){
-                return 0;
-            } else if hdr.is_valid() &&
-                hdr.message_type != NBSS_MSGTYPE_SESSION_MESSAGE {
-                //we accept a first small netbios message before real SMB
-                let hl = hdr.length as usize;
-                if hdr.data.len() >= hl + 8 {
-                    // 8 is 4 bytes NBSS + 4 bytes SMB0xFX magic
-                    match parse_nbss_record_partial(&hdr.data[hl..]) {
-                        Ok((_, ref hdr2)) => {
-                            if hdr2.is_smb() {
-                                SCLogDebug!("smb found");
-                                return 1;
-                            }
-                        }
-                        _ => {}
-                    }
-                } else if hdr.length < 256 {
-                    // we want more data, 256 is some random value
-                    return 0;
-                }
-                // default is failure
-            }
-        },
-        _ => { },
+    return smb_probe_tcp(direction, slice, rdir, true);
+}
+
+// probing confirmation parser
+// return 1 if found, 0 is not found
+#[no_mangle]
+pub extern "C" fn rs_smb_probe_tcp(direction: u8, input: *const u8, len: u32, rdir: *mut u8)
+    -> i8
+{
+    if len < MIN_REC_SIZE as u32 {
+        return 0;
     }
-    SCLogDebug!("no smb");
-    return -1
+    let slice = build_slice!(input, len as usize);
+    return smb_probe_tcp(direction, slice, rdir, false);
 }
 
 #[no_mangle]
index 72d3a83113f238c745a0240625034d09b47e8f44..732bd111e0a1c424806fbf819c566f35fea71ab0 100644 (file)
@@ -92,6 +92,27 @@ static uint16_t SMBTCPProbe(Flow *f, uint8_t direction,
     }
 }
 
+static uint16_t SMBTCPProbeBegins(Flow *f, uint8_t direction,
+        const uint8_t *input, uint32_t len, uint8_t *rdir)
+{
+    SCLogDebug("SMBTCPProbeBegins");
+
+    if (len < MIN_REC_SIZE) {
+        return ALPROTO_UNKNOWN;
+    }
+
+    const int r = rs_smb_probe_begins_tcp(direction, input, len, rdir);
+    switch (r) {
+        case 1:
+            return ALPROTO_SMB;
+        case 0:
+            return ALPROTO_UNKNOWN;
+        case -1:
+        default:
+            return ALPROTO_FAILED;
+    }
+}
+
 /** \internal
  *  \brief as SMB3 records have no direction indicator, fall
  *         back to the port numbers for a hint
@@ -197,18 +218,18 @@ static int SMBRegisterPatternsForProtocolDetection(void)
     int r = 0;
     /* SMB1 */
     r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB,
-            "|ff|SMB", 8, 4, STREAM_TOSERVER, SMBTCPProbe,
+            "|ff|SMB", 8, 4, STREAM_TOSERVER, SMBTCPProbeBegins,
             MIN_REC_SIZE, MIN_REC_SIZE);
     r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB,
-            "|ff|SMB", 8, 4, STREAM_TOCLIENT, SMBTCPProbe,
+            "|ff|SMB", 8, 4, STREAM_TOCLIENT, SMBTCPProbeBegins,
             MIN_REC_SIZE, MIN_REC_SIZE);
 
     /* SMB2/3 */
     r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB,
-            "|fe|SMB", 8, 4, STREAM_TOSERVER, SMBTCPProbe,
+            "|fe|SMB", 8, 4, STREAM_TOSERVER, SMBTCPProbeBegins,
             MIN_REC_SIZE, MIN_REC_SIZE);
     r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB,
-            "|fe|SMB", 8, 4, STREAM_TOCLIENT, SMBTCPProbe,
+            "|fe|SMB", 8, 4, STREAM_TOCLIENT, SMBTCPProbeBegins,
             MIN_REC_SIZE, MIN_REC_SIZE);
 
     /* SMB3 encrypted records */