packet-dcerpc: let dissect_dcerpc_cn_auth() always dissect the whole auth_info

As all this information belongs together I'm moving it into a subtree.

Change-Id: I839a5a6294360976a78b4b43f219e30381b4f516
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-on: https://code.wireshark.org/review/17878
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Stefan Metzmacher 2016-09-19 04:35:49 +02:00 committed by Anders Broman
parent 68dbc6431f
commit 1ec28b4a08
2 changed files with 110 additions and 141 deletions

View File

@ -610,6 +610,7 @@ static int hf_dcerpc_stub_data_with_sec_vt = -1;
static int hf_dcerpc_stub_data = -1;
static int hf_dcerpc_auth_padding = -1;
static int hf_dcerpc_auth_verifier = -1;
static int hf_dcerpc_auth_info = -1;
static int hf_dcerpc_auth_credentials = -1;
static int hf_dcerpc_fault_stub_data = -1;
static int hf_dcerpc_fragment_data = -1;
@ -653,6 +654,7 @@ static gint ett_dcerpc_string = -1;
static gint ett_dcerpc_fragments = -1;
static gint ett_dcerpc_fragment = -1;
static gint ett_dcerpc_krb5_auth_verf = -1;
static gint ett_dcerpc_auth_info = -1;
static gint ett_dcerpc_verification_trailer = -1;
static gint ett_dcerpc_sec_vt_command = -1;
static gint ett_dcerpc_sec_vt_bitmask = -1;
@ -1204,9 +1206,7 @@ void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
/* Hand off verifier data to a registered dissector */
static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
proto_tree *tree,
dcerpc_auth_subdissector_fns *auth_fns,
static void dissect_auth_verf(packet_info *pinfo,
e_dce_cn_common_hdr_t *hdr,
dcerpc_auth_info *auth_info)
{
@ -1217,33 +1217,42 @@ static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
*/
FAKE_DCERPC_INFO_STRUCTURE
if (auth_info == NULL) {
return;
}
if (auth_info->auth_fns == NULL) {
return;
}
switch (hdr->ptype) {
case PDU_BIND:
case PDU_ALTER:
fn = auth_fns->bind_fn;
fn = auth_info->auth_fns->bind_fn;
break;
case PDU_BIND_ACK:
case PDU_ALTER_ACK:
fn = auth_fns->bind_ack_fn;
fn = auth_info->auth_fns->bind_ack_fn;
break;
case PDU_AUTH3:
fn = auth_fns->auth3_fn;
fn = auth_info->auth_fns->auth3_fn;
break;
case PDU_REQ:
case PDU_CO_CANCEL:
case PDU_ORPHANED:
fn = auth_fns->req_verf_fn;
fn = auth_info->auth_fns->req_verf_fn;
break;
case PDU_RESP:
case PDU_FAULT:
fn = auth_fns->resp_verf_fn;
fn = auth_info->auth_fns->resp_verf_fn;
break;
default:
/* Don't know how to handle authentication data in this
pdu type. */
proto_tree_add_expert_format(tree, pinfo, &ei_dcerpc_invalid_pdu_authentication_attempt,
auth_tvb, 0, 0,
proto_tree_add_expert_format(auth_info->auth_tree, pinfo,
&ei_dcerpc_invalid_pdu_authentication_attempt,
auth_info->auth_tvb, 0, 0,
"Don't know how to dissect authentication data for %s pdu type",
val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
return;
@ -1251,15 +1260,15 @@ static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
}
if (fn)
fn(auth_tvb, 0, pinfo, tree, &di, hdr->drep);
else {
proto_tree_add_expert_format(tree, pinfo, &ei_dcerpc_verifier_unavailable,
auth_tvb, 0, hdr->auth_len,
fn(auth_info->auth_tvb, 0, pinfo, auth_info->auth_tree, &di, hdr->drep);
else
proto_tree_add_expert_format(auth_info->auth_tree, pinfo,
&ei_dcerpc_verifier_unavailable,
auth_info->auth_tvb, 0, hdr->auth_len,
"%s Verifier unavailable",
val_to_str(auth_info->auth_type,
authn_protocol_vals,
"Unknown (%u)"));
}
}
static proto_item*
@ -1285,21 +1294,30 @@ proto_tree_add_dcerpc_drep(proto_tree *tree, tvbuff_t *tvb, int offset, guint8 d
/* Hand off payload data to a registered dissector */
static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
tvbuff_t *auth_tvb,
packet_info *pinfo,
dcerpc_auth_subdissector_fns *auth_fns,
gboolean is_request,
e_dce_cn_common_hdr_t *hdr,
dcerpc_auth_info *auth_info)
{
dcerpc_decode_data_fnct_t *fn;
dcerpc_decode_data_fnct_t *fn = NULL;
if (is_request)
fn = auth_fns->req_data_fn;
else
fn = auth_fns->resp_data_fn;
if (auth_info == NULL)
return NULL;
if (auth_info->auth_fns == NULL)
return NULL;
switch (hdr->ptype) {
case PDU_REQ:
fn = auth_info->auth_fns->req_data_fn;
break;
case PDU_RESP:
case PDU_FAULT:
fn = auth_info->auth_fns->resp_data_fn;
break;
}
if (fn)
return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
return fn(data_tvb, auth_info->auth_tvb, 0, pinfo, auth_info);
return NULL;
}
@ -3651,51 +3669,10 @@ dcerpc_try_handoff(packet_info *pinfo, proto_tree *tree,
return 0;
}
static int
dissect_dcerpc_verifier(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
dcerpc_auth_info *auth_info)
{
int auth_offset;
auth_info->auth_data = NULL;
if (auth_info->auth_size != 0) {
dcerpc_auth_subdissector_fns *auth_fns;
tvbuff_t *auth_tvb;
auth_offset = hdr->frag_len - hdr->auth_len;
auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
hdr->auth_len);
auth_info->auth_data = auth_tvb;
if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
auth_info->auth_type))) {
/*
* Catch all bounds-error exceptions, so that even if the
* verifier is bad or we don't have all of it, we still
* show the stub data.
*/
TRY {
dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
hdr, auth_info);
} CATCH_BOUNDS_ERRORS {
show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
} ENDTRY;
} else {
proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_verifier, auth_tvb, 0, hdr->auth_len, ENC_NA);
}
}
return hdr->auth_len;
}
static void
dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
gboolean are_credentials, dcerpc_auth_info *auth_info)
dcerpc_auth_info *auth_info)
{
volatile int offset;
@ -3703,10 +3680,15 @@ dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
* Initially set auth_level and auth_type to zero to indicate that we
* haven't yet seen any authentication level information.
*/
auth_info->auth_level = 0;
auth_info->auth_type = 0;
auth_info->auth_size = 0;
auth_info->auth_pad_len = 0;
auth_info->auth_type = 0;
auth_info->auth_level = 0;
auth_info->auth_context_id = 0;
auth_info->auth_pad_len = 0;
auth_info->auth_size = 0;
auth_info->auth_fns = NULL;
auth_info->auth_tvb = NULL;
auth_info->auth_item = NULL;
auth_info->auth_tree = NULL;
/*
* The authentication information is at the *end* of the PDU; in
@ -3732,6 +3714,15 @@ dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
*/
offset = hdr->frag_len - (hdr->auth_len + 8);
if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
/* Compute the size of the auth block. Note that this should not
include auth padding, since when NTLMSSP encryption is used, the
padding is actually inside the encrypted stub */
auth_info->auth_size = hdr->auth_len + 8;
auth_info->auth_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_info,
tvb, offset, auth_info->auth_size, ENC_NA);
auth_info->auth_tree = proto_item_add_subtree(auth_info->auth_item, ett_dcerpc_auth_info);
/*
* Either there's no stub data, or the last byte of the stub
* data is present in the captured data, so we shouldn't
@ -3743,44 +3734,49 @@ dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
* dissect after this, such as stub data.
*/
TRY {
offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
hf_dcerpc_auth_type,
&auth_info->auth_type);
offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
hf_dcerpc_auth_level,
&auth_info->auth_level);
offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
hf_dcerpc_auth_pad_len,
&auth_info->auth_pad_len);
offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
hf_dcerpc_auth_rsrvd, NULL);
offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_auth_ctx_id, NULL);
offset = dissect_dcerpc_uint32(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
hf_dcerpc_auth_ctx_id,
&auth_info->auth_context_id);
proto_item_append_text(auth_info->auth_item,
": %s, %s, AuthContextId(%d)",
val_to_str(auth_info->auth_type,
authn_protocol_vals,
"AuthType(%u)"),
val_to_str(auth_info->auth_level,
authn_level_vals,
"AuthLevel(%u)"),
auth_info->auth_context_id);
/*
* Dissect the authentication data.
*/
if (are_credentials) {
tvbuff_t *auth_tvb;
dcerpc_auth_subdissector_fns *auth_fns;
auth_tvb = tvb_new_subset(tvb, offset,
auth_info->auth_tvb = tvb_new_subset(tvb, offset,
MIN(hdr->auth_len,tvb_reported_length_remaining(tvb, offset)),
hdr->auth_len);
if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
auth_info->auth_type)))
dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
hdr, auth_info);
else
proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_credentials, tvb, offset, hdr->auth_len, ENC_NA);
}
auth_info->auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
auth_info->auth_type);
if (auth_info->auth_fns != NULL)
dissect_auth_verf(pinfo, hdr, auth_info);
else
proto_tree_add_item(auth_info->auth_tree,
hf_dcerpc_auth_credentials,
auth_info->auth_tvb, 0,
hdr->auth_len, ENC_NA);
/* Compute the size of the auth block. Note that this should not
include auth padding, since when NTLMSSP encryption is used, the
padding is actually inside the encrypted stub */
auth_info->auth_size = hdr->auth_len + 8;
} CATCH_BOUNDS_ERRORS {
show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
} ENDTRY;
@ -4024,7 +4020,7 @@ dissect_dcerpc_cn_bind(tvbuff_t *tvb, gint offset, packet_info *pinfo,
* an authentication header, and associate it with an authentication
* context, so subsequent PDUs can use that context.
*/
dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
}
static void
@ -4132,7 +4128,7 @@ dissect_dcerpc_cn_bind_ack(tvbuff_t *tvb, gint offset, packet_info *pinfo,
* XXX - do we need to do anything with the authentication level
* we get back from this?
*/
dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
}
static void
@ -4196,7 +4192,7 @@ dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
gboolean save_fragmented;
fragment_head *fd_head = NULL;
tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb = NULL;
tvbuff_t *payload_tvb, *decrypted_tvb = NULL;
proto_item *pi;
proto_item *parent_pi;
proto_item *dcerpc_tree_item;
@ -4216,45 +4212,17 @@ dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
length = reported_length;
payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
auth_tvb = NULL;
/*don't bother if we don't have the entire tvb */
/*XXX we should really make sure we calculate auth_info->auth_data
and use that one instead of this auth_tvb hack
*/
if (tvb_captured_length(tvb) == tvb_reported_length(tvb)) {
if (tvb_reported_length_remaining(tvb, offset+length) > 8) {
auth_tvb = tvb_new_subset_remaining(tvb, offset+length+8);
}
}
/* Decrypt the PDU if it is encrypted */
if (auth_info->auth_type &&
(auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
/*
* We know the authentication type, and the authentication
* level is "Packet privacy", meaning the payload is
* encrypted; attempt to decrypt it.
*/
dcerpc_auth_subdissector_fns *auth_fns;
/* Start out assuming we won't succeed in decrypting. */
/* Schannel needs information into the footer (verifier) in order to setup decryption keys
* so we call it in order to have a chance to decipher the data
*/
if (DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN == auth_info->auth_type) {
dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, auth_info);
}
if ((auth_fns = get_auth_subdissector_fns(
auth_info->auth_level, auth_info->auth_type))) {
if (auth_info->auth_fns != NULL) {
tvbuff_t *result;
result = decode_encrypted_data(
payload_tvb, auth_tvb, pinfo, auth_fns,
hdr->ptype == PDU_REQ, auth_info);
result = decode_encrypted_data(payload_tvb, pinfo, hdr, auth_info);
if (result) {
proto_tree_add_item(dcerpc_tree, hf_dcerpc_encrypted_stub_data, payload_tvb, 0, -1, ENC_NA);
@ -4465,7 +4433,7 @@ dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
* XXX - what if this was set when the connection was set up,
* and we just have a security context?
*/
dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
@ -4583,10 +4551,6 @@ dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
}
}
/* Dissect the verifier */
dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
}
static void
@ -4628,7 +4592,7 @@ dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
* XXX - what if this was set when the connection was set up,
* and we just have a security context?
*/
dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
@ -4718,9 +4682,6 @@ dissect_dcerpc_cn_resp(tvbuff_t *tvb, gint offset, packet_info *pinfo,
show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
}
}
/* Dissect the verifier */
dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
}
static void
@ -4775,7 +4736,7 @@ dissect_dcerpc_cn_fault(tvbuff_t *tvb, gint offset, packet_info *pinfo,
* XXX - what if this was set when the connection was set up,
* and we just have a security context?
*/
dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
@ -5491,7 +5452,7 @@ dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
/*
* Nothing after the common header other than credentials.
*/
dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, TRUE,
dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr,
&auth_info);
break;
@ -5517,7 +5478,7 @@ dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
* Nothing after the common header other than an authentication
* verifier.
*/
dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr,
&auth_info);
break;
@ -5533,7 +5494,7 @@ dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
default:
/* might as well dissect the auth info */
dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr,
&auth_info);
break;
}
@ -6903,6 +6864,7 @@ proto_register_dcerpc(void)
{ &hf_dcerpc_stub_data_with_sec_vt, { "Stub data with rpc_sec_verification_trailer", "dcerpc.stub_data_with_sec_vt", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_dcerpc_stub_data, { "Stub data", "dcerpc.stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_dcerpc_auth_padding, { "Auth Padding", "dcerpc.auth_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_dcerpc_auth_info, { "Auth Info", "dcerpc.auth_info", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_dcerpc_auth_verifier, { "Auth Verifier", "dcerpc.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_dcerpc_auth_credentials, { "Auth Credentials", "dcerpc.auth_credentials", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_dcerpc_fault_stub_data, { "Fault stub data", "dcerpc.fault_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
@ -6930,6 +6892,7 @@ proto_register_dcerpc(void)
&ett_dcerpc_fragments,
&ett_dcerpc_fragment,
&ett_dcerpc_krb5_auth_verf,
&ett_dcerpc_auth_info,
&ett_dcerpc_verification_trailer,
&ett_dcerpc_sec_vt_command,
&ett_dcerpc_sec_vt_bitmask,

View File

@ -100,12 +100,18 @@ typedef struct _e_dce_dg_common_hdr_t {
guint8 serial_lo;
} e_dce_dg_common_hdr_t;
struct _dcerpc_auth_subdissector_fns;
typedef struct _dcerpc_auth_info {
guint8 auth_pad_len;
guint8 auth_level;
guint8 auth_type;
guint8 auth_level;
guint32 auth_context_id;
guint8 auth_pad_len;
guint32 auth_size;
tvbuff_t *auth_data;
struct _dcerpc_auth_subdissector_fns *auth_fns;
tvbuff_t *auth_tvb;
proto_item *auth_item;
proto_tree *auth_tree;
} dcerpc_auth_info;
typedef struct dcerpcstat_tap_data