aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-smtp.c
diff options
context:
space:
mode:
authorMichael Mann <mmann78@netscape.net>2013-04-22 02:43:52 +0000
committerMichael Mann <mmann78@netscape.net>2013-04-22 02:43:52 +0000
commitf3689204a984819201acdefd2240e1426476b505 (patch)
treee2f422c84adc94daf434e94eb21780cc88c247bf /epan/dissectors/packet-smtp.c
parent4a1bd75b60171d781dc9f2d3ffd6d498acc74b1a (diff)
Improve AUTH handling (NTLM and elementary PLAIN mechanism)
from Uli Heilmeier, bug 8600 (https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8600) svn path=/trunk/; revision=48961
Diffstat (limited to 'epan/dissectors/packet-smtp.c')
-rw-r--r--epan/dissectors/packet-smtp.c165
1 files changed, 162 insertions, 3 deletions
diff --git a/epan/dissectors/packet-smtp.c b/epan/dissectors/packet-smtp.c
index c635b8cee1..2655a91759 100644
--- a/epan/dissectors/packet-smtp.c
+++ b/epan/dissectors/packet-smtp.c
@@ -113,6 +113,7 @@ static const fragment_items smtp_data_frag_items = {
static dissector_handle_t ssl_handle;
static dissector_handle_t imf_handle;
+static dissector_handle_t ntlmssp_handle;
/*
* A CMD is an SMTP command, MESSAGE is the message portion, and EOM is the
@@ -144,6 +145,13 @@ typedef enum {
SMTP_AUTH_STATE_USERNAME_RSP, /* Received username response from client */
SMTP_AUTH_STATE_PASSWORD_REQ, /* Received password request from server */
SMTP_AUTH_STATE_PASSWORD_RSP, /* Received password request from server */
+ SMTP_AUTH_STATE_PLAIN_START_REQ, /* Received AUTH PLAIN command from client*/
+ SMTP_AUTH_STATE_PLAIN_CRED_REQ, /* Received AUTH PLAIN command including creds from client*/
+ SMTP_AUTH_STATE_PLAIN_REQ, /* Received AUTH PLAIN request from server */
+ SMTP_AUTH_STATE_PLAIN_RSP, /* Received AUTH PLAIN response from client */
+ SMTP_AUTH_STATE_NTLM_REQ, /* Received ntlm negotiate request from client */
+ SMTP_AUTH_STATE_NTLM_CHALLANGE, /* Received ntlm challange request from server */
+ SMTP_AUTH_STATE_NTLM_RSP, /* Received ntlm auth request from client */
SMTP_AUTH_STATE_SUCCESS, /* Password received, authentication successful, start decoding */
SMTP_AUTH_STATE_FAILED, /* authentication failed, no decoding */
} smtp_auth_state_t;
@@ -162,7 +170,12 @@ struct smtp_session_state {
guint32 msg_tot_len; /* Total length of BDAT message */
gboolean msg_last; /* Is this the last BDAT chunk */
guint32 last_nontls_frame; /* last non-TLS frame; 0 if not known or no TLS */
- guint32 username_cmd_frame; /* AUTH command contains username */
+ guint32 username_cmd_frame; /* AUTH command contains username */
+ guint32 user_pass_cmd_frame; /* AUTH command contains username and password */
+ guint32 user_pass_frame; /* Frame contains username and password */
+ guint32 ntlm_req_frame; /* Frame containing NTLM request */
+ guint32 ntlm_cha_frame; /* Frame containing NTLM challange. */
+ guint32 ntlm_rsp_frame; /* Frame containing NTLM response. */
};
/*
@@ -281,11 +294,24 @@ dissect_smtp_data(tvbuff_t *tvb, int offset, proto_tree *smtp_tree)
}
static void
+dissect_ntlm_auth(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ const char *line)
+{
+ tvbuff_t *ntlm_tvb;
+
+ ntlm_tvb = base64_to_tvb(tvb, line);
+ if(tvb_strneql(ntlm_tvb, 0, "NTLMSSP", 7) == 0) {
+ add_new_data_source(pinfo, ntlm_tvb, "NTLMSSP Data");
+ call_dissector(ntlmssp_handle, ntlm_tvb, pinfo, tree);
+ }
+}
+
+static void
dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
struct smtp_proto_data *spd_frame_data;
proto_tree *smtp_tree = NULL;
- proto_tree *cmdresp_tree;
+ proto_tree *cmdresp_tree = NULL;
proto_item *ti, *hidden_item;
int offset = 0;
int request = 0;
@@ -302,6 +328,8 @@ dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
fragment_data *frag_msg = NULL;
tvbuff_t *next_tvb;
guint8 *decrypt = NULL;
+ guint8 *base64_string = NULL;
+ guint8 *base64_plain = NULL;
guint8 line_code[3];
/* As there is no guarantee that we will only see frames in the
@@ -599,6 +627,33 @@ dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
session_state->auth_state = SMTP_AUTH_STATE_USERNAME_RSP;
session_state->first_auth_frame = pinfo->fd->num;
session_state->username_cmd_frame = pinfo->fd->num;
+ } else if ((g_ascii_strncasecmp(line, "AUTH PLAIN", 10) == 0) && (linelen <= 11)) {
+ /*
+ * AUTH PLAIN command.
+ * Username and Password is in one seperate frame
+ */
+ spd_frame_data->pdu_type = SMTP_PDU_CMD;
+ session_state->smtp_state = SMTP_STATE_READING_CMDS;
+ session_state->auth_state = SMTP_AUTH_STATE_PLAIN_START_REQ;
+ session_state->first_auth_frame = pinfo->fd->num;
+ } else if ((g_ascii_strncasecmp(line, "AUTH PLAIN", 10) == 0) && (linelen > 11)) {
+ /*
+ * AUTH PLAIN command.
+ * Username and Password follows the 'AUTH PLAIN' string
+ */
+ spd_frame_data->pdu_type = SMTP_PDU_CMD;
+ session_state->smtp_state = SMTP_STATE_READING_CMDS;
+ session_state->auth_state = SMTP_AUTH_STATE_PLAIN_CRED_REQ;
+ session_state->first_auth_frame = pinfo->fd->num;
+ session_state->user_pass_cmd_frame = pinfo->fd->num;
+ } else if ((g_ascii_strncasecmp(line, "AUTH NTLM", 9) == 0) && (linelen > 10)) {
+ /*
+ * AUTH NTLM command with nlmssp request
+ */
+ spd_frame_data->pdu_type = SMTP_PDU_CMD;
+ session_state->smtp_state = SMTP_STATE_READING_CMDS;
+ session_state->auth_state = SMTP_AUTH_STATE_NTLM_REQ;
+ session_state->ntlm_req_frame = pinfo->fd->num;
} else if (g_ascii_strncasecmp(line, "STARTTLS", 8) == 0) {
/*
* STARTTLS command.
@@ -619,6 +674,12 @@ dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
} else if (session_state->auth_state == SMTP_AUTH_STATE_PASSWORD_REQ) {
session_state->auth_state = SMTP_AUTH_STATE_PASSWORD_RSP;
session_state->password_frame = pinfo->fd->num;
+ } else if (session_state->auth_state == SMTP_AUTH_STATE_PLAIN_REQ) {
+ session_state->auth_state = SMTP_AUTH_STATE_PLAIN_RSP;
+ session_state->user_pass_frame = pinfo->fd->num;
+ } else if (session_state->auth_state == SMTP_AUTH_STATE_NTLM_CHALLANGE) {
+ session_state->auth_state = SMTP_AUTH_STATE_NTLM_RSP;
+ session_state->ntlm_rsp_frame = pinfo->fd->num;
}
else {
@@ -767,6 +828,38 @@ dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_tree_add_string(smtp_tree, hf_smtp_password, tvb,
loffset, linelen, decrypt);
col_append_str(pinfo->cinfo, COL_INFO, decrypt);
+ } else if (session_state->ntlm_rsp_frame == pinfo->fd->num) {
+ decrypt = tvb_get_ephemeral_string(tvb, loffset, linelen);
+ if (stmp_decryption_enabled) {
+ if (epan_base64_decode(decrypt) == 0) {
+ /* Go back to the original string */
+ decrypt = tvb_get_ephemeral_string(tvb, loffset, linelen);
+ col_append_str(pinfo->cinfo, COL_INFO, decrypt);
+ proto_tree_add_item(smtp_tree, hf_smtp_command_line, tvb,
+ loffset, linelen, ENC_ASCII|ENC_NA);
+ }
+ else {
+ base64_string = tvb_get_ephemeral_string(tvb, loffset, linelen);
+ dissect_ntlm_auth(tvb, pinfo, smtp_tree, base64_string);
+ }
+ }
+ else {
+ col_append_str(pinfo->cinfo, COL_INFO, decrypt);
+ proto_tree_add_item(smtp_tree, hf_smtp_command_line, tvb,
+ loffset, linelen, ENC_ASCII|ENC_NA);
+ }
+ } else if (session_state->user_pass_frame == pinfo->fd->num) {
+ base64_plain = tvb_get_ephemeral_string(tvb, loffset, linelen);
+ /* FIXME when stmp_decryption_enabled is active the plain mechs credentials
+ * should also be decoded.
+ * Format is:
+ * [authorize-user]+[NULL character]+[authentication-user]+[NULL character]+[password]
+ */
+ proto_tree_add_string(smtp_tree, hf_smtp_username, tvb,
+ loffset, linelen, base64_plain);
+ proto_tree_add_string(smtp_tree, hf_smtp_password, tvb,
+ loffset, linelen, base64_plain);
+ col_append_str(pinfo->cinfo, COL_INFO, base64_plain);
} else {
if (linelen >= 4)
@@ -802,6 +895,44 @@ dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
col_append_str(pinfo->cinfo, COL_INFO, tvb_get_ephemeral_string(tvb, loffset, 11));
col_append_str(pinfo->cinfo, COL_INFO, decrypt);
}
+ else if ((linelen > 5) && (session_state->ntlm_req_frame == pinfo->fd->num) ) {
+ proto_tree_add_item(cmdresp_tree, hf_smtp_req_parameter, tvb,
+ loffset + 5, linelen - 5, ENC_ASCII|ENC_NA);
+ decrypt = tvb_get_ephemeral_string(tvb, loffset + 10, linelen - 10);
+ if (stmp_decryption_enabled) {
+ if (epan_base64_decode(decrypt) == 0) {
+ /* Go back to the original string */
+ decrypt = tvb_get_ephemeral_string(tvb, loffset + 10, linelen - 10);
+ col_append_str(pinfo->cinfo, COL_INFO, tvb_get_ephemeral_string(tvb, loffset, 10));
+ col_append_str(pinfo->cinfo, COL_INFO, decrypt);
+ }
+ else {
+ base64_string = tvb_get_ephemeral_string(tvb, loffset + 10, linelen - 10);
+ col_append_str(pinfo->cinfo, COL_INFO, tvb_get_ephemeral_string(tvb, loffset, 10));
+ dissect_ntlm_auth(tvb, pinfo, cmdresp_tree, base64_string);
+ }
+ }
+ else {
+ col_append_str(pinfo->cinfo, COL_INFO, tvb_get_ephemeral_string(tvb, loffset, 10));
+ col_append_str(pinfo->cinfo, COL_INFO, decrypt);
+ }
+ }
+ else if ((linelen > 5) && (session_state->user_pass_cmd_frame == pinfo->fd->num) ) {
+ proto_tree_add_item(cmdresp_tree, hf_smtp_req_parameter, tvb,
+ loffset + 5, linelen - 5, ENC_ASCII|ENC_NA);
+ base64_plain = tvb_get_ephemeral_string(tvb, loffset + 10, linelen - 10);
+ /* FIXME when stmp_decryption_enabled is active the plain mechs credentials
+ * should also be decoded.
+ * Format is:
+ * [authorize-user]+[NULL character]+[authentication-user]+[NULL character]+[password]
+ */
+ proto_tree_add_string(cmdresp_tree, hf_smtp_username, tvb,
+ loffset + 10, linelen - 10, base64_plain);
+ proto_tree_add_string(cmdresp_tree, hf_smtp_password, tvb,
+ loffset + 10, linelen - 10, base64_plain);
+ col_append_str(pinfo->cinfo, COL_INFO, tvb_get_ephemeral_string(tvb, loffset, 11));
+ col_append_str(pinfo->cinfo, COL_INFO, base64_plain);
+ }
else if (linelen > 5) {
proto_tree_add_item(cmdresp_tree, hf_smtp_req_parameter, tvb,
loffset + 5, linelen - 5, ENC_ASCII|ENC_NA);
@@ -911,16 +1042,32 @@ dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
case SMTP_AUTH_STATE_USERNAME_RSP:
session_state->auth_state = SMTP_AUTH_STATE_PASSWORD_REQ;
break;
+ case SMTP_AUTH_STATE_PLAIN_REQ:
+ session_state->auth_state = SMTP_AUTH_STATE_PLAIN_RSP;
+ break;
+ case SMTP_AUTH_STATE_PLAIN_START_REQ:
+ session_state->auth_state = SMTP_AUTH_STATE_PLAIN_REQ;
+ break;
+ case SMTP_AUTH_STATE_NTLM_REQ:
+ session_state->auth_state = SMTP_AUTH_STATE_NTLM_CHALLANGE;
+ break;
case SMTP_AUTH_STATE_NONE:
case SMTP_AUTH_STATE_USERNAME_REQ:
case SMTP_AUTH_STATE_PASSWORD_REQ:
case SMTP_AUTH_STATE_PASSWORD_RSP:
+ case SMTP_AUTH_STATE_PLAIN_RSP:
+ case SMTP_AUTH_STATE_PLAIN_CRED_REQ:
+ case SMTP_AUTH_STATE_NTLM_RSP:
+ case SMTP_AUTH_STATE_NTLM_CHALLANGE:
case SMTP_AUTH_STATE_SUCCESS:
case SMTP_AUTH_STATE_FAILED:
/* ignore */
break;
}
- } else if (session_state->auth_state == SMTP_AUTH_STATE_PASSWORD_RSP) {
+ } else if ((session_state->auth_state == SMTP_AUTH_STATE_PASSWORD_RSP) ||
+ ( session_state->auth_state == SMTP_AUTH_STATE_PLAIN_RSP) ||
+ ( session_state->auth_state == SMTP_AUTH_STATE_NTLM_RSP) ||
+ ( session_state->auth_state == SMTP_AUTH_STATE_PLAIN_CRED_REQ) ) {
if (code == 235) {
session_state->auth_state = SMTP_AUTH_STATE_SUCCESS;
} else {
@@ -940,10 +1087,19 @@ dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if ((stmp_decryption_enabled) && (code == 334)) {
decrypt = tvb_get_ephemeral_string(tvb, offset + 4, linelen - 4);
if (epan_base64_decode(decrypt) > 0) {
+ if (g_ascii_strncasecmp(decrypt, "NTLMSSP", 7) == 0) {
+ base64_string = tvb_get_ephemeral_string(tvb, loffset + 4, linelen - 4);
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%d ", code);
+ proto_tree_add_string(cmdresp_tree, hf_smtp_rsp_parameter, tvb,
+ offset + 4, linelen - 4, (const char*)base64_string);
+ dissect_ntlm_auth(tvb, pinfo, cmdresp_tree, base64_string);
+ }
+ else {
proto_tree_add_string(cmdresp_tree, hf_smtp_rsp_parameter, tvb,
offset + 4, linelen - 4, (const char*)decrypt);
col_append_fstr(pinfo->cinfo, COL_INFO, "%d %s", code, decrypt);
+ }
} else {
decrypt = NULL;
}
@@ -1127,6 +1283,9 @@ proto_reg_handoff_smtp(void)
/* find the SSL dissector */
ssl_handle = find_dissector("ssl");
+
+ /* find the NTLM dissector */
+ ntlmssp_handle = find_dissector("ntlmssp");
}
/*