From: Jeff Lucovsky Date: Thu, 24 Apr 2025 12:46:13 +0000 (-0400) Subject: detect/ftp: Add ftp.dynamic_port keyword X-Git-Tag: suricata-8.0.0-rc1~420 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=19fe098e88085c7ed9ff809a8c65908afc56c638;p=thirdparty%2Fsuricata.git detect/ftp: Add ftp.dynamic_port keyword Issue: 7504 Add implementation of the ftp.dynamic_port rule keyword. The implementation uses the U16 integer matching/parsing and thus supports the comparison operations such as <, >, <=, >=, !, !=, and range (-). --- diff --git a/src/Makefile.am b/src/Makefile.am index ec169c585f..19f8557b39 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -168,6 +168,7 @@ noinst_HEADERS = \ detect-ftpdata.h \ detect-ftp-command.h \ detect-ftp-command-data.h \ + detect-ftp-dynamic-port.h \ detect-ftp-reply.h \ detect-geoip.h \ detect-gid.h \ @@ -754,6 +755,7 @@ libsuricata_c_a_SOURCES = \ detect-ftpdata.c \ detect-ftp-command.c \ detect-ftp-command-data.c \ + detect-ftp-dynamic-port.c \ detect-ftp-reply.c \ detect-geoip.c \ detect-gid.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 8a5710be50..9038c5fdff 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -124,6 +124,7 @@ #include "detect-requires.h" #include "detect-tcp-window.h" #include "detect-ftpbounce.h" +#include "detect-ftp-dynamic-port.h" #include "detect-isdataat.h" #include "detect-id.h" #include "detect-rpc.h" @@ -633,6 +634,7 @@ void SigTableSetup(void) DetectRpcRegister(); DetectFtpbounceRegister(); DetectFtpdataRegister(); + DetectFtpDynamicPortRegister(); DetectIsdataatRegister(); DetectIdRegister(); DetectDsizeRegister(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index d67d57e0ce..a2ba40e749 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -104,6 +104,7 @@ enum DetectKeywordId { DETECT_GEOIP, DETECT_IPPROTO, DETECT_FTPBOUNCE, + DETECT_FTP_DYNPORT, DETECT_ID, DETECT_RPC, DETECT_NOALERT, diff --git a/src/detect-ftp-dynamic-port.c b/src/detect-ftp-dynamic-port.c new file mode 100644 index 0000000000..e3f7c0e7b9 --- /dev/null +++ b/src/detect-ftp-dynamic-port.c @@ -0,0 +1,117 @@ +/* Copyright (C) 2025 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Jeff Lucovsky + * + * Implements the ftp.dynamic_port sticky buffer + * + */ + +#include "suricata-common.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-uint.h" +#include "detect-content.h" + +#include "flow.h" + +#include "util-debug.h" + +#include "app-layer.h" +#include "app-layer-ftp.h" + +#include "detect-ftp-dynamic-port.h" + +#define KEYWORD_NAME "ftp.dynamic_port" +#define KEYWORD_DOC "ftp-keywords.html#ftp-dynamic_port" +#define BUFFER_NAME "ftp.dynamic_port" +#define BUFFER_DESC "ftp dynamic_port" + +static int g_ftp_dynport_buffer_id = 0; + +static DetectU16Data *DetectFtpDynamicPortParse(const char *rawstr) +{ + return SCDetectU16Parse(rawstr); +} + +static void DetectFtpDynamicPortFree(DetectEngineCtx *de_ctx, void *ptr) +{ + SCDetectU16Free(ptr); +} + +static int DetectFtpDynamicPortSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectSignatureSetAppProto(s, ALPROTO_FTP) < 0) + return -1; + + DetectU16Data *fdp = DetectFtpDynamicPortParse(str); + if (fdp == NULL) { + SCLogError("parsing dynamic port from \"%s\" failed", str); + return -1; + } + + SCLogDebug("low %u hi %u", fdp->arg1, fdp->arg2); + if (SigMatchAppendSMToList(de_ctx, s, DETECT_FTP_DYNPORT, (SigMatchCtx *)fdp, + g_ftp_dynport_buffer_id) == NULL) { + DetectFtpDynamicPortFree(de_ctx, fdp); + return -1; + } + return 0; +} + +static int DetectFtpDynamicPortMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + FTPTransaction *tx = (FTPTransaction *)txv; + if (tx->command_descriptor.command_code == FTP_COMMAND_UNKNOWN) + return 0; + + const DetectU16Data *ftpd = (const DetectU16Data *)ctx; + + SCLogDebug("Checking for match between rule value(s) %u, %u with actual value %d", ftpd->arg1, + ftpd->arg2, tx->dyn_port); + return DetectU16Match(tx->dyn_port, ftpd); +} + +void DetectFtpDynamicPortRegister(void) +{ + /* ftp.dynamic_port sticky buffer */ + sigmatch_table[DETECT_FTP_DYNPORT].name = KEYWORD_NAME; + sigmatch_table[DETECT_FTP_DYNPORT].desc = "match on the FTP dynamic_port buffer"; + sigmatch_table[DETECT_FTP_DYNPORT].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_FTP_DYNPORT].Setup = DetectFtpDynamicPortSetup; + sigmatch_table[DETECT_FTP_DYNPORT].Free = DetectFtpDynamicPortFree; + sigmatch_table[DETECT_FTP_DYNPORT].AppLayerTxMatch = DetectFtpDynamicPortMatch; + + DetectAppLayerInspectEngineRegister( + BUFFER_NAME, ALPROTO_FTP, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL); + + DetectAppLayerInspectEngineRegister( + BUFFER_NAME, ALPROTO_FTP, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); + + g_ftp_dynport_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-ftp-dynamic-port.h b/src/detect-ftp-dynamic-port.h new file mode 100644 index 0000000000..b0f42a8e9d --- /dev/null +++ b/src/detect-ftp-dynamic-port.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2025 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Jeff Lucovsky + */ + +#ifndef SURICATA_DETECT_FTP_DYN_PORT_H +#define SURICATA_DETECT_FTP_DYN_PORT_H + +void DetectFtpDynamicPortRegister(void); + +#endif /* SURICATA_DETECT_FTP_DYN_PORT_H */