GH-865: fix parsing of SMB NegotiateContextList

* The compression capability was incorrectly set to 0x0004 instead of 0x0003

* The padding was 4-byte instead of 8-byte aligned and also the spec.
  does not strictly require the padding for the last item in the list.

* Add a default case to handle parsing of unknown context types.
This commit is contained in:
Jon Siwek 2020-03-16 19:00:01 -07:00
parent acb3b27a2c
commit 9c70bcecbc
4 changed files with 62 additions and 8 deletions

View file

@ -11,7 +11,7 @@ enum smb3_capabilities {
enum smb3_context_type { enum smb3_context_type {
SMB2_PREAUTH_INTEGRITY_CAPABILITIES = 0x0001, SMB2_PREAUTH_INTEGRITY_CAPABILITIES = 0x0001,
SMB2_ENCRYPTION_CAPABILITIES = 0x0002, SMB2_ENCRYPTION_CAPABILITIES = 0x0002,
SMB2_COMPRESSION_CAPABILITIES = 0x0004, SMB2_COMPRESSION_CAPABILITIES = 0x0003,
SMB2_NETNAME_NEGOTIATE_CONTEXT_ID = 0x0005, SMB2_NETNAME_NEGOTIATE_CONTEXT_ID = 0x0005,
}; };
@ -50,9 +50,13 @@ refine connection SMB_Conn += {
VectorVal* cv = new VectorVal(BifType::Vector::SMB2::NegotiateContextValues); VectorVal* cv = new VectorVal(BifType::Vector::SMB2::NegotiateContextValues);
if ( ${val.dialect_revision} == 0x0311 ) if ( ${val.dialect_revision} == 0x0311 && ${val.negotiate_context_count} > 0 )
for ( auto i = 0u; i < ${val.smb3_ncl.vals}->size(); ++i ) {
cv->Assign(i, BuildSMB2ContextVal(${val.smb3_ncl.vals[i]})); for ( auto i = 0u; i < ${val.smb3_ncl.list.vals}->size(); ++i )
cv->Assign(i, BuildSMB2ContextVal(${val.smb3_ncl.list.vals[i].ncv}));
cv->Assign(${val.smb3_ncl.list.vals}->size(), BuildSMB2ContextVal(${val.smb3_ncl.list.last_val}));
}
nr->Assign(6, cv); nr->Assign(6, cv);
@ -97,8 +101,13 @@ type SMB3_negotiate_context_value = record {
SMB2_ENCRYPTION_CAPABILITIES -> encryption_capabilities : SMB3_encryption_capabilities; SMB2_ENCRYPTION_CAPABILITIES -> encryption_capabilities : SMB3_encryption_capabilities;
SMB2_COMPRESSION_CAPABILITIES -> compression_capabilities : SMB3_compression_capabilities; SMB2_COMPRESSION_CAPABILITIES -> compression_capabilities : SMB3_compression_capabilities;
SMB2_NETNAME_NEGOTIATE_CONTEXT_ID -> netname_negotiate_context_id : SMB3_netname_negotiate_context_id(data_length); SMB2_NETNAME_NEGOTIATE_CONTEXT_ID -> netname_negotiate_context_id : SMB3_netname_negotiate_context_id(data_length);
default -> unknown_context_data : bytestring &length=data_length;
}; };
pad : padding align 4; };
type Padded_SMB3_negotiate_context_value = record {
ncv: SMB3_negotiate_context_value;
pad: padding align 8;
}; };
type SMB2_negotiate_request(header: SMB2_Header) = record { type SMB2_negotiate_request(header: SMB2_Header) = record {
@ -115,8 +124,16 @@ type SMB2_negotiate_request(header: SMB2_Header) = record {
}; };
type NegotiateContextList(len: uint16) = record { type NegotiateContextList(len: uint16) = record {
vals : SMB3_negotiate_context_value[len]; vals: Padded_SMB3_negotiate_context_value[len - 1];
} last_val: SMB3_negotiate_context_value;
};
type OptNegotiateContextList(len: uint16) = record {
opt: case len of {
0 -> nil: empty;
default -> list: NegotiateContextList(len);
};
};
type SMB2_negotiate_response(header: SMB2_Header) = record { type SMB2_negotiate_response(header: SMB2_Header) = record {
structure_size : uint16; structure_size : uint16;
@ -136,7 +153,7 @@ type SMB2_negotiate_response(header: SMB2_Header) = record {
security_blob : bytestring &length=security_length; security_blob : bytestring &length=security_length;
pad1 : padding to (dialect_revision == 0x0311 ? negotiate_context_offset - header.head_length : 0); pad1 : padding to (dialect_revision == 0x0311 ? negotiate_context_offset - header.head_length : 0);
negotiate_context_list : case dialect_revision of { negotiate_context_list : case dialect_revision of {
0x0311 -> smb3_ncl : NegotiateContextList(negotiate_context_count); 0x0311 -> smb3_ncl : OptNegotiateContextList(negotiate_context_count);
default -> unknown : empty; default -> unknown : empty;
}; };
} &byteorder=littleendian, &let { } &byteorder=littleendian, &let {

View file

@ -0,0 +1,4 @@
context value type 1, length 38
[hash_alg_count=1, salt_length=32, hash_alg=[1], salt=\xfbV\x86\xeb\xb8\x8f\x1e\xb2\x1f\xd1?&\x94\xa5\xa53'\x01\x96\x96:\xca.\xcc\xa5\xa8\xd2\xf9\x15\xd7*\x92]
context value type 3, length 10
[alg_count=1, algs=[1]]

Binary file not shown.

View file

@ -0,0 +1,33 @@
# @TEST-EXEC: zeek -b -r $TRACES/smb/SMBGhost.pcap %INPUT >out
# @TEST-EXEC: btest-diff out
@load base/protocols/smb
event smb2_negotiate_response(c: connection, hdr: SMB2::Header, response: SMB2::NegotiateResponse)
{
for ( i in response$negotiate_context_values )
{
local ncv = response$negotiate_context_values[i];
print fmt("context value type %s, length %s",
ncv$context_type, ncv$data_length);
switch ( ncv$context_type ) {
case 0x001:
print fmt(" %s", ncv$preauth_info);
break;
case 0x002:
print fmt(" %s", ncv$encryption_info);
break;
case 0x003:
print fmt(" %s", ncv$compression_info);
break;
case 0x005:
print fmt(" %s", ncv$netname);
break;
default:
print " unknown context value type";
break;
}
}
}