]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
smb: fix smb2 header flag parsing
authorJason Ish <jason.ish@oisf.net>
Mon, 18 Apr 2022 16:32:25 +0000 (10:32 -0600)
committerVictor Julien <vjulien@oisf.net>
Tue, 19 Apr 2022 11:50:42 +0000 (13:50 +0200)
The bits were being parsed in the order they're displayed in Wireshark,
rather than the order they were being seen on the wire, resulting in
direction and async being 0 more often than they should be.

Instead of bits, take the 4 bytes as an le_u32 and just use bit masks to
extract what we need into a struct, I think its easier to reason about
this way when comparing to the Microsoft documentation.

(cherry picked from commit 7b659489c85eaed4921ed9c4b97ecf827560376e)

rust/src/smb/smb2_records.rs

index 54a5238963b75487aa936b4201eb50f248ef82c5..44deb0ffc96a935a68e331699d424326a3b54a3b 100644 (file)
@@ -22,6 +22,9 @@ use nom::number::streaming::{le_u8, le_u16, le_u32, le_u64};
 use crate::smb::smb::*;
 use crate::smb::nbss_records::NBSS_MSGTYPE_SESSION_MESSAGE;
 
+const SMB2_FLAGS_SERVER_TO_REDIR: u32 = 0x0000_0001;
+const SMB2_FLAGS_ASYNC_COMMAND: u32 = 0x0000_0002;
+
 #[derive(Debug,PartialEq)]
 pub struct Smb2SecBlobRecord<'a> {
     pub data: &'a[u8],
@@ -68,18 +71,20 @@ impl<'a> Smb2Record<'a> {
     }
 }
 
-fn parse_smb2_request_flags(i:&[u8]) -> IResult<&[u8],(u8,u8,u8,u32,u8,u8,u8,u8)> {
-    bits!(i,
-        tuple!(
-            take_bits!(2u8),      // reserved / unused
-            take_bits!(1u8),      // replay op
-            take_bits!(1u8),      // dfs op
-            take_bits!(24u32),    // reserved / unused
-            take_bits!(1u8),      // signing
-            take_bits!(1u8),      // chained
-            take_bits!(1u8),      // async
-            take_bits!(1u8)       // response
-        ))
+#[derive(Debug)]
+struct SmbFlags {
+    direction: u8,
+    async_command: u8,
+}
+
+fn parse_smb2_flags(i: &[u8]) -> IResult<&[u8], SmbFlags> {
+    let (i, val) = le_u32(i)?;
+    let direction = if val & SMB2_FLAGS_SERVER_TO_REDIR != 0 { 1 } else { 0 };
+    let async_command = if val & SMB2_FLAGS_ASYNC_COMMAND != 0 { 1 } else { 0 };
+    Ok((i, SmbFlags {
+        direction,
+        async_command,
+    }))
 }
 
 named!(pub parse_smb2_request_record<Smb2Record>,
@@ -91,7 +96,7 @@ named!(pub parse_smb2_request_record<Smb2Record>,
         >>  _reserved: take!(2)
         >>  command: le_u16
         >>  _credits_requested: le_u16
-        >>  flags: parse_smb2_request_flags
+        >>  flags: parse_smb2_flags
         >> chain_offset: le_u32
         >> message_id: le_u64
         >> _process_id: le_u32
@@ -102,7 +107,7 @@ named!(pub parse_smb2_request_record<Smb2Record>,
         >> data_c: cond!(chain_offset > hlen as u32, take!(chain_offset - hlen as u32))
         >> data_r: cond!(chain_offset <= hlen as u32, rest)
         >> (Smb2Record {
-                direction: flags.7,
+                direction: flags.direction,
                 nt_status: 0,
                 command:command,
                 message_id: message_id,
@@ -513,19 +518,19 @@ named!(pub parse_smb2_response_record<Smb2Record>,
         >>  nt_status: le_u32
         >>  command: le_u16
         >>  _credit_granted: le_u16
-        >>  flags: parse_smb2_request_flags
+        >>  flags: parse_smb2_flags
         >> chain_offset: le_u32
         >> message_id: le_u64
-        >> _process_id: cond!(flags.6==0, le_u32)
-        >> tree_id: cond!(flags.6==0, le_u32)
-        >> async_id: cond!(flags.6==1, le_u64)
+        >> _process_id: cond!(flags.async_command == 0, le_u32)
+        >> tree_id: cond!(flags.async_command == 0, le_u32)
+        >> async_id: cond!(flags.async_command == 1, le_u64)
         >> session_id: le_u64
         >> _signature: take!(16)
         // there is probably a cleaner way to do this
         >> data_c: cond!(chain_offset > hlen as u32, take!(chain_offset - hlen as u32))
         >> data_r: cond!(chain_offset <= hlen as u32, rest)
         >> (Smb2Record {
-                direction: flags.7,
+                direction: flags.direction,
                 nt_status: nt_status,
                 message_id: message_id,
                 tree_id: tree_id.unwrap_or(0),