smb: improve dcerpc logic

Detect whether a pipe is a dcerpc channel based on the name of the
pipe.
pull/3421/head
Victor Julien 7 years ago
parent 7c8a078a2c
commit 1b86d4e1a2

@ -574,10 +574,9 @@ pub const SMBHDR_TYPE_OFFSET: u32 = 4;
pub const SMBHDR_TYPE_GENERICTX: u32 = 5; pub const SMBHDR_TYPE_GENERICTX: u32 = 5;
pub const SMBHDR_TYPE_HEADER: u32 = 6; 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_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 = 8;
pub const SMBHDR_TYPE_TRANS_FRAG: u32 = 9; pub const SMBHDR_TYPE_TREE: u32 = 9;
pub const SMBHDR_TYPE_TREE: u32 = 10; pub const SMBHDR_TYPE_DCERPCTX: u32 = 10;
pub const SMBHDR_TYPE_DCERPCTX: u32 = 11;
#[derive(Hash, Eq, PartialEq, Debug)] #[derive(Hash, Eq, PartialEq, Debug)]
pub struct SMBCommonHdr { pub struct SMBCommonHdr {
@ -1044,13 +1043,19 @@ impl SMBState {
{ {
let (name, is_dcerpc) = match self.guid2name_map.get(&guid.to_vec()) { let (name, is_dcerpc) = match self.guid2name_map.get(&guid.to_vec()) {
Some(n) => { 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("PSEXESVC") => ("PSEXESVC", false),
Ok("svcctl") => ("svcctl", true), Ok("svcctl") => ("svcctl", true),
Ok("srvsvc") => ("srvsvc", true), Ok("srvsvc") => ("srvsvc", true),
Ok("atsvc") => ("atsvc", true), Ok("atsvc") => ("atsvc", true),
Ok("lsarpc") => ("lsarpc", true), Ok("lsarpc") => ("lsarpc", true),
Ok("samr") => ("samr", true), Ok("samr") => ("samr", true),
Ok("spoolss") => ("spoolss", true),
Err(_) => ("MALFORMED", false), Err(_) => ("MALFORMED", false),
Ok(&_) => { Ok(&_) => {
SCLogDebug!("don't know {}", String::from_utf8_lossy(&n)); SCLogDebug!("don't know {}", String::from_utf8_lossy(&n));

@ -20,7 +20,6 @@
*/ */
extern crate libc; extern crate libc;
use std::str;
use nom::{IResult}; use nom::{IResult};
@ -683,22 +682,6 @@ pub fn smb1_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32
0 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>) pub fn smb1_trans_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
{ {
let mut events : Vec<SMBEvent> = Vec::new(); 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); SCLogDebug!("TRANS request {:?}", rd);
/* if we have a fid, store it so the response can pick it up */ /* if we have a fid, store it so the response can pick it up */
let mut pipe_dcerpc = false;
if rd.pipe != None { if rd.pipe != None {
let pipe = rd.pipe.unwrap(); let pipe = rd.pipe.unwrap();
state.ssn2vec_map.insert(SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID), state.ssn2vec_map.insert(SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID),
pipe.fid.to_vec()); pipe.fid.to_vec());
}
let (sername, is_dcerpc) = get_service_for_nameslice(&rd.txname); let mut frankenfid = pipe.fid.to_vec();
SCLogDebug!("service: {} dcerpc {}", sername, is_dcerpc); frankenfid.extend_from_slice(&u32_as_bytes(r.ssn_id));
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 (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 // trans request will tell us the max size of the response
// if there is more response data, it will first give a // if there is more response data, it will first give a
// TRANS with 'max data cnt' worth of data, and the rest // 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); 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 // if we get status 'BUFFER_OVERFLOW' this is only a part of
// the data. Store it in the ssn/tree for later use. // the data. Store it in the ssn/tree for later use.
if r.nt_status == SMB_NTSTATUS_BUFFER_OVERFLOW { if r.nt_status == SMB_NTSTATUS_BUFFER_OVERFLOW {
state.ssnguid2vec_map.insert(SMBHashKeyHdrGuid::new( state.ssnguid2vec_map.insert(SMBHashKeyHdrGuid::new(
SMBCommonHdr::from1(r, SMBHDR_TYPE_TRANS_FRAG), fid), SMBCommonHdr::from1(r, SMBHDR_TYPE_TRANS_FRAG), fid),
rd.data.to_vec()); rd.data.to_vec());
} else { } else if is_dcerpc {
let txn_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_TXNAME); SCLogDebug!("SMBv1 TRANS TO PIPE");
let is_dcerpc = match state.ssn2vec_map.remove(&txn_hdr) { let hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER);
None => false, let vercmd = SMBVerCmdStat::new1_with_ntstatus(r.command, r.nt_status);
Some(s) => { smb_read_dcerpc_record(state, vercmd, hdr, &fid, &rd.data);
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);
}
} }
}, },
_ => { _ => {
events.push(SMBEvent::MalformedData); events.push(SMBEvent::MalformedData);
}, },
} }
// generic tx as well. Set events if needed. // generic tx as well. Set events if needed.

Loading…
Cancel
Save