|
|
|
@ -164,8 +164,7 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema
|
|
|
|
|
|
|
|
|
|
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_with_open_file(&file_guid, Direction::ToClient) {
|
|
|
|
|
Some(tx) => {
|
|
|
|
|
let found = if let Some(tx) = state.get_file_tx_by_fuid_with_open_file(&file_guid, Direction::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 {
|
|
|
|
@ -184,8 +183,8 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
true
|
|
|
|
|
},
|
|
|
|
|
None => { false },
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
};
|
|
|
|
|
SCLogDebug!("existing file tx? {}", found);
|
|
|
|
|
if !found {
|
|
|
|
@ -309,8 +308,7 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let mut set_event_fileoverlap = false;
|
|
|
|
|
let found = match state.get_file_tx_by_fuid_with_open_file(&file_guid, Direction::ToServer) {
|
|
|
|
|
Some(tx) => {
|
|
|
|
|
let found = if let Some(tx) = state.get_file_tx_by_fuid_with_open_file(&file_guid, Direction::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 {
|
|
|
|
@ -329,8 +327,8 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
true
|
|
|
|
|
},
|
|
|
|
|
None => { false },
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
};
|
|
|
|
|
if !found {
|
|
|
|
|
let tree_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_SHARE);
|
|
|
|
@ -490,8 +488,7 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
SMB2_COMMAND_NEGOTIATE_PROTOCOL => {
|
|
|
|
|
match parse_smb2_request_negotiate_protocol(r.data) {
|
|
|
|
|
Ok((_, rd)) => {
|
|
|
|
|
if let Ok((_, rd)) = parse_smb2_request_negotiate_protocol(r.data) {
|
|
|
|
|
let mut dialects : Vec<Vec<u8>> = Vec::new();
|
|
|
|
|
for d in rd.dialects_vec {
|
|
|
|
|
SCLogDebug!("dialect {:x} => {}", d, &smb2_dialect_string(d));
|
|
|
|
@ -499,14 +496,7 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
dialects.push(dvec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let found = match state.get_negotiate_tx(2) {
|
|
|
|
|
Some(_) => {
|
|
|
|
|
SCLogDebug!("WEIRD, should not have NEGOTIATE tx!");
|
|
|
|
|
true
|
|
|
|
|
},
|
|
|
|
|
None => { false },
|
|
|
|
|
};
|
|
|
|
|
if !found {
|
|
|
|
|
if state.get_negotiate_tx(2).is_none() {
|
|
|
|
|
let tx = state.new_negotiate_tx(2);
|
|
|
|
|
if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = tx.type_data {
|
|
|
|
|
tdn.dialects2 = dialects;
|
|
|
|
@ -515,11 +505,9 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
tx.request_done = true;
|
|
|
|
|
}
|
|
|
|
|
true
|
|
|
|
|
},
|
|
|
|
|
_ => {
|
|
|
|
|
} else {
|
|
|
|
|
events.push(SMBEvent::MalformedData);
|
|
|
|
|
false
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
SMB2_COMMAND_SESSION_SETUP => {
|
|
|
|
@ -527,8 +515,7 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
true
|
|
|
|
|
},
|
|
|
|
|
SMB2_COMMAND_TREE_CONNECT => {
|
|
|
|
|
match parse_smb2_request_tree_connect(r.data) {
|
|
|
|
|
Ok((_, tr)) => {
|
|
|
|
|
if let Ok((_, tr)) = parse_smb2_request_tree_connect(r.data) {
|
|
|
|
|
let name_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_TREE);
|
|
|
|
|
let mut name_val = tr.share_name.to_vec();
|
|
|
|
|
name_val.retain(|&i|i != 0x00);
|
|
|
|
@ -540,16 +527,13 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
tx.request_done = true;
|
|
|
|
|
tx.vercmd.set_smb2_cmd(SMB2_COMMAND_TREE_CONNECT);
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
} else {
|
|
|
|
|
events.push(SMBEvent::MalformedData);
|
|
|
|
|
false
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
SMB2_COMMAND_READ => {
|
|
|
|
|
match parse_smb2_request_read(r.data) {
|
|
|
|
|
Ok((_, rd)) => {
|
|
|
|
|
if let Ok((_, rd)) = parse_smb2_request_read(r.data) {
|
|
|
|
|
if (state.max_read_size != 0 && rd.rd_len > state.max_read_size) ||
|
|
|
|
|
(unsafe { SMB_CFG_MAX_READ_SIZE != 0 && SMB_CFG_MAX_READ_SIZE < rd.rd_len }) {
|
|
|
|
|
events.push(SMBEvent::ReadRequestTooLarge);
|
|
|
|
@ -562,35 +546,28 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
let guidoff = SMBFileGUIDOffset::new(rd.guid.to_vec(), rd.rd_offset);
|
|
|
|
|
state.ssn2vecoffset_map.insert(guid_key, guidoff);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
_ => {
|
|
|
|
|
} else {
|
|
|
|
|
events.push(SMBEvent::MalformedData);
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
false
|
|
|
|
|
},
|
|
|
|
|
SMB2_COMMAND_CREATE => {
|
|
|
|
|
match parse_smb2_request_create(r.data) {
|
|
|
|
|
Ok((_, cr)) => {
|
|
|
|
|
if let Ok((_, cr)) = parse_smb2_request_create(r.data) {
|
|
|
|
|
let del = cr.create_options & 0x0000_1000 != 0;
|
|
|
|
|
let dir = cr.create_options & 0x0000_0001 != 0;
|
|
|
|
|
|
|
|
|
|
SCLogDebug!("create_options {:08x}", cr.create_options);
|
|
|
|
|
|
|
|
|
|
let name_key = SMBCommonHdr::from2_notree(r, SMBHDR_TYPE_FILENAME);
|
|
|
|
|
state.ssn2vec_map.insert(name_key, cr.data.to_vec());
|
|
|
|
|
|
|
|
|
|
let tx_hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX);
|
|
|
|
|
let tx = state.new_create_tx(cr.data,
|
|
|
|
|
cr.disposition, del, dir, tx_hdr);
|
|
|
|
|
let tx = state.new_create_tx(cr.data, cr.disposition, del, dir, tx_hdr);
|
|
|
|
|
tx.vercmd.set_smb2_cmd(r.command);
|
|
|
|
|
SCLogDebug!("TS CREATE TX {} created", tx.id);
|
|
|
|
|
true
|
|
|
|
|
},
|
|
|
|
|
_ => {
|
|
|
|
|
} else {
|
|
|
|
|
events.push(SMBEvent::MalformedData);
|
|
|
|
|
false
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
SMB2_COMMAND_WRITE => {
|
|
|
|
@ -598,10 +575,8 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
true // write handling creates both file tx and generic tx
|
|
|
|
|
},
|
|
|
|
|
SMB2_COMMAND_CLOSE => {
|
|
|
|
|
match parse_smb2_request_close(r.data) {
|
|
|
|
|
Ok((_, cd)) => {
|
|
|
|
|
let found_ts = match state.get_file_tx_by_fuid(cd.guid, Direction::ToServer) {
|
|
|
|
|
Some(tx) => {
|
|
|
|
|
if let Ok((_, cd)) = parse_smb2_request_close(r.data) {
|
|
|
|
|
let found_ts = if let Some(tx) = state.get_file_tx_by_fuid(cd.guid, Direction::ToServer) {
|
|
|
|
|
if !tx.request_done {
|
|
|
|
|
if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
|
|
|
|
|
filetracker_close(&mut tdf.file_tracker);
|
|
|
|
@ -611,11 +586,10 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
tx.response_done = true;
|
|
|
|
|
tx.set_status(SMB_NTSTATUS_SUCCESS, false);
|
|
|
|
|
true
|
|
|
|
|
},
|
|
|
|
|
None => { false },
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
};
|
|
|
|
|
let found_tc = match state.get_file_tx_by_fuid(cd.guid, Direction::ToClient) {
|
|
|
|
|
Some(tx) => {
|
|
|
|
|
let found_tc = if let Some(tx) = state.get_file_tx_by_fuid(cd.guid, Direction::ToClient) {
|
|
|
|
|
if !tx.request_done {
|
|
|
|
|
if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
|
|
|
|
|
filetracker_close(&mut tdf.file_tracker);
|
|
|
|
@ -625,16 +599,14 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
tx.response_done = true;
|
|
|
|
|
tx.set_status(SMB_NTSTATUS_SUCCESS, false);
|
|
|
|
|
true
|
|
|
|
|
},
|
|
|
|
|
None => { false },
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
};
|
|
|
|
|
if !found_ts && !found_tc {
|
|
|
|
|
SCLogDebug!("SMBv2: CLOSE(TS): no TX at GUID {:?}", cd.guid);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
_ => {
|
|
|
|
|
} else {
|
|
|
|
|
events.push(SMBEvent::MalformedData);
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
false
|
|
|
|
|
},
|
|
|
|
@ -671,9 +643,7 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
},
|
|
|
|
|
SMB2_COMMAND_WRITE => {
|
|
|
|
|
if r.nt_status == SMB_NTSTATUS_SUCCESS {
|
|
|
|
|
match parse_smb2_response_write(r.data)
|
|
|
|
|
{
|
|
|
|
|
Ok((_, _wr)) => {
|
|
|
|
|
if let Ok((_, _wr)) = parse_smb2_response_write(r.data) {
|
|
|
|
|
SCLogDebug!("SMBv2: Write response => {:?}", _wr);
|
|
|
|
|
|
|
|
|
|
/* search key-guid map */
|
|
|
|
@ -681,10 +651,8 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
r.session_id, r.tree_id, r.message_id);
|
|
|
|
|
let _guid_vec = state.ssn2vec_map.remove(&guid_key).unwrap_or_default();
|
|
|
|
|
SCLogDebug!("SMBv2 write response for GUID {:?}", _guid_vec);
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
} else {
|
|
|
|
|
events.push(SMBEvent::MalformedData);
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
false // the request may have created a generic tx, so handle that here
|
|
|
|
@ -693,21 +661,17 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
if r.nt_status == SMB_NTSTATUS_SUCCESS ||
|
|
|
|
|
r.nt_status == SMB_NTSTATUS_BUFFER_OVERFLOW {
|
|
|
|
|
smb2_read_response_record(state, r, 0);
|
|
|
|
|
false
|
|
|
|
|
|
|
|
|
|
} else if r.nt_status == SMB_NTSTATUS_END_OF_FILE {
|
|
|
|
|
SCLogDebug!("SMBv2: read response => EOF");
|
|
|
|
|
|
|
|
|
|
let guid_key = SMBCommonHdr::from2_notree(r, SMBHDR_TYPE_OFFSET);
|
|
|
|
|
let file_guid = match state.ssn2vecoffset_map.remove(&guid_key) {
|
|
|
|
|
Some(o) => o.guid,
|
|
|
|
|
_ => {
|
|
|
|
|
let file_guid = if let Some(o) = state.ssn2vecoffset_map.remove(&guid_key) {
|
|
|
|
|
o.guid
|
|
|
|
|
} else {
|
|
|
|
|
SCLogDebug!("SMBv2 READ response: reply to unknown request");
|
|
|
|
|
Vec::new()
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
let found = match state.get_file_tx_by_fuid(&file_guid, Direction::ToClient) {
|
|
|
|
|
Some(tx) => {
|
|
|
|
|
if let Some(tx) = state.get_file_tx_by_fuid(&file_guid, Direction::ToClient) {
|
|
|
|
|
if !tx.request_done {
|
|
|
|
|
if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
|
|
|
|
|
filetracker_close(&mut tdf.file_tracker);
|
|
|
|
@ -715,23 +679,15 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
}
|
|
|
|
|
tx.set_status(r.nt_status, false);
|
|
|
|
|
tx.request_done = true;
|
|
|
|
|
false
|
|
|
|
|
},
|
|
|
|
|
None => { false },
|
|
|
|
|
};
|
|
|
|
|
if !found {
|
|
|
|
|
SCLogDebug!("SMBv2 READ: no TX at GUID {:?}", file_guid);
|
|
|
|
|
}
|
|
|
|
|
false
|
|
|
|
|
} else {
|
|
|
|
|
SCLogDebug!("SMBv2 READ: status {}", r.nt_status);
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
false
|
|
|
|
|
},
|
|
|
|
|
SMB2_COMMAND_CREATE => {
|
|
|
|
|
if r.nt_status == SMB_NTSTATUS_SUCCESS {
|
|
|
|
|
match parse_smb2_response_create(r.data) {
|
|
|
|
|
Ok((_, cr)) => {
|
|
|
|
|
if let Ok((_, cr)) = parse_smb2_response_create(r.data) {
|
|
|
|
|
SCLogDebug!("SMBv2: Create response => {:?}", cr);
|
|
|
|
|
|
|
|
|
|
let guid_key = SMBCommonHdr::from2_notree(r, SMBHDR_TYPE_FILENAME);
|
|
|
|
@ -758,10 +714,8 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
tdn.guid = cr.guid.to_vec();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
} else {
|
|
|
|
|
events.push(SMBEvent::MalformedData);
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
true
|
|
|
|
|
} else {
|
|
|
|
@ -777,8 +731,7 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
}
|
|
|
|
|
SMB2_COMMAND_TREE_CONNECT => {
|
|
|
|
|
if r.nt_status == SMB_NTSTATUS_SUCCESS {
|
|
|
|
|
match parse_smb2_response_tree_connect(r.data) {
|
|
|
|
|
Ok((_, tr)) => {
|
|
|
|
|
if let Ok((_, tr)) = parse_smb2_response_tree_connect(r.data) {
|
|
|
|
|
let name_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_TREE);
|
|
|
|
|
let mut share_name = Vec::new();
|
|
|
|
|
let is_pipe = tr.share_type == 2;
|
|
|
|
@ -804,23 +757,19 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
state.ssn2tree_map.insert(tree_key, tree);
|
|
|
|
|
}
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
} else {
|
|
|
|
|
events.push(SMBEvent::MalformedData);
|
|
|
|
|
false
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
let name_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_TREE);
|
|
|
|
|
let found = match state.get_treeconnect_tx(name_key) {
|
|
|
|
|
Some(tx) => {
|
|
|
|
|
if let Some(tx) = state.get_treeconnect_tx(name_key) {
|
|
|
|
|
tx.response_done = true;
|
|
|
|
|
tx.set_status(r.nt_status, false);
|
|
|
|
|
true
|
|
|
|
|
},
|
|
|
|
|
None => { false },
|
|
|
|
|
};
|
|
|
|
|
found
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
SMB2_COMMAND_NEGOTIATE_PROTOCOL => {
|
|
|
|
@ -829,8 +778,7 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
} else {
|
|
|
|
|
parse_smb2_response_negotiate_protocol_error(r.data)
|
|
|
|
|
};
|
|
|
|
|
match res {
|
|
|
|
|
Ok((_, rd)) => {
|
|
|
|
|
if let Ok((_, rd)) = res {
|
|
|
|
|
SCLogDebug!("SERVER dialect => {}", &smb2_dialect_string(rd.dialect));
|
|
|
|
|
|
|
|
|
|
let smb_cfg_max_read_size = unsafe { SMB_CFG_MAX_READ_SIZE };
|
|
|
|
@ -870,12 +818,10 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record)
|
|
|
|
|
None => { false },
|
|
|
|
|
};
|
|
|
|
|
found1 || found2
|
|
|
|
|
},
|
|
|
|
|
_ => {
|
|
|
|
|
} else {
|
|
|
|
|
events.push(SMBEvent::MalformedData);
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
_ => {
|
|
|
|
|
SCLogDebug!("default case: no TX");
|
|
|
|
|