]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
smb: andx support 5910/head
authorPhilippe Antoine <contact@catenacyber.fr>
Fri, 4 Dec 2020 13:46:39 +0000 (14:46 +0100)
committerVictor Julien <victor@inliniac.net>
Tue, 23 Feb 2021 11:11:15 +0000 (12:11 +0100)
Add AndX support for SMB1. Finishes #3475.

[Updated by Victor Julien to split functions]

rust/src/smb/smb.rs
rust/src/smb/smb1.rs
rust/src/smb/smb1_records.rs
rust/src/smb/smb1_session.rs

index 42da36272a84a873120919a0028f7155a7341e8a..32ba667c25c03be96f05266dc194270d8a284f6c 100644 (file)
@@ -1319,7 +1319,7 @@ impl SMBState {
                                             if is_pipe {
                                                 return 0;
                                             }
-                                            smb1_write_request_record(self, r);
+                                            smb1_write_request_record(self, r, SMB1_HEADER_SIZE, SMB1_COMMAND_WRITE_ANDX);
                                             let consumed = input.len() - output.len();
                                             return consumed;
                                         }
@@ -1561,7 +1561,7 @@ impl SMBState {
                                             if is_pipe {
                                                 return 0;
                                             }
-                                            smb1_read_response_record(self, r);
+                                            smb1_read_response_record(self, r, SMB1_HEADER_SIZE);
                                             let consumed = input.len() - output.len();
                                             return consumed;
                                         }
index 274a8246ab197291658a5d392329a792039ee20b..7a00b739ce446805777dfa7199d04f6790d2755c 100644 (file)
@@ -72,6 +72,7 @@ pub const SMB1_COMMAND_QUERY_INFO_DISK:         u8 = 0x80;
 pub const SMB1_COMMAND_NT_TRANS:                u8 = 0xa0;
 pub const SMB1_COMMAND_NT_CREATE_ANDX:          u8 = 0xa2;
 pub const SMB1_COMMAND_NT_CANCEL:               u8 = 0xa4;
+pub const SMB1_COMMAND_NONE:                    u8 = 0xff;
 
 pub fn smb1_command_string(c: u8) -> String {
     match c {
@@ -179,13 +180,29 @@ fn smb1_close_file(state: &mut SMBState, fid: &Vec<u8>)
     }
 }
 
-pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
-    SCLogDebug!("record: command {}: record {:?}", r.command, r);
+fn smb1_command_is_andx(c: u8) -> bool {
+    match c {
+        SMB1_COMMAND_LOCKING_ANDX |
+        SMB1_COMMAND_OPEN_ANDX |
+        SMB1_COMMAND_READ_ANDX |
+        SMB1_COMMAND_SESSION_SETUP_ANDX |
+        SMB1_COMMAND_LOGOFF_ANDX |
+        SMB1_COMMAND_TREE_CONNECT_ANDX |
+        SMB1_COMMAND_NT_CREATE_ANDX |
+        SMB1_COMMAND_WRITE_ANDX  => {
+            return true;
+        }
+        _ => {
+            return false;
+        }
+    }
+}
 
+fn smb1_request_record_one<'b>(state: &mut SMBState, r: &SmbRecord<'b>, command: u8, andx_offset: &mut usize) -> u32 {
     let mut events : Vec<SMBEvent> = Vec::new();
     let mut no_response_expected = false;
 
-    let have_tx = match r.command {
+    let have_tx = match command {
         SMB1_COMMAND_RENAME => {
             match parse_smb_rename_request_record(r.data) {
                 Ok((_, rd)) => {
@@ -396,7 +413,7 @@ pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
             }
         },
         SMB1_COMMAND_READ_ANDX => {
-            match parse_smb_read_andx_request_record(r.data) {
+            match parse_smb_read_andx_request_record(&r.data[*andx_offset-SMB1_HEADER_SIZE..]) {
                 Ok((_, rr)) => {
                     SCLogDebug!("rr {:?}", rr);
 
@@ -416,7 +433,7 @@ pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
         SMB1_COMMAND_WRITE_ANDX |
         SMB1_COMMAND_WRITE |
         SMB1_COMMAND_WRITE_AND_CLOSE => {
-            smb1_write_request_record(state, r);
+            smb1_write_request_record(state, r, *andx_offset, command);
             true // tx handling in func
         },
         SMB1_COMMAND_TRANS => {
@@ -469,7 +486,7 @@ pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
             }
         },
         SMB1_COMMAND_NT_CREATE_ANDX => {
-            match parse_smb_create_andx_request_record(r.data, r) {
+            match parse_smb_create_andx_request_record(&r.data[*andx_offset-SMB1_HEADER_SIZE..], r) {
                 Ok((_, cr)) => {
                     SCLogDebug!("Create AndX {:?}", cr);
                     let del = cr.create_options & 0x0000_1000 != 0;
@@ -483,7 +500,7 @@ pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
                     let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX);
                     let tx = state.new_create_tx(&cr.file_name.to_vec(),
                             cr.disposition, del, dir, tx_hdr);
-                    tx.vercmd.set_smb1_cmd(r.command);
+                    tx.vercmd.set_smb1_cmd(command);
                     SCLogDebug!("TS CREATE TX {} created", tx.id);
                     true
                 },
@@ -495,12 +512,12 @@ pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
         },
         SMB1_COMMAND_SESSION_SETUP_ANDX => {
             SCLogDebug!("SMB1_COMMAND_SESSION_SETUP_ANDX user_id {}", r.user_id);
-            smb1_session_setup_request(state, r);
+            smb1_session_setup_request(state, r, *andx_offset);
             true
         },
         SMB1_COMMAND_TREE_CONNECT_ANDX => {
             SCLogDebug!("SMB1_COMMAND_TREE_CONNECT_ANDX");
-            match parse_smb_connect_tree_andx_record(r.data, r) {
+            match parse_smb_connect_tree_andx_record(&r.data[*andx_offset-SMB1_HEADER_SIZE..], r) {
                 Ok((_, tr)) => {
                     let name_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_TREE);
                     let mut name_val = tr.path;
@@ -550,36 +567,63 @@ pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
             false
         },
         _ => {
-            if r.command == SMB1_COMMAND_LOGOFF_ANDX ||
-               r.command == SMB1_COMMAND_TREE_DISCONNECT ||
-               r.command == SMB1_COMMAND_NT_TRANS ||
-               r.command == SMB1_COMMAND_NT_CANCEL ||
-               r.command == SMB1_COMMAND_RENAME ||
-               r.command == SMB1_COMMAND_CHECK_DIRECTORY ||
-               r.command == SMB1_COMMAND_ECHO ||
-               r.command == SMB1_COMMAND_TRANS
+            if command == SMB1_COMMAND_LOGOFF_ANDX ||
+               command == SMB1_COMMAND_TREE_DISCONNECT ||
+               command == SMB1_COMMAND_NT_TRANS ||
+               command == SMB1_COMMAND_NT_CANCEL ||
+               command == SMB1_COMMAND_RENAME ||
+               command == SMB1_COMMAND_CHECK_DIRECTORY ||
+               command == SMB1_COMMAND_ECHO ||
+               command == SMB1_COMMAND_TRANS
             { } else {
                  SCLogDebug!("unsupported command {}/{}",
-                         r.command, &smb1_command_string(r.command));
+                         command, &smb1_command_string(command));
             }
             false
         },
     };
     if !have_tx {
-        if smb1_create_new_tx(r.command) {
+        if smb1_create_new_tx(command) {
             let tx_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX);
-            let tx = state.new_generic_tx(1, r.command as u16, tx_key);
-            SCLogDebug!("tx {} created for {}/{}", tx.id, r.command, &smb1_command_string(r.command));
+            let tx = state.new_generic_tx(1, command as u16, tx_key);
+            SCLogDebug!("tx {} created for {}/{}", tx.id, command, &smb1_command_string(command));
             tx.set_events(events);
             if no_response_expected {
                 tx.response_done = true;
             }
         }
     }
+    return 0;
+}
+
+pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
+    SCLogDebug!("record: command {}: record {:?}", r.command, r);
+
+    let mut andx_offset = SMB1_HEADER_SIZE;
+    let mut command = r.command;
+    loop {
+        if smb1_request_record_one(state, r, command, &mut andx_offset) != 0 {
+             break;
+        }
+        // continue for next andx command if any
+        if smb1_command_is_andx(command) {
+            if let Ok((_, andx_hdr)) = smb1_parse_andx_header(&r.data[andx_offset-SMB1_HEADER_SIZE..]) {
+                if (andx_hdr.andx_offset as usize) > andx_offset &&
+                   andx_hdr.andx_command != SMB1_COMMAND_NONE &&
+                   (andx_hdr.andx_offset as usize) - SMB1_HEADER_SIZE < r.data.len() {
+                    andx_offset = andx_hdr.andx_offset as usize;
+                    command = andx_hdr.andx_command;
+                    continue;
+                }
+            }
+        }
+        break;
+    }
+
     0
 }
 
-pub fn smb1_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
+fn smb1_response_record_one<'b>(state: &mut SMBState, r: &SmbRecord<'b>, command: u8, andx_offset: &mut usize) -> u32 {
     SCLogDebug!("record: command {} status {} -> {:?}", r.command, r.nt_status, r);
 
     let key_ssn_id = r.ssn_id;
@@ -588,9 +632,9 @@ pub fn smb1_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32
     let mut tx_sync = false;
     let mut events : Vec<SMBEvent> = Vec::new();
 
-    let have_tx = match r.command {
+    let have_tx = match command {
         SMB1_COMMAND_READ_ANDX => {
-            smb1_read_response_record(state, &r);
+            smb1_read_response_record(state, &r, *andx_offset);
             true // tx handling in func
         },
         SMB1_COMMAND_NEGOTIATE_PROTOCOL => {
@@ -652,7 +696,7 @@ pub fn smb1_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32
                 return 0;
             }
 
-            match parse_smb_connect_tree_andx_response_record(r.data) {
+            match parse_smb_connect_tree_andx_response_record(&r.data[*andx_offset-SMB1_HEADER_SIZE..]) {
                 Ok((_, tr)) => {
                     let name_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_TREE);
                     let is_pipe = tr.service == "IPC".as_bytes();
@@ -696,7 +740,7 @@ pub fn smb1_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32
         SMB1_COMMAND_NT_CREATE_ANDX => {
             SCLogDebug!("SMB1_COMMAND_NT_CREATE_ANDX response {:08x}", r.nt_status);
             if r.nt_status == SMB_NTSTATUS_SUCCESS {
-                match parse_smb_create_andx_response_record(r.data) {
+                match parse_smb_create_andx_response_record(&r.data[*andx_offset-SMB1_HEADER_SIZE..]) {
                     Ok((_, cr)) => {
                         SCLogDebug!("Create AndX {:?}", cr);
 
@@ -717,9 +761,9 @@ pub fn smb1_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32
                         }
 
                         let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX);
-                        if let Some(tx) = state.get_generic_tx(1, r.command as u16, &tx_hdr) {
+                        if let Some(tx) = state.get_generic_tx(1, command as u16, &tx_hdr) {
                             SCLogDebug!("tx {} with {}/{} marked as done",
-                                    tx.id, r.command, &smb1_command_string(r.command));
+                                    tx.id, command, &smb1_command_string(command));
                             tx.set_status(r.nt_status, false);
                             tx.response_done = true;
 
@@ -748,7 +792,7 @@ pub fn smb1_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32
             true
         },
         SMB1_COMMAND_SESSION_SETUP_ANDX => {
-            smb1_session_setup_response(state, r);
+            smb1_session_setup_response(state, r, *andx_offset);
             true
         },
         SMB1_COMMAND_LOGOFF_ANDX => {
@@ -761,24 +805,24 @@ pub fn smb1_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32
     };
 
     if !have_tx && tx_sync {
-        match state.get_last_tx(1, r.command as u16) {
+        match state.get_last_tx(1, command as u16) {
             Some(tx) => {
-                SCLogDebug!("last TX {} is CMD {}", tx.id, &smb1_command_string(r.command));
+                SCLogDebug!("last TX {} is CMD {}", tx.id, &smb1_command_string(command));
                 tx.response_done = true;
-                SCLogDebug!("tx {} cmd {} is done", tx.id, r.command);
+                SCLogDebug!("tx {} cmd {} is done", tx.id, command);
                 tx.set_status(r.nt_status, r.is_dos_error);
                 tx.set_events(events);
             },
             _ => {},
         }
-    } else if !have_tx && smb1_check_tx(r.command) {
+    } else if !have_tx && smb1_check_tx(command) {
         let tx_key = SMBCommonHdr::new(SMBHDR_TYPE_GENERICTX,
                 key_ssn_id as u64, key_tree_id as u32, key_multiplex_id as u64);
-        let _have_tx2 = match state.get_generic_tx(1, r.command as u16, &tx_key) {
+        let _have_tx2 = match state.get_generic_tx(1, command as u16, &tx_key) {
             Some(tx) => {
                 tx.request_done = true;
                 tx.response_done = true;
-                SCLogDebug!("tx {} cmd {} is done", tx.id, r.command);
+                SCLogDebug!("tx {} cmd {} is done", tx.id, command);
                 tx.set_status(r.nt_status, r.is_dos_error);
                 tx.set_events(events);
                 true
@@ -789,8 +833,35 @@ pub fn smb1_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32
             },
         };
     } else {
-        SCLogDebug!("have tx for cmd {}", r.command);
+        SCLogDebug!("have tx for cmd {}", command);
+    }
+
+    return 0;
+}
+
+pub fn smb1_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
+    let mut andx_offset = SMB1_HEADER_SIZE;
+    let mut command = r.command;
+    loop {
+        if smb1_response_record_one(state, r, command, &mut andx_offset) != 0 {
+            break;
+        }
+
+        // continue for next andx command if any
+        if smb1_command_is_andx(command) {
+            if let Ok((_, andx_hdr)) = smb1_parse_andx_header(&r.data[andx_offset-SMB1_HEADER_SIZE..]) {
+                if (andx_hdr.andx_offset as usize) > andx_offset &&
+                    andx_hdr.andx_command != SMB1_COMMAND_NONE &&
+                    (andx_hdr.andx_offset as usize) - SMB1_HEADER_SIZE < r.data.len() {
+                    andx_offset = andx_hdr.andx_offset as usize;
+                    command = andx_hdr.andx_command;
+                    continue;
+                }
+            }
+        }
+        break;
     }
+
     0
 }
 
@@ -882,13 +953,13 @@ pub fn smb1_trans_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
 }
 
 /// Handle WRITE, WRITE_ANDX, WRITE_AND_CLOSE request records
-pub fn smb1_write_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
+pub fn smb1_write_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>, andx_offset: usize, command: u8)
 {
     let mut events : Vec<SMBEvent> = Vec::new();
 
-    let result = if r.command == SMB1_COMMAND_WRITE_ANDX {
-        parse_smb1_write_andx_request_record(r.data)
-    } else if r.command == SMB1_COMMAND_WRITE {
+    let result = if command == SMB1_COMMAND_WRITE_ANDX {
+        parse_smb1_write_andx_request_record(&r.data[andx_offset-SMB1_HEADER_SIZE..], andx_offset)
+    } else if command == SMB1_COMMAND_WRITE {
         parse_smb1_write_request_record(r.data)
     } else {
         parse_smb1_write_and_close_request_record(r.data)
@@ -932,7 +1003,7 @@ pub fn smb1_write_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
                 if is_pipe {
                     SCLogDebug!("SMBv1 WRITE TO PIPE");
                     let hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER);
-                    let vercmd = SMBVerCmdStat::new1_with_ntstatus(r.command, r.nt_status);
+                    let vercmd = SMBVerCmdStat::new1_with_ntstatus(command, r.nt_status);
                     smb_write_dcerpc_record(state, vercmd, hdr, &rd.data);
                 } else {
                     let (tx, files, flags) = state.new_file_tx(&file_fid, &file_name, STREAM_TOSERVER);
@@ -956,7 +1027,7 @@ pub fn smb1_write_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
 
             state.set_file_left(STREAM_TOSERVER, rd.len, rd.data.len() as u32, file_fid.to_vec());
 
-            if r.command == SMB1_COMMAND_WRITE_AND_CLOSE {
+            if command == SMB1_COMMAND_WRITE_AND_CLOSE {
                 SCLogDebug!("closing FID {:?}", file_fid);
                 smb1_close_file(state, &file_fid);
             }
@@ -968,12 +1039,12 @@ pub fn smb1_write_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
     smb1_request_record_generic(state, r, events);
 }
 
-pub fn smb1_read_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
+pub fn smb1_read_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>, andx_offset: usize)
 {
     let mut events : Vec<SMBEvent> = Vec::new();
 
     if r.nt_status == SMB_NTSTATUS_SUCCESS {
-        match parse_smb_read_andx_response_record(r.data) {
+        match parse_smb_read_andx_response_record(&r.data[andx_offset-SMB1_HEADER_SIZE..]) {
             Ok((_, rd)) => {
                 SCLogDebug!("SMBv1: read response => {:?}", rd);
 
@@ -1037,7 +1108,7 @@ pub fn smb1_read_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
                 } else {
                     SCLogDebug!("SMBv1 READ response from PIPE");
                     let hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER);
-                    let vercmd = SMBVerCmdStat::new1(r.command);
+                    let vercmd = SMBVerCmdStat::new1(SMB1_COMMAND_READ_ANDX);
 
                     // hack: we store fid with ssn id mixed in, but here we want the
                     // real thing instead.
index 2112304c5c1e95259ef4f2fda006902b4f614f9c..760daba00d6fb9ce4150b8b38b6cbd087340ca67 100644 (file)
@@ -22,6 +22,8 @@ use nom::number::streaming::{le_u8, le_u16, le_u32, le_u64};
 use crate::smb::smb::*;
 use crate::smb::smb_records::*;
 
+pub const SMB1_HEADER_SIZE: usize = 32;
+
 fn smb_get_unicode_string_with_offset(i: &[u8], offset: usize) -> IResult<&[u8], Vec<u8>, SmbError>
 {
     do_parse!(i,
@@ -40,6 +42,28 @@ pub fn smb1_get_string<'a>(i: &'a[u8], r: &SmbRecord, offset: usize) -> IResult<
     }
 }
 
+
+#[derive(Debug,PartialEq)]
+pub struct SmbParamBlockAndXHeader {
+    pub wct: u8,
+    pub andx_command: u8,
+    pub andx_offset: u16,
+}
+
+named!(pub smb1_parse_andx_header<SmbParamBlockAndXHeader>,
+    do_parse!(
+            wct: le_u8
+        >>  andx_command: le_u8
+        >>  take!(1)    // reserved
+        >>  andx_offset: le_u16
+        >>  (SmbParamBlockAndXHeader {
+                wct: wct,
+                andx_command: andx_command,
+                andx_offset: andx_offset,
+            }))
+
+);
+
 #[derive(Debug,PartialEq)]
 pub struct Smb1WriteRequestRecord<'a> {
     pub offset: u64,
@@ -67,8 +91,9 @@ named!(pub parse_smb1_write_request_record<Smb1WriteRequestRecord>,
             }))
 );
 
-named!(pub parse_smb1_write_andx_request_record<Smb1WriteRequestRecord>,
-    do_parse!(
+pub fn parse_smb1_write_andx_request_record(i : &[u8], andx_offset: usize) -> IResult<&[u8], Smb1WriteRequestRecord> {
+    let ax = andx_offset as u16;
+    do_parse!(i,
             wct: le_u8
         >>  _andx_command: le_u8
         >>  take!(1)    // reserved
@@ -85,7 +110,7 @@ named!(pub parse_smb1_write_andx_request_record<Smb1WriteRequestRecord>,
         >>  bcc: le_u16
         //spec [MS-CIFS].pdf says always take one byte padding
         >>  _padding: cond!(bcc > data_len_low, take!(bcc - data_len_low)) // TODO figure out how this works with data_len_high
-        >>  _padding_evasion: cond!(data_offset > 36+2*(wct as u16), take!(data_offset - (36+2*(wct as u16))))
+        >>  _padding_evasion: cond!(data_offset > ax+4+2*(wct as u16), take!(data_offset - (ax+4+2*(wct as u16))))
         >>  file_data: rest
         >> (Smb1WriteRequestRecord {
                 offset: if high_offset != None { ((high_offset.unwrap() as u64) << 32)|(offset as u64) } else { 0 },
@@ -93,7 +118,7 @@ named!(pub parse_smb1_write_andx_request_record<Smb1WriteRequestRecord>,
                 fid,
                 data:file_data,
             }))
-);
+}
 
 named!(pub parse_smb1_write_and_close_request_record<Smb1WriteRequestRecord>,
     do_parse!(
index 8c9b123974dedc581f241937c5c1e53a46a01756..ad3f330fdaf1bc196bd7965feb1aa6761f60f56e 100644 (file)
@@ -123,10 +123,10 @@ pub fn smb1_session_setup_response_host_info(r: &SmbRecord, blob: &[u8]) -> Sess
     }
 }
 
-pub fn smb1_session_setup_request(state: &mut SMBState, r: &SmbRecord)
+pub fn smb1_session_setup_request(state: &mut SMBState, r: &SmbRecord, andx_offset: usize)
 {
     SCLogDebug!("SMB1_COMMAND_SESSION_SETUP_ANDX user_id {}", r.user_id);
-    match parse_smb_setup_andx_record(r.data) {
+    match parse_smb_setup_andx_record(&r.data[andx_offset-SMB1_HEADER_SIZE..]) {
         Ok((rem, setup)) => {
             let hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER,
                     r.ssn_id as u64, 0, r.multiplex_id as u64);
@@ -150,9 +150,9 @@ pub fn smb1_session_setup_request(state: &mut SMBState, r: &SmbRecord)
     }
 }
 
-fn smb1_session_setup_update_tx(tx: &mut SMBTransaction, r: &SmbRecord)
+fn smb1_session_setup_update_tx(tx: &mut SMBTransaction, r: &SmbRecord, andx_offset: usize)
 {
-    match parse_smb_response_setup_andx_record(r.data) {
+    match parse_smb_response_setup_andx_record(&r.data[andx_offset-SMB1_HEADER_SIZE..]) {
         Ok((rem, _setup)) => {
             if let Some(SMBTransactionTypeData::SESSIONSETUP(ref mut td)) = tx.type_data {
                 td.response_host = Some(smb1_session_setup_response_host_info(r, rem));
@@ -168,7 +168,7 @@ fn smb1_session_setup_update_tx(tx: &mut SMBTransaction, r: &SmbRecord)
     tx.response_done = true;
 }
 
-pub fn smb1_session_setup_response(state: &mut SMBState, r: &SmbRecord)
+pub fn smb1_session_setup_response(state: &mut SMBState, r: &SmbRecord, andx_offset: usize)
 {
     // try exact match with session id already set (e.g. NTLMSSP AUTH phase)
     let found = r.ssn_id != 0 && match state.get_sessionsetup_tx(
@@ -176,7 +176,7 @@ pub fn smb1_session_setup_response(state: &mut SMBState, r: &SmbRecord)
                     r.ssn_id as u64, 0, r.multiplex_id as u64))
     {
         Some(tx) => {
-            smb1_session_setup_update_tx(tx, r);
+            smb1_session_setup_update_tx(tx, r, andx_offset);
             SCLogDebug!("smb1_session_setup_response: tx {:?}", tx);
             true
         },
@@ -188,7 +188,7 @@ pub fn smb1_session_setup_response(state: &mut SMBState, r: &SmbRecord)
                 SMBCommonHdr::new(SMBHDR_TYPE_HEADER, 0, 0, r.multiplex_id as u64))
         {
             Some(tx) => {
-                smb1_session_setup_update_tx(tx, r);
+                smb1_session_setup_update_tx(tx, r, andx_offset);
                 SCLogDebug!("smb1_session_setup_response: tx {:?}", tx);
             },
             None => {