diff --git a/doc/userguide/rules/differences-from-snort.rst b/doc/userguide/rules/differences-from-snort.rst index 9ca145c5e238..a32966c4284b 100644 --- a/doc/userguide/rules/differences-from-snort.rst +++ b/doc/userguide/rules/differences-from-snort.rst @@ -19,6 +19,7 @@ Automatic Protocol Detection - dns - http - imap (detection only by default; no parsing) + - pop3 (detection only by default; no parsing) - ftp - modbus (disabled by default; minimalist probe parser; can lead to false positives) - smb diff --git a/doc/userguide/rules/intro.rst b/doc/userguide/rules/intro.rst index ab35f8a311ca..c00fbe762625 100644 --- a/doc/userguide/rules/intro.rst +++ b/doc/userguide/rules/intro.rst @@ -96,6 +96,7 @@ you can pick from. These are: * ssh * smtp * imap +* pop3 * modbus (disabled by default) * dnp3 (disabled by default) * enip (disabled by default) diff --git a/etc/schema.json b/etc/schema.json index c194017ddf6f..c0295b36411f 100644 --- a/etc/schema.json +++ b/etc/schema.json @@ -3791,6 +3791,9 @@ "pgsql": { "$ref": "#/$defs/stats_applayer_error" }, + "pop3": { + "$ref": "#/$defs/stats_applayer_error" + }, "quic": { "$ref": "#/$defs/stats_applayer_error" }, @@ -3908,6 +3911,9 @@ "pgsql": { "type": "integer" }, + "pop3": { + "type": "integer" + }, "quic": { "type": "integer" }, @@ -4019,6 +4025,9 @@ "pgsql": { "type": "integer" }, + "pop3": { + "type": "integer" + }, "quic": { "type": "integer" }, diff --git a/src/app-layer-ftp.c b/src/app-layer-ftp.c index 8925d6dd6a13..dfbc718dc8c7 100644 --- a/src/app-layer-ftp.c +++ b/src/app-layer-ftp.c @@ -951,6 +951,15 @@ static int FTPGetAlstateProgress(void *vtx, uint8_t direction) return FTP_STATE_FINISHED; } +static AppProto FTPUserProbingParser( + Flow *f, uint8_t direction, const uint8_t *input, uint32_t len, uint8_t *rdir) +{ + if (f->alproto_tc == ALPROTO_POP3) { + // POP traffic begins by same "USER" pattern as FTP + return ALPROTO_FAILED; + } + return ALPROTO_FTP; +} static int FTPRegisterPatternsForProtocolDetection(void) { @@ -962,8 +971,8 @@ static int FTPRegisterPatternsForProtocolDetection(void) IPPROTO_TCP, ALPROTO_FTP, "FEAT", 4, 0, STREAM_TOSERVER) < 0) { return -1; } - if (AppLayerProtoDetectPMRegisterPatternCI( - IPPROTO_TCP, ALPROTO_FTP, "USER ", 5, 0, STREAM_TOSERVER) < 0) { + if (AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_FTP, "USER ", 5, 0, + STREAM_TOSERVER, FTPUserProbingParser, 5, 5) < 0) { return -1; } if (AppLayerProtoDetectPMRegisterPatternCI( diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 1f6066471757..7f10c433eca5 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -1778,14 +1778,24 @@ void AppLayerParserRegisterProtocolParsers(void) if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_IMAP, "1|20|capability", 12, 0, STREAM_TOSERVER) < 0) { - SCLogInfo("imap proto registration failure"); - exit(EXIT_FAILURE); + FatalError("imap proto registration failure"); } } else { SCLogInfo("Protocol detection and parser disabled for %s protocol.", "imap"); } + /** POP3 */ + AppLayerProtoDetectRegisterProtocol(ALPROTO_POP3, "pop3"); + if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", "pop3")) { + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_POP3, "+OK ", 4, 0, STREAM_TOCLIENT) < 0) { + FatalError("pop3 proto registration failure"); + } + } else { + SCLogInfo("Protocol detection and parser disabled for pop3 protocol."); + } + ValidateParsers(); return; } diff --git a/src/app-layer-protos.c b/src/app-layer-protos.c index 368efacd88d7..e71b0e8b2937 100644 --- a/src/app-layer-protos.c +++ b/src/app-layer-protos.c @@ -64,6 +64,7 @@ const AppProtoStringTuple AppProtoStrings[ALPROTO_MAX] = { { ALPROTO_RDP, "rdp" }, { ALPROTO_HTTP2, "http2" }, { ALPROTO_BITTORRENT_DHT, "bittorrent-dht" }, + { ALPROTO_POP3, "pop3" }, { ALPROTO_HTTP, "http" }, { ALPROTO_FAILED, "failed" }, #ifdef UNITTESTS diff --git a/src/app-layer-protos.h b/src/app-layer-protos.h index dd372550cbf5..d0becafbce56 100644 --- a/src/app-layer-protos.h +++ b/src/app-layer-protos.h @@ -60,6 +60,7 @@ enum AppProtoEnum { ALPROTO_RDP, ALPROTO_HTTP2, ALPROTO_BITTORRENT_DHT, + ALPROTO_POP3, // signature-only (ie not seen in flow) // HTTP for any version (ALPROTO_HTTP1 (version 1) or ALPROTO_HTTP2) diff --git a/src/output.c b/src/output.c index 149dda58c284..b2c195ef5380 100644 --- a/src/output.c +++ b/src/output.c @@ -1163,6 +1163,7 @@ static EveJsonSimpleAppLayerLogger simple_json_applayer_loggers[ALPROTO_MAX] = { { ALPROTO_RDP, (EveJsonSimpleTxLogFunc)rs_rdp_to_json }, { ALPROTO_HTTP2, rs_http2_log_json }, { ALPROTO_BITTORRENT_DHT, rs_bittorrent_dht_logger_log }, + { ALPROTO_POP3, NULL }, // protocol detection only { ALPROTO_HTTP, NULL }, // signature protocol, not for app-layer logging { ALPROTO_FAILED, NULL }, #ifdef UNITTESTS diff --git a/suricata.yaml.in b/suricata.yaml.in index 630399126dbe..0ce289d02db2 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -971,6 +971,8 @@ app-layer: content-inspect-window: 4096 imap: enabled: detection-only + pop3: + enabled: detection-only smb: enabled: yes detection-ports: