From: Philippe Antoine Date: Fri, 1 Jul 2022 11:30:46 +0000 (+0200) Subject: ftp: adds server side detection X-Git-Tag: suricata-8.0.0-beta1~1004 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=694b2797cd31f10881d6d5d475f1aaa9eeef7bb4;p=thirdparty%2Fsuricata.git ftp: adds server side detection --- diff --git a/src/app-layer-ftp.c b/src/app-layer-ftp.c index fc64d1eb20..a1a99d4bd7 100644 --- a/src/app-layer-ftp.c +++ b/src/app-layer-ftp.c @@ -965,6 +965,31 @@ static AppProto FTPUserProbingParser( return ALPROTO_FTP; } +static AppProto FTPServerProbingParser( + Flow *f, uint8_t direction, const uint8_t *input, uint32_t len, uint8_t *rdir) +{ + // another check for minimum length + if (len < 5) { + return ALPROTO_UNKNOWN; + } + // begins by 220 + if (input[0] != '2' || input[1] != '2' || input[2] != '0') { + return ALPROTO_FAILED; + } + // followed by space or hypen + if (input[3] != ' ' && input[3] != '-') { + return ALPROTO_FAILED; + } + if (f->alproto_ts == ALPROTO_FTP || (f->todstbytecnt > 4 && f->alproto_ts == ALPROTO_UNKNOWN)) { + // only validates FTP if client side was FTP + // or if client side is unknown despite having received bytes + if (memchr(input + 4, '\n', len - 4) != NULL) { + return ALPROTO_FTP; + } + } + return ALPROTO_UNKNOWN; +} + static int FTPRegisterPatternsForProtocolDetection(void) { if (AppLayerProtoDetectPMRegisterPatternCI( @@ -987,7 +1012,15 @@ static int FTPRegisterPatternsForProtocolDetection(void) IPPROTO_TCP, ALPROTO_FTP, "PORT ", 5, 0, STREAM_TOSERVER) < 0) { return -1; } - + // Only check FTP on known ports as the banner has nothing special beyond + // the response code shared with SMTP. + if (!AppLayerProtoDetectPPParseConfPorts( + "tcp", IPPROTO_TCP, "ftp", ALPROTO_FTP, 0, 5, NULL, FTPServerProbingParser)) { + // STREAM_TOSERVER here means use 21 as flow destination port + // and NULL, FTPServerProbingParser means use probing parser to client + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "21", ALPROTO_FTP, 0, 5, STREAM_TOSERVER, NULL, + FTPServerProbingParser); + } return 0; }