aboutsummaryrefslogtreecommitdiff
path: root/src/lib/protocols/mail_smtp.c
diff options
context:
space:
mode:
authorIvan Nardi <12729895+IvanNardi@users.noreply.github.com>2021-11-11 11:55:56 +0100
committerGitHub <noreply@github.com>2021-11-11 11:55:56 +0100
commit0f168d9150cfcc94464b84591605a2c5e17c728e (patch)
treee6bb951d91ce2413b86917744a376a57a636544e /src/lib/protocols/mail_smtp.c
parent9abf528c8ed2256c7a091d9f69c506987c8c756a (diff)
IMAP, POP3, SMTP: improve dissection (#1368)
Avoid NATS false positives
Diffstat (limited to 'src/lib/protocols/mail_smtp.c')
-rw-r--r--src/lib/protocols/mail_smtp.c97
1 files changed, 86 insertions, 11 deletions
diff --git a/src/lib/protocols/mail_smtp.c b/src/lib/protocols/mail_smtp.c
index 7ee1cdd8d..551f67886 100644
--- a/src/lib/protocols/mail_smtp.c
+++ b/src/lib/protocols/mail_smtp.c
@@ -38,12 +38,13 @@
#define SMTP_BIT_HELO_EHLO 0x20
#define SMTP_BIT_MAIL 0x40
#define SMTP_BIT_RCPT 0x80
-#define SMTP_BIT_AUTH 0x100
+#define SMTP_BIT_AUTH_LOGIN 0x100
#define SMTP_BIT_STARTTLS 0x200
#define SMTP_BIT_DATA 0x400
#define SMTP_BIT_NOOP 0x800
#define SMTP_BIT_RSET 0x1000
#define SMTP_BIT_TlRM 0x2000
+#define SMTP_BIT_AUTH_PLAIN 0x4000
/* #define SMTP_DEBUG 1 */
@@ -65,6 +66,53 @@ static void smtpInitExtraPacketProcessing(struct ndpi_flow_struct *flow);
/* **************************************** */
+static void get_credentials_auth_plain(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow,
+ const u_int8_t *line, u_int16_t line_len)
+{
+ u_int8_t buf[255];
+ u_char *out;
+ size_t i, out_len;
+ unsigned int user_len = 0;
+
+ /* AUTH PLAIN XXXXXX */
+ if(line_len <= 11)
+ return;
+
+ line += 11;
+ line_len -= 11;
+
+ ndpi_user_pwd_payload_copy(buf, sizeof(buf), 0, line, line_len);
+ out = ndpi_base64_decode(buf, strlen((char *)buf), &out_len);
+ if(!out)
+ return;
+ /* No guarantee that out is null terminated:
+ UTF8NUL authcid UTF8NUL passwd */
+ for(i = 1; i < out_len; i++) {
+ if(out[i] == '\0')
+ user_len = i - 1;
+ }
+ if(user_len > 0) {
+ user_len = ndpi_min(user_len, sizeof(flow->protos.ftp_imap_pop_smtp.username) - 1);
+
+ memcpy(flow->protos.ftp_imap_pop_smtp.username, out + 1, user_len);
+ flow->protos.ftp_imap_pop_smtp.username[user_len] = '\0';
+
+ ndpi_set_risk(ndpi_struct, flow, NDPI_CLEAR_TEXT_CREDENTIALS);
+
+ if(1 + user_len + 1 < out_len) {
+ unsigned int pwd_len;
+
+ pwd_len = ndpi_min(out_len - (1 + user_len + 1), sizeof(flow->protos.ftp_imap_pop_smtp.password) - 1);
+ memcpy(flow->protos.ftp_imap_pop_smtp.password, out + 1 + user_len + 1, pwd_len);
+ flow->protos.ftp_imap_pop_smtp.password[pwd_len] = '\0';
+ }
+ }
+ ndpi_free(out);
+}
+
+/* **************************************** */
+
void ndpi_search_mail_smtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
@@ -102,10 +150,14 @@ void ndpi_search_mail_smtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
len = ndpi_min(len, sizeof(flow->host_server_name)-1);
strncpy((char*)flow->host_server_name, (char*)&packet->line[a].ptr[4], len);
flow->host_server_name[len] = '\0';
-
- ndpi_match_hostname_protocol(ndpi_struct, flow, NDPI_PROTOCOL_MAIL_SMTP,
- (char *)flow->host_server_name,
- strlen((const char *)flow->host_server_name));
+ if(ndpi_match_hostname_protocol(ndpi_struct, flow, NDPI_PROTOCOL_MAIL_SMTP,
+ (char *)flow->host_server_name,
+ strlen((const char *)flow->host_server_name))) {
+ /* We set the protocols; we need to initialize extra dissection
+ to search for credentials */
+ NDPI_LOG_DBG(ndpi_struct, "SMTP: hostname matched\n");
+ smtpInitExtraPacketProcessing(flow);
+ }
}
}
}
@@ -139,6 +191,8 @@ void ndpi_search_mail_smtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
&& packet->line[a].ptr[4] == ' ') {
flow->l4.tcp.smtp_command_bitmask |= SMTP_BIT_MAIL;
flow->protos.ftp_imap_pop_smtp.auth_found = 0;
+ /* We shouldn't be here if there are credentials */
+ flow->protos.ftp_imap_pop_smtp.auth_done = 1;
} else if((packet->line[a].ptr[0] == 'R' || packet->line[a].ptr[0] == 'r')
&& (packet->line[a].ptr[1] == 'C' || packet->line[a].ptr[1] == 'c')
&& (packet->line[a].ptr[2] == 'P' || packet->line[a].ptr[2] == 'p')
@@ -146,6 +200,8 @@ void ndpi_search_mail_smtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
&& packet->line[a].ptr[4] == ' ') {
flow->l4.tcp.smtp_command_bitmask |= SMTP_BIT_RCPT;
flow->protos.ftp_imap_pop_smtp.auth_found = 0;
+ /* We shouldn't be here if there are credentials */
+ flow->protos.ftp_imap_pop_smtp.auth_done = 1;
} else if((packet->line[a].ptr[0] == 'A' || packet->line[a].ptr[0] == 'a')
&& (packet->line[a].ptr[1] == 'U' || packet->line[a].ptr[1] == 'u')
&& (packet->line[a].ptr[2] == 'T' || packet->line[a].ptr[2] == 't')
@@ -154,16 +210,27 @@ void ndpi_search_mail_smtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
#ifdef SMTP_DEBUG
printf("%s() AUTH [%.*s]\n", __FUNCTION__, packet->line[a].len, packet->line[a].ptr);
#endif
-
- flow->l4.tcp.smtp_command_bitmask |= SMTP_BIT_AUTH;
flow->protos.ftp_imap_pop_smtp.auth_found = 1;
+ if(packet->line[a].len >= 6) {
+ if(packet->line[a].ptr[5] == 'L' || packet->line[a].ptr[5] == 'l') {
+ flow->l4.tcp.smtp_command_bitmask |= SMTP_BIT_AUTH_LOGIN;
+ /* AUTH LOGIN: Username and pwd on the next messages */
+ } else if(packet->line[a].ptr[5] == 'P' || packet->line[a].ptr[5] == 'p') {
+ flow->l4.tcp.smtp_command_bitmask |= SMTP_BIT_AUTH_PLAIN;
+ /* AUTH PLAIN: username and pwd here */
+ get_credentials_auth_plain(ndpi_struct, flow,
+ packet->line[a].ptr, packet->line[a].len);
+ flow->protos.ftp_imap_pop_smtp.auth_done = 1;
+ }
+ }
} else {
if(packet->line[a].ptr[3] != ' ') {
#ifdef SMTP_DEBUG
printf("%s() => [%.*s]\n", __FUNCTION__, packet->line[a].len, packet->line[a].ptr);
#endif
- if(flow->protos.ftp_imap_pop_smtp.auth_found) {
+ if(flow->protos.ftp_imap_pop_smtp.auth_found &&
+ (flow->l4.tcp.smtp_command_bitmask & SMTP_BIT_AUTH_LOGIN)) {
if(flow->protos.ftp_imap_pop_smtp.username[0] == '\0') {
/* Username */
u_int8_t buf[48];
@@ -214,6 +281,8 @@ void ndpi_search_mail_smtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
}
ndpi_set_risk(ndpi_struct, flow, NDPI_CLEAR_TEXT_CREDENTIALS);
+
+ flow->protos.ftp_imap_pop_smtp.auth_done = 1;
} else {
flow->host_server_name[0] = '\0';
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
@@ -234,6 +303,8 @@ void ndpi_search_mail_smtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
&& (packet->line[a].ptr[6] == 'L' || packet->line[a].ptr[6] == 'l')
&& (packet->line[a].ptr[7] == 'S' || packet->line[a].ptr[7] == 's')) {
flow->l4.tcp.smtp_command_bitmask |= SMTP_BIT_STARTTLS;
+ flow->protos.ftp_imap_pop_smtp.auth_tls = 1;
+ flow->protos.ftp_imap_pop_smtp.auth_done = 1;
}
}
@@ -274,8 +345,12 @@ void ndpi_search_mail_smtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
bit_count, flow->protos.ftp_imap_pop_smtp.password);
#endif
- ndpi_int_mail_smtp_add_connection(ndpi_struct, flow);
- smtpInitExtraPacketProcessing(flow);
+ /* Only if we don't have already set the protocol via hostname matching */
+ if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN &&
+ flow->detected_protocol_stack[1] == NDPI_PROTOCOL_UNKNOWN) {
+ ndpi_int_mail_smtp_add_connection(ndpi_struct, flow);
+ smtpInitExtraPacketProcessing(flow);
+ }
return;
}
@@ -324,7 +399,7 @@ static void smtpInitExtraPacketProcessing(struct ndpi_flow_struct *flow) {
#endif
flow->check_extra_packets = 1;
- /* At most 7 packets should almost always be enough */
+ /* At most 12 packets should almost always be enough */
flow->max_extra_packets_to_check = 12;
flow->extra_packets_func = ndpi_extra_search_mail_smtp_tcp;
}