]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
smb: improve dcerpc logic
authorVictor Julien <victor@inliniac.net>
Sat, 7 Jul 2018 09:47:55 +0000 (11:47 +0200)
committerVictor Julien <victor@inliniac.net>
Fri, 13 Jul 2018 11:37:35 +0000 (13:37 +0200)
Detect whether a pipe is a dcerpc channel based on the name of the
pipe.

rust/src/smb/smb.rs
rust/src/smb/smb1.rs

index 2e96e448e72b3fad5c41c99dc482871b5782cc56..5af874c77aa2b9fcee3679c850c2b691aec266ae 100644 (file)
@@ -574,10 +574,9 @@ pub const SMBHDR_TYPE_OFFSET:      u32 = 4;
 pub const SMBHDR_TYPE_GENERICTX:   u32 = 5;
 pub const SMBHDR_TYPE_HEADER:      u32 = 6;
 pub const SMBHDR_TYPE_MAX_SIZE:    u32 = 7; // max resp size for SMB1_COMMAND_TRANS
-pub const SMBHDR_TYPE_TXNAME:      u32 = 8; // SMB1_COMMAND_TRANS tx_name
-pub const SMBHDR_TYPE_TRANS_FRAG:  u32 = 9;
-pub const SMBHDR_TYPE_TREE:        u32 = 10;
-pub const SMBHDR_TYPE_DCERPCTX:    u32 = 11;
+pub const SMBHDR_TYPE_TRANS_FRAG:  u32 = 8;
+pub const SMBHDR_TYPE_TREE:        u32 = 9;
+pub const SMBHDR_TYPE_DCERPCTX:    u32 = 10;
 
 #[derive(Hash, Eq, PartialEq, Debug)]
 pub struct SMBCommonHdr {
@@ -1044,13 +1043,19 @@ impl SMBState {
     {
         let (name, is_dcerpc) = match self.guid2name_map.get(&guid.to_vec()) {
             Some(n) => {
-                match str::from_utf8(&n) {
+                let mut s = n.as_slice();
+                // skip leading \ if we have it
+                if s.len() > 1 && s[0] == 0x5c_u8 {
+                    s = &s[1..];
+                }
+                match str::from_utf8(s) {
                     Ok("PSEXESVC") => ("PSEXESVC", false),
                     Ok("svcctl") => ("svcctl", true),
                     Ok("srvsvc") => ("srvsvc", true),
                     Ok("atsvc") => ("atsvc", true),
                     Ok("lsarpc") => ("lsarpc", true),
                     Ok("samr") => ("samr", true),
+                    Ok("spoolss") => ("spoolss", true),
                     Err(_) => ("MALFORMED", false),
                     Ok(&_) => {
                         SCLogDebug!("don't know {}", String::from_utf8_lossy(&n));
index a45508b8c8f1f3fe11813fb72517352d9de5d79c..2ee9b9d2c125aafff4b179c60d0f8005cdf3b669 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 extern crate libc;
-use std::str;
 
 use nom::{IResult};
 
@@ -683,22 +682,6 @@ pub fn smb1_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32
     0
 }
 
-pub fn get_service_for_nameslice(nameslice: &[u8]) -> (&'static str, bool)
-{
-    let mut name = nameslice.to_vec();
-    name.retain(|&i|i != 0x00);
-
-    match str::from_utf8(&name) {
-        Ok("\\PIPE\\LANMAN") => ("LANMAN", false),
-        Ok("\\PIPE\\") => ("PIPE", true), // TODO not sure if this is true
-        Err(_) => ("MALFORMED", false),
-        Ok(&_) => {
-            SCLogDebug!("don't know \"{}\"", String::from_utf8_lossy(&name));
-            ("UNKNOWN", false)
-        },
-    }
-}
-
 pub fn smb1_trans_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
 {
     let mut events : Vec<SMBEvent> = Vec::new();
@@ -708,19 +691,24 @@ pub fn smb1_trans_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
             SCLogDebug!("TRANS request {:?}", rd);
 
             /* if we have a fid, store it so the response can pick it up */
+            let mut pipe_dcerpc = false;
             if rd.pipe != None {
                 let pipe = rd.pipe.unwrap();
                 state.ssn2vec_map.insert(SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID),
                         pipe.fid.to_vec());
-            }
 
-            let (sername, is_dcerpc) = get_service_for_nameslice(&rd.txname);
-            SCLogDebug!("service: {} dcerpc {}", sername, is_dcerpc);
-            if is_dcerpc {
-                // store tx name so the response also knows this is dcerpc
-                let txn_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_TXNAME);
-                state.ssn2vec_map.insert(txn_hdr, rd.txname);
+                let mut frankenfid = pipe.fid.to_vec();
+                frankenfid.extend_from_slice(&u32_as_bytes(r.ssn_id));
 
+                let (filename, is_dcerpc) = match state.get_service_for_guid(&frankenfid) {
+                    (n, x) => (n, x),
+                };
+                SCLogDebug!("smb1_trans_request_record: name {} is_dcerpc {}",
+                        filename, is_dcerpc);
+                pipe_dcerpc = is_dcerpc;
+            }
+
+            if pipe_dcerpc {
                 // trans request will tell us the max size of the response
                 // if there is more response data, it will first give a
                 // TRANS with 'max data cnt' worth of data, and the rest
@@ -761,33 +749,31 @@ pub fn smb1_trans_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
             };
             SCLogDebug!("FID {:?}", fid);
 
+            let mut frankenfid = fid.to_vec();
+            frankenfid.extend_from_slice(&u32_as_bytes(r.ssn_id));
+
+            let (filename, is_dcerpc) = match state.get_service_for_guid(&frankenfid) {
+                (n, x) => (n, x),
+            };
+            SCLogDebug!("smb1_trans_response_record: name {} is_dcerpc {}",
+                    filename, is_dcerpc);
+
             // if we get status 'BUFFER_OVERFLOW' this is only a part of
             // the data. Store it in the ssn/tree for later use.
             if r.nt_status == SMB_NTSTATUS_BUFFER_OVERFLOW {
                 state.ssnguid2vec_map.insert(SMBHashKeyHdrGuid::new(
                             SMBCommonHdr::from1(r, SMBHDR_TYPE_TRANS_FRAG), fid),
                         rd.data.to_vec());
-            } else {
-                let txn_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_TXNAME);
-                let is_dcerpc = match state.ssn2vec_map.remove(&txn_hdr) {
-                    None => false,
-                    Some(s) => {
-                        let (sername, is_dcerpc) = get_service_for_nameslice(&s);
-                        SCLogDebug!("service: {} dcerpc {}", sername, is_dcerpc);
-                        is_dcerpc
-                    },
-                };
-                if is_dcerpc {
-                    SCLogDebug!("SMBv1 TRANS TO PIPE");
-                    let hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER);
-                    let vercmd = SMBVerCmdStat::new1_with_ntstatus(r.command, r.nt_status);
-                    smb_read_dcerpc_record(state, vercmd, hdr, &fid, &rd.data);
-                }
+            } else if is_dcerpc {
+                SCLogDebug!("SMBv1 TRANS TO PIPE");
+                let hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER);
+                let vercmd = SMBVerCmdStat::new1_with_ntstatus(r.command, r.nt_status);
+                smb_read_dcerpc_record(state, vercmd, hdr, &fid, &rd.data);
             }
         },
-            _ => {
-                events.push(SMBEvent::MalformedData);
-            },
+        _ => {
+            events.push(SMBEvent::MalformedData);
+        },
     }
 
     // generic tx as well. Set events if needed.