IResult::Done(rem, d)
}
-fn parse_secblob_spnego(state: &mut SMBState, blob: &[u8])
+pub struct SpnegoRequest {
+ pub krb: Option<Kerberos5Ticket>,
+ pub ntlmssp: Option<NtlmsspData>,
+}
+
+fn parse_secblob_spnego(blob: &[u8]) -> Option<SpnegoRequest>
{
- let mut ntlmssp = false;
- let mut kerberos = false;
+ let mut have_ntlmssp = false;
+ let mut have_kerberos = false;
let mut kticket : Option<Kerberos5Ticket> = None;
+ let mut ntlmssp : Option<NtlmsspData> = None;
let o = match der_parser::parse_der_sequence(blob) {
IResult::Done(_, o) => o,
- _ => { return; },
+ _ => { return None; },
};
for s in o {
SCLogDebug!("s {:?}", s);
SCLogDebug!("OID {:?}", oid);
match oid.to_string().as_str() {
"1.2.840.48018.1.2.2" => { SCLogDebug!("Microsoft Kerberos 5"); },
- "1.2.840.113554.1.2.2" => { SCLogDebug!("Kerberos 5"); kerberos = true; },
+ "1.2.840.113554.1.2.2" => { SCLogDebug!("Kerberos 5"); have_kerberos = true; },
"1.2.840.113554.1.2.2.1" => { SCLogDebug!("krb5-name"); },
"1.2.840.113554.1.2.2.2" => { SCLogDebug!("krb5-principal"); },
"1.2.840.113554.1.2.2.3" => { SCLogDebug!("krb5-user-to-user-mech"); },
- "1.3.6.1.4.1.311.2.2.10" => { SCLogDebug!("NTLMSSP"); ntlmssp = true; },
+ "1.3.6.1.4.1.311.2.2.10" => { SCLogDebug!("NTLMSSP"); have_ntlmssp = true; },
"1.3.6.1.4.1.311.2.2.30" => { SCLogDebug!("NegoEx"); },
_ => { SCLogNotice!("unexpected OID {:?}", oid); },
}
}
},
der_parser::DerObjectContent::OctetString(ref os) => {
- if kerberos {
+ if have_kerberos {
match parse_kerberos5_request(os) {
IResult::Done(_, t) => {
kticket = Some(t)
}
}
- if ntlmssp && kticket == None {
+ if have_ntlmssp && kticket == None {
SCLogDebug!("parsing expected NTLMSSP");
- parse_ntlmssp_blob(state, os);
+ ntlmssp = parse_ntlmssp_blob(os);
}
},
_ => {},
}
}
- state.krb_ticket = kticket;
+ let s = SpnegoRequest {
+ krb: kticket,
+ ntlmssp: ntlmssp,
+ };
+ Some(s)
}
#[derive(Debug,PartialEq)]
pub host: Vec<u8>,
pub user: Vec<u8>,
pub domain: Vec<u8>,
+ pub version: Option<NTLMSSPVersion>,
}
/// take in blob, search for the header and parse it
-fn parse_ntlmssp_blob(state: &mut SMBState, blob: &[u8])
+fn parse_ntlmssp_blob(blob: &[u8]) -> Option<NtlmsspData>
{
+ let mut ntlmssp_data : Option<NtlmsspData> = None;
+
SCLogDebug!("NTLMSSP {:?}", blob);
match parse_ntlmssp(blob) {
IResult::Done(_, nd) => {
host: host,
user: user,
domain: domain,
+ version: ad.version,
};
- state.ntlmssp = Some(d);
+ ntlmssp_data = Some(d);
},
_ => {},
}
},
_ => {},
}
+ return ntlmssp_data;
}
// if spnego parsing fails try to fall back to ntlmssp
-pub fn parse_secblob(state: &mut SMBState, blob: &[u8])
+pub fn parse_secblob(blob: &[u8]) -> Option<SpnegoRequest>
{
match parse_secblob_get_spnego(blob) {
IResult::Done(_, spnego) => {
match parse_secblob_spnego_start(spnego) {
IResult::Done(_, spnego_start) => {
- parse_secblob_spnego(state, spnego_start);
+ parse_secblob_spnego(spnego_start)
},
_ => {
- parse_ntlmssp_blob(state, blob);
+ match parse_ntlmssp_blob(blob) {
+ Some(n) => {
+ let s = SpnegoRequest {
+ krb: None,
+ ntlmssp: Some(n),
+ };
+ Some(s)
+ },
+ None => { None },
+ }
},
}
},
_ => {
- parse_ntlmssp_blob(state, blob);
+ match parse_ntlmssp_blob(blob) {
+ Some(n) => {
+ let s = SpnegoRequest {
+ krb: None,
+ ntlmssp: Some(n),
+ };
+ Some(s)
+ },
+ None => { None },
+ }
},
}
}
js.set_boolean("request_done", tx.request_done);
js.set_boolean("response_done", tx.request_done);
+ match tx.type_data {
+ Some(SMBTransactionTypeData::SESSIONSETUP(ref x)) => {
+ if let Some(ref ntlmssp) = x.ntlmssp {
+ let jsd = Json::object();
+ let domain = match str::from_utf8(&ntlmssp.domain) {
+ Ok(v) => v,
+ Err(_) => "UTF8_ERROR",
+ };
+ jsd.set_string("domain", &domain);
- match state.ntlmssp {
- Some(ref ntlmssp) => {
- let jsd = Json::object();
- let domain = match str::from_utf8(&ntlmssp.domain) {
- Ok(v) => v,
- Err(_) => "UTF8_ERROR",
- };
- jsd.set_string("domain", &domain);
+ let user = match str::from_utf8(&ntlmssp.user) {
+ Ok(v) => v,
+ Err(_) => "UTF8_ERROR",
+ };
+ jsd.set_string("user", &user);
- let user = match str::from_utf8(&ntlmssp.user) {
- Ok(v) => v,
- Err(_) => "UTF8_ERROR",
- };
- jsd.set_string("user", &user);
+ let host = match str::from_utf8(&ntlmssp.host) {
+ Ok(v) => v,
+ Err(_) => "UTF8_ERROR",
+ };
+ jsd.set_string("host", &host);
- let host = match str::from_utf8(&ntlmssp.host) {
- Ok(v) => v,
- Err(_) => "UTF8_ERROR",
- };
- jsd.set_string("host", &host);
- js.set("ntlmssp", jsd);
- }
- None => {},
- }
+ if let Some(ref v) = ntlmssp.version {
+ jsd.set_string("version", v.to_string().as_str());
+ }
- match state.krb_ticket {
- Some(ref ticket) => {
- let jsd = Json::object();
- let realm = match str::from_utf8(&ticket.realm) {
- Ok(v) => v,
- Err(_) => "UTF8_ERROR",
- };
- jsd.set_string("realm", &realm);
- let jsa = Json::array();
- for sname in &ticket.snames {
- let name = match str::from_utf8(&sname) {
+ js.set("ntlmssp", jsd);
+ }
+
+ if let Some(ref ticket) = x.krb_ticket {
+ let jsd = Json::object();
+ let realm = match str::from_utf8(&ticket.realm) {
Ok(v) => v,
Err(_) => "UTF8_ERROR",
};
- jsa.array_append_string(&name);
+ jsd.set_string("realm", &realm);
+ let jsa = Json::array();
+ for sname in &ticket.snames {
+ let name = match str::from_utf8(&sname) {
+ Ok(v) => v,
+ Err(_) => "UTF8_ERROR",
+ };
+ jsa.array_append_string(&name);
+ }
+ jsd.set("snames", jsa);
+ js.set("kerberos", jsd);
}
- jsd.set("snames", jsa);
- js.set("kerberos", jsd);
- },
- None => { },
- }
- match tx.type_data {
+ match x.request_host {
+ Some(ref r) => {
+ let jsd = Json::object();
+ let os = match str::from_utf8(&r.native_os) {
+ Ok(v) => v,
+ Err(_) => "UTF8_ERROR",
+ };
+ jsd.set_string("native_os", &os);
+ let lm = match str::from_utf8(&r.native_lm) {
+ Ok(v) => v,
+ Err(_) => "UTF8_ERROR",
+ };
+ jsd.set_string("native_lm", &lm);
+ js.set("request", jsd);
+ },
+ None => { },
+ }
+ match x.response_host {
+ Some(ref r) => {
+ let jsd = Json::object();
+ let os = match str::from_utf8(&r.native_os) {
+ Ok(v) => v,
+ Err(_) => "UTF8_ERROR",
+ };
+ jsd.set_string("native_os", &os);
+ let lm = match str::from_utf8(&r.native_lm) {
+ Ok(v) => v,
+ Err(_) => "UTF8_ERROR",
+ };
+ jsd.set_string("native_lm", &lm);
+ js.set("response", jsd);
+ },
+ None => { },
+ }
+ },
Some(SMBTransactionTypeData::CREATE(ref x)) => {
let mut name_raw = x.filename.to_vec();
name_raw.retain(|&i|i != 0x00);
pub mod smb;
pub mod smb1;
+pub mod smb1_session;
pub mod smb2;
+pub mod smb2_session;
pub mod dcerpc;
+pub mod session;
pub mod log;
pub mod detect;
pub mod debug;
* 02110-1301, USA.
*/
-use nom::{rest, le_u16, le_u32};
+use nom::{rest, le_u8, le_u16, le_u32};
+
+#[derive(Debug,PartialEq)]
+pub struct NTLMSSPVersion {
+ pub ver_major: u8,
+ pub ver_minor: u8,
+ pub ver_build: u16,
+ pub ver_ntlm_rev: u8,
+}
+
+impl NTLMSSPVersion {
+ pub fn to_string(&self) -> String {
+ format!("{}.{} build {} rev {}",
+ self.ver_major, self.ver_minor,
+ self.ver_build, self.ver_ntlm_rev)
+ }
+}
+
+named!(parse_ntlm_auth_version<NTLMSSPVersion>,
+ do_parse!(
+ ver_major: le_u8
+ >> ver_minor: le_u8
+ >> ver_build: le_u16
+ >> take!(3)
+ >> ver_ntlm_rev: le_u8
+ >> ( NTLMSSPVersion {
+ ver_major: ver_major,
+ ver_minor: ver_minor,
+ ver_build: ver_build,
+ ver_ntlm_rev: ver_ntlm_rev,
+ })
+));
#[derive(Debug,PartialEq)]
pub struct NTLMSSPAuthRecord<'a> {
pub domain: &'a[u8],
pub user: &'a[u8],
pub host: &'a[u8],
+ pub version: Option<NTLMSSPVersion>,
}
named!(pub parse_ntlm_auth_record<NTLMSSPAuthRecord>,
- dbg_dmp!(do_parse!(
+ do_parse!(
lm_blob_len: le_u16
>> lm_blob_maxlen: le_u16
>> lm_blob_offset: le_u32
>> ssnkey_blob_maxlen: le_u16
>> ssnkey_blob_offset: le_u32
+ >> nego_flags: bits!(tuple!(take_bits!(u8, 6),take_bits!(u8,1),take_bits!(u32,25)))
+ >> version: cond!(nego_flags.1==1, parse_ntlm_auth_version)
+
// subtrack 12 as idenfier (8) and type (4) are cut before we are called
- // subtract 48 for the len/offset/maxlen fields above
- >> take!(domain_blob_offset - (12 + 48))
+ // subtract 60 for the len/offset/maxlen fields above
+ >> cond!(nego_flags.1==1, take!(domain_blob_offset - (12 + 60)))
+ // or 52 if we have no version
+ >> cond!(nego_flags.1==0, take!(domain_blob_offset - (12 + 52)))
- //>> lm_blob: take!(lm_blob_len)
- //>> ntlmresp_blob: take!(ntlmresp_blob_len)
>> domain_blob: take!(domain_blob_len)
>> user_blob: take!(user_blob_len)
>> host_blob: take!(host_blob_len)
domain: domain_blob,
user: user_blob,
host: host_blob,
+
+ version: version,
})
-)));
+));
#[derive(Debug,PartialEq)]
pub struct NTLMSSPRecord<'a> {
--- /dev/null
+/* Copyright (C) 2018 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+use log::*;
+
+use smb::smb::*;
+use smb::smb1_session::*;
+use smb::auth::*;
+
+#[derive(Debug)]
+pub struct SMBTransactionSessionSetup {
+ pub request_host: Option<SessionSetupRequest>,
+ pub response_host: Option<SessionSetupResponse>,
+ pub ntlmssp: Option<NtlmsspData>,
+ pub krb_ticket: Option<Kerberos5Ticket>,
+}
+
+impl SMBTransactionSessionSetup {
+ pub fn new() -> SMBTransactionSessionSetup {
+ return SMBTransactionSessionSetup {
+ request_host: None,
+ response_host: None,
+ ntlmssp: None,
+ krb_ticket: None,
+ }
+ }
+}
+
+impl SMBState {
+ pub fn new_sessionsetup_tx(&mut self, hdr: SMBCommonHdr)
+ -> (&mut SMBTransaction)
+ {
+ let mut tx = self.new_tx();
+
+ tx.hdr = hdr;
+ tx.type_data = Some(SMBTransactionTypeData::SESSIONSETUP(
+ SMBTransactionSessionSetup::new()));
+ tx.request_done = true;
+ tx.response_done = self.tc_trunc; // no response expected if tc is truncated
+
+ SCLogDebug!("SMB: TX SESSIONSETUP created: ID {}", tx.id);
+ self.transactions.push(tx);
+ let tx_ref = self.transactions.last_mut();
+ return tx_ref.unwrap();
+ }
+
+ pub fn get_sessionsetup_tx(&mut self, hdr: SMBCommonHdr)
+ -> Option<&mut SMBTransaction>
+ {
+ for tx in &mut self.transactions {
+ let hit = tx.hdr == hdr && match tx.type_data {
+ Some(SMBTransactionTypeData::SESSIONSETUP(_)) => { true },
+ _ => { false },
+ };
+ if hit {
+ return Some(tx);
+ }
+ }
+ return None;
+ }
+}
use smb::smb1::*;
use smb::smb2::*;
use smb::dcerpc::*;
+use smb::session::*;
use smb::events::*;
-use smb::auth::*;
use smb::files::*;
pub static mut SURICATA_SMB_FILE_CONFIG: Option<&'static SuricataFileContext> = None;
NEGOTIATE(SMBTransactionNegotiate),
DCERPC(SMBTransactionDCERPC),
CREATE(SMBTransactionCreate),
+ SESSIONSETUP(SMBTransactionSessionSetup),
}
#[derive(Debug)]
pub ts_gap: bool, // last TS update was gap
pub tc_gap: bool, // last TC update was gap
- ts_trunc: bool, // no more data for TOSERVER
- tc_trunc: bool, // no more data for TOCLIENT
+ pub ts_trunc: bool, // no more data for TOSERVER
+ pub tc_trunc: bool, // no more data for TOCLIENT
/// transactions list
pub transactions: Vec<SMBTransaction>,
/// dcerpc interfaces, stored here to be able to match
/// them while inspecting DCERPC REQUEST txs
pub dcerpc_ifaces: Option<Vec<DCERPCIface>>,
-
- pub ntlmssp: Option<NtlmsspData>,
- pub krb_ticket: Option<Kerberos5Ticket>,
}
impl SMBState {
dialect_vec: None,
dialects: None,
dcerpc_ifaces: None,
- ntlmssp: None,
- krb_ticket: None,
}
}
use core::*;
use log::*;
-use smb::smb1_records::*;
use smb::smb::*;
use smb::dcerpc::*;
use smb::events::*;
-use smb::auth::*;
use smb::files::*;
+use smb::smb1_records::*;
+use smb::smb1_session::*;
+
// https://msdn.microsoft.com/en-us/library/ee441741.aspx
pub const SMB1_COMMAND_CREATE_DIRECTORY: u8 = 0x00;
pub const SMB1_COMMAND_DELETE_DIRECTORY: u8 = 0x01;
pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
SCLogDebug!("record: {:?} command {}", r.greeter, r.command);
- // init default tx keys
- let mut key_ssn_id = r.ssn_id;
- let key_tree_id = r.tree_id;
- let key_multiplex_id = r.multiplex_id;
let mut events : Vec<SMBEvent> = Vec::new();
let mut no_response_expected = false;
},
SMB1_COMMAND_SESSION_SETUP_ANDX => {
SCLogDebug!("SMB1_COMMAND_SESSION_SETUP_ANDX user_id {}", r.user_id);
- match parse_smb_setup_andx_record(r.data) {
- IResult::Done(_, setup) => {
- parse_secblob(state, setup.sec_blob);
-/*
- _ => {
- events.push(SMBEvent::MalformedNtlmsspRequest);
- },
-*/
- },
- _ => {
- events.push(SMBEvent::MalformedData);
- },
- }
- key_ssn_id = 0;
- false
+ smb1_session_setup_request(state, r);
+ true
},
SMB1_COMMAND_TREE_CONNECT_ANDX => {
SCLogDebug!("SMB1_COMMAND_TREE_CONNECT_ANDX");
};
if !have_tx {
if smb1_create_new_tx(r.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 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));
tx.set_events(events);
true
},
SMB1_COMMAND_SESSION_SETUP_ANDX => {
+/*
+ SCLogDebug!("SMB1_COMMAND_SESSION_SETUP_ANDX user_id {}", r.user_id);
+ match parse_smb_response_setup_andx_record(r.data) {
+ IResult::Done(rem, _setup) => {
+ //parse_secblob(state, setup.sec_blob);
+ state.response_host = Some(smb1_session_setup_response_host_info(r, rem));
+ },
+ _ => {},
+ }
tx_sync = true;
false
+*/
+ smb1_session_setup_response(state, r);
+ true
},
SMB1_COMMAND_LOGOFF_ANDX => {
tx_sync = true;
>> skip2: take!(8)
>> bcc: le_u16
>> sec_blob: take!(sec_blob_len)
- >> skip3: rest
+ //>> skip3: rest
>> (SmbRecordSetupAndX {
sec_blob:sec_blob,
}))
);
+#[derive(Debug,PartialEq)]
+pub struct SmbResponseRecordSetupAndX<'a> {
+ pub sec_blob: &'a[u8],
+}
+
+named!(pub parse_smb_response_setup_andx_record<SmbResponseRecordSetupAndX>,
+ do_parse!(
+ skip1: take!(7)
+ >> sec_blob_len: le_u16
+ >> bcc: le_u16
+ >> sec_blob: take!(sec_blob_len)
+ //>> skip3: rest
+ >> (SmbResponseRecordSetupAndX {
+ sec_blob:sec_blob,
+ }))
+);
+
#[derive(Debug,PartialEq)]
pub struct SmbRequestReadAndXRecord<'a> {
pub fid: &'a[u8],
--- /dev/null
+/* Copyright (C) 2018 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+use nom::{IResult, ErrorKind};
+
+use log::*;
+
+use smb::smb1_records::*;
+use smb::smb::*;
+use smb::events::*;
+use smb::auth::*;
+
+#[derive(Debug)]
+pub struct SessionSetupRequest {
+ pub native_os: Vec<u8>,
+ pub native_lm: Vec<u8>,
+ pub primary_domain: Vec<u8>,
+}
+
+#[derive(Debug)]
+pub struct SessionSetupResponse {
+ pub native_os: Vec<u8>,
+ pub native_lm: Vec<u8>,
+}
+
+fn get_unicode_string(blob: &[u8]) -> IResult<&[u8], Vec<u8>>
+{
+ SCLogDebug!("get_unicode_string: blob {} {:?}", blob.len(), blob);
+ let mut name : Vec<u8> = Vec::new();
+ let mut c = blob;
+ while c.len() >= 1 {
+ if c.len() == 1 && c[0] == 0 {
+ let rem = &c[1..];
+ SCLogDebug!("get_unicode_string: name {:?}", name);
+ return IResult::Done(rem, name)
+ } else if c.len() == 1 {
+ break;
+ } else if c[0] == 0 && c[1] == 0 {
+ let rem = &c[2..];
+ SCLogDebug!("get_unicode_string: name {:?}", name);
+ return IResult::Done(rem, name)
+ }
+ name.push(c[0]);
+ c = &c[2..];
+ //SCLogNotice!("get_unicode_string: c {:?}", c);
+ }
+ IResult::Error(error_code!(ErrorKind::Custom(130)))
+}
+
+named!(pub get_nullterm_string<Vec<u8>>,
+ do_parse!(
+ s: take_until_and_consume!("\x00")
+ >> ( s.to_vec() )
+));
+
+pub fn smb1_session_setup_request_host_info(r: &SmbRecord, blob: &[u8]) -> SessionSetupRequest
+{
+ if blob.len() > 1 && r.flags2 & 0x8000_u16 != 0 {
+ let offset = r.data.len() - blob.len();
+ let blob = if offset % 2 == 1 { &blob[1..] } else { blob };
+ let (native_os, native_lm, primary_domain) = match get_unicode_string(blob) {
+ IResult::Done(rem, n1) => {
+ match get_unicode_string(rem) {
+ IResult::Done(rem, n2) => {
+ match get_unicode_string(rem) {
+ IResult::Done(_, n3) => { (n1, n2, n3) },
+ _ => { (n1, n2, Vec::new()) },
+ }
+ },
+ _ => { (n1, Vec::new(), Vec::new()) },
+ }
+ },
+ _ => { (Vec::new(), Vec::new(), Vec::new()) },
+ };
+
+ SCLogDebug!("name1 {:?} name2 {:?} name3 {:?}", native_os,native_lm,primary_domain);
+ SessionSetupRequest {
+ native_os:native_os,
+ native_lm:native_lm,
+ primary_domain:primary_domain,
+ }
+ } else {
+ let (native_os, native_lm, primary_domain) = match get_nullterm_string(blob) {
+ IResult::Done(rem, n1) => {
+ match get_nullterm_string(rem) {
+ IResult::Done(rem, n2) => {
+ match get_nullterm_string(rem) {
+ IResult::Done(_, n3) => { (n1, n2, n3) },
+ _ => { (n1, n2, Vec::new()) },
+ }
+ },
+ _ => { (n1, Vec::new(), Vec::new()) },
+ }
+ },
+ _ => { (Vec::new(), Vec::new(), Vec::new()) },
+ };
+
+ SCLogDebug!("session_setup_request_host_info: not unicode");
+ SessionSetupRequest {
+ native_os: native_os,
+ native_lm: native_lm,
+ primary_domain: primary_domain,
+ }
+ }
+}
+
+pub fn smb1_session_setup_response_host_info(r: &SmbRecord, blob: &[u8]) -> SessionSetupResponse
+{
+ if blob.len() > 1 && r.flags2 & 0x8000_u16 != 0 {
+ let offset = r.data.len() - blob.len();
+ let blob = if offset % 2 == 1 { &blob[1..] } else { blob };
+ let (native_os, native_lm) = match get_unicode_string(blob) {
+ IResult::Done(rem, n1) => {
+ match get_unicode_string(rem) {
+ IResult::Done(_, n2) => {
+ (n1, n2)
+ },
+ _ => { (n1, Vec::new()) },
+ }
+ },
+ _ => { (Vec::new(), Vec::new()) },
+ };
+
+ SCLogDebug!("name1 {:?} name2 {:?}", native_os,native_lm);
+ SessionSetupResponse {
+ native_os:native_os,
+ native_lm:native_lm,
+ }
+ } else {
+ SCLogDebug!("session_setup_response_host_info: not unicode");
+ let (native_os, native_lm) = match get_nullterm_string(blob) {
+ IResult::Done(rem, n1) => {
+ match get_nullterm_string(rem) {
+ IResult::Done(_, n2) => {
+ (n1, n2)
+ },
+ _ => { (n1, Vec::new()) },
+ }
+ },
+ _ => { (Vec::new(), Vec::new()) },
+ };
+ SessionSetupResponse {
+ native_os: native_os,
+ native_lm: native_lm,
+ }
+ }
+}
+
+pub fn smb1_session_setup_request(state: &mut SMBState, r: &SmbRecord)
+{
+ SCLogDebug!("SMB1_COMMAND_SESSION_SETUP_ANDX user_id {}", r.user_id);
+ match parse_smb_setup_andx_record(r.data) {
+ IResult::Done(rem, setup) => {
+ let hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER);
+ let tx = state.new_sessionsetup_tx(hdr);
+ tx.vercmd.set_smb1_cmd(r.command);
+
+ if let Some(SMBTransactionTypeData::SESSIONSETUP(ref mut td)) = tx.type_data {
+ match parse_secblob(setup.sec_blob) {
+ Some(s) => {
+ td.ntlmssp = s.ntlmssp;
+ td.krb_ticket = s.krb;
+ },
+ None => { },
+ }
+ td.request_host = Some(smb1_session_setup_request_host_info(r, rem));
+ }
+ },
+ _ => {
+// events.push(SMBEvent::MalformedData);
+ },
+ }
+}
+
+fn smb1_session_setup_update_tx(tx: &mut SMBTransaction, r: &SmbRecord)
+{
+ match parse_smb_response_setup_andx_record(r.data) {
+ IResult::Done(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));
+ }
+ },
+ _ => {
+ tx.set_event(SMBEvent::MalformedData);
+ },
+ }
+ // update tx even if we can't parse the response
+ tx.hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER); // to overwrite ssn_id 0
+ tx.set_status(r.nt_status, r.is_dos_error);
+ tx.response_done = true;
+}
+
+pub fn smb1_session_setup_response(state: &mut SMBState, r: &SmbRecord)
+{
+ // try exact match with session id already set (e.g. NTLMSSP AUTH phase)
+ let found = r.ssn_id != 0 && match state.get_sessionsetup_tx(
+ SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER))
+ {
+ Some(tx) => {
+ smb1_session_setup_update_tx(tx, r);
+ SCLogDebug!("smb1_session_setup_response: tx {:?}", tx);
+ true
+ },
+ None => { false },
+ };
+ // otherwise try match with ssn id 0 (e.g. NTLMSSP_NEGOTIATE)
+ if !found {
+ match state.get_sessionsetup_tx(
+ SMBCommonHdr::new(SMBHDR_TYPE_HEADER, 0, 0, r.multiplex_id as u64))
+ {
+ Some(tx) => {
+ smb1_session_setup_update_tx(tx, r);
+ SCLogDebug!("smb1_session_setup_response: tx {:?}", tx);
+ },
+ None => {
+ SCLogNotice!("smb1_session_setup_response: tx not found for {:?}", r);
+ },
+ }
+ }
+}
use smb::smb::*;
use smb::smb2_records::*;
+use smb::smb2_session::*;
use smb::dcerpc::*;
use smb::events::*;
-use smb::auth::*;
use smb::files::*;
pub const SMB2_COMMAND_NEGOTIATE_PROTOCOL: u16 = 0;
}
},
SMB2_COMMAND_SESSION_SETUP => {
- SCLogDebug!("SMB2_COMMAND_SESSION_SETUP: r.data.len() {}", r.data.len());
- match parse_smb2_request_session_setup(r.data) {
- IResult::Done(_, setup) => {
- SCLogDebug!("SMB2_COMMAND_SESSION_SETUP parsed. rd.data.len() {}", setup.data.len());
- parse_secblob(state, setup.data);
-/*
- match parse_ntlmssp(rd.data) {
- IResult::Done(_, nd) => {
- SCLogDebug!("NTLMSSP TYPE {}/{} nd {:?}",
- nd.msg_type, &ntlmssp_type_string(nd.msg_type), nd);
- match nd.msg_type {
- NTLMSSP_NEGOTIATE => {
- key_session_id = 0;
- },
- NTLMSSP_AUTH => {
- match parse_ntlm_auth_record(nd.data) {
- IResult::Done(_, ad) => {
- SCLogDebug!("auth data {:?}", ad);
- state.ntlmssp_host = ad.host.to_vec();
- state.ntlmssp_user = ad.user.to_vec();
- state.ntlmssp_domain = ad.domain.to_vec();
- },
- _ => {
- events.push(SMBEvent::MalformedData);
- },
- }
- },
- _ => { },
- }
- },
- _ => {
- SCLogNotice!("error parsing ntlmssp");
- },
- }
-*/
- },
- _ => {
- events.push(SMBEvent::MalformedData);
- },
- }
- false
+ smb2_session_setup_request(state, r);
+ true
},
SMB2_COMMAND_TREE_CONNECT => {
match parse_smb2_request_tree_connect(r.data) {
}
}
-fn smb2_response_record_session_setup<'b>(state: &mut SMBState, r: &Smb2Record<'b>)
-{
- // first try exact match
- let found = match state.get_generic_tx(2, r.command, &SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX)) {
- Some(tx) => {
- if r.nt_status != SMB_NTSTATUS_PENDING {
- tx.response_done = true;
- }
- tx.set_status(r.nt_status, false);
- true
- },
- None => false,
- };
- // if not found try with ssn id 0.
- if !found {
- let tx_key = SMBCommonHdr::new(SMBHDR_TYPE_GENERICTX, 0, 0, r.message_id);
- match state.get_generic_tx(2, r.command, &tx_key) {
- Some(tx) => {
- if r.nt_status != SMB_NTSTATUS_PENDING {
- tx.response_done = true;
- }
- tx.set_status(r.nt_status, false);
- },
- None => { },
- }
- }
-}
-
pub fn smb2_response_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>)
{
SCLogDebug!("SMBv2 response record, command {} status {} tree {} session {} message {}",
have_ioctl_tx
},
SMB2_COMMAND_SESSION_SETUP => {
- smb2_response_record_session_setup(state, r);
+ smb2_session_setup_response(state, r);
true
},
SMB2_COMMAND_WRITE => {
--- /dev/null
+/* Copyright (C) 2018 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+use nom::{IResult};
+
+use log::*;
+
+use smb::smb2_records::*;
+use smb::smb::*;
+//use smb::events::*;
+use smb::auth::*;
+
+pub fn smb2_session_setup_request(state: &mut SMBState, r: &Smb2Record)
+{
+ SCLogDebug!("SMB2_COMMAND_SESSION_SETUP: r.data.len() {}", r.data.len());
+ match parse_smb2_request_session_setup(r.data) {
+ IResult::Done(_, setup) => {
+ let hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER);
+ let tx = state.new_sessionsetup_tx(hdr);
+ tx.vercmd.set_smb2_cmd(r.command);
+
+ if let Some(SMBTransactionTypeData::SESSIONSETUP(ref mut td)) = tx.type_data {
+ if let Some(s) = parse_secblob(setup.data) {
+ td.ntlmssp = s.ntlmssp;
+ td.krb_ticket = s.krb;
+ }
+ }
+ },
+ _ => {
+// events.push(SMBEvent::MalformedData);
+ },
+ }
+}
+
+fn smb2_session_setup_update_tx(tx: &mut SMBTransaction, r: &Smb2Record)
+{
+ tx.hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER); // to overwrite ssn_id 0
+ tx.set_status(r.nt_status, false);
+ tx.response_done = true;
+}
+
+pub fn smb2_session_setup_response(state: &mut SMBState, r: &Smb2Record)
+{
+ // try exact match with session id already set (e.g. NTLMSSP AUTH phase)
+ let found = r.session_id != 0 && match state.get_sessionsetup_tx(
+ SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER))
+ {
+ Some(tx) => {
+ smb2_session_setup_update_tx(tx, r);
+ SCLogDebug!("smb2_session_setup_response: tx {:?}", tx);
+ true
+ },
+ None => { false },
+ };
+ // otherwise try match with ssn id 0 (e.g. NTLMSSP_NEGOTIATE)
+ if !found {
+ match state.get_sessionsetup_tx(
+ SMBCommonHdr::new(SMBHDR_TYPE_HEADER, 0, 0, r.message_id))
+ {
+ Some(tx) => {
+ smb2_session_setup_update_tx(tx, r);
+ SCLogDebug!("smb2_session_setup_response: tx {:?}", tx);
+ },
+ None => {
+ SCLogNotice!("smb2_session_setup_response: tx not found for {:?}", r);
+ },
+ }
+ }
+}