ftp: support APPE data transfers

Support the APPE (append) command on the ftp data channel. Like STOR,
APPE uploads file content on the data channel.

Ticket: #8664
pull/15726/head
Jason Ish 4 weeks ago committed by Victor Julien
parent 5856ced29c
commit e65bf4c905

@ -7,12 +7,12 @@ ftpdata_command
---------------
Filter ftp-data channel based on command used on the FTP command channel.
Currently supported commands are STOR (put on a file), RETR (get a file), and
NLST, LIST and MLSD (list directory contents).
Currently supported commands are STOR and APPE (put/upload a file), RETR (get a
file), and NLST, LIST and MLSD (list directory contents).
Syntax::
ftpdata_command:(stor|retr|nlst|list|mlsd)
ftpdata_command:(stor|appe|retr|nlst|list|mlsd)
Signature Example:

@ -480,7 +480,8 @@ static AppLayerResult FTPParseRequest(Flow *f, void *ftp_state, AppLayerParserSt
* For ftp active mode, data connection direction is opposite to
* control direction.
*/
if ((state->active && state->command == FTP_COMMAND_STOR) ||
if ((state->active &&
(state->command == FTP_COMMAND_STOR || state->command == FTP_COMMAND_APPE)) ||
(!state->active &&
(state->command == FTP_COMMAND_RETR || state->command == FTP_COMMAND_NLST ||
state->command == FTP_COMMAND_LIST ||
@ -515,6 +516,8 @@ static AppLayerResult FTPParseRequest(Flow *f, void *ftp_state, AppLayerParserSt
case FTP_COMMAND_RETR:
// fallthrough
case FTP_COMMAND_STOR:
// fallthrough
case FTP_COMMAND_APPE:
/* Ensure that there is a file name
* -- need more than 5 chars: cmd [4], space, <filename>
*/
@ -1090,6 +1093,11 @@ static AppLayerResult FTPDataParse(Flow *f, FtpDataState *ftpdata_state,
SCLogDebug("STOR data to %s",
(ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient");
break;
case FTP_COMMAND_APPE:
ftpdata_state->direction = data->direction;
SCLogDebug("APPE data to %s",
(ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient");
break;
case FTP_COMMAND_RETR:
ftpdata_state->direction = data->direction;
SCLogDebug("RETR data to %s",
@ -1461,6 +1469,9 @@ bool EveFTPDataAddMetadata(void *vtx, SCJsonBuilder *jb)
case FTP_COMMAND_STOR:
JB_SET_STRING(jb, "command", "STOR");
break;
case FTP_COMMAND_APPE:
JB_SET_STRING(jb, "command", "APPE");
break;
case FTP_COMMAND_RETR:
JB_SET_STRING(jb, "command", "RETR");
break;

@ -37,7 +37,7 @@
/**
* \brief Regex for parsing our keyword options
*/
#define PARSE_REGEX "^\\s*(stor|retr|nlst|list|mlsd)\\s*$"
#define PARSE_REGEX "^\\s*(stor|appe|retr|nlst|list|mlsd)\\s*$"
static DetectParseRegex parse_regex;
/* Prototypes of functions registered in DetectFtpdataRegister below */
@ -143,6 +143,8 @@ static DetectFtpdataData *DetectFtpdataParse(const char *ftpcommandstr)
goto error;
if (!strcmp(arg1, "stor")) {
ftpcommandd->command = FTP_COMMAND_STOR;
} else if (!strcmp(arg1, "appe")) {
ftpcommandd->command = FTP_COMMAND_APPE;
} else if (!strcmp(arg1, "retr")) {
ftpcommandd->command = FTP_COMMAND_RETR;
} else if (!strcmp(arg1, "nlst")) {
@ -218,6 +220,11 @@ static int DetectFtpdataParseTest01(void)
FAIL_IF(!(ftpcommandd->command == FTP_COMMAND_STOR));
DetectFtpdataFree(NULL, ftpcommandd);
ftpcommandd = DetectFtpdataParse("appe");
FAIL_IF_NULL(ftpcommandd);
FAIL_IF(!(ftpcommandd->command == FTP_COMMAND_APPE));
DetectFtpdataFree(NULL, ftpcommandd);
ftpcommandd = DetectFtpdataParse("list");
FAIL_IF_NULL(ftpcommandd);
FAIL_IF(!(ftpcommandd->command == FTP_COMMAND_LIST));
@ -240,13 +247,16 @@ static int DetectFtpdataSignatureTest01(void)
sig = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (ftpdata_command:retr; sid:2; rev:1;)");
FAIL_IF_NULL(sig);
sig = DetectEngineAppendSig(
de_ctx, "alert ip any any -> any any (ftpdata_command:list; sid:3; rev:1;)");
de_ctx, "alert ip any any -> any any (ftpdata_command:appe; sid:3; rev:1;)");
FAIL_IF_NULL(sig);
sig = DetectEngineAppendSig(
de_ctx, "alert ip any any -> any any (ftpdata_command:list; sid:4; rev:1;)");
FAIL_IF_NULL(sig);
sig = DetectEngineAppendSig(
de_ctx, "alert ip any any -> any any (ftpdata_command:mlsd; sid:4; rev:1;)");
de_ctx, "alert ip any any -> any any (ftpdata_command:mlsd; sid:5; rev:1;)");
FAIL_IF_NULL(sig);
sig = DetectEngineAppendSig(
de_ctx, "alert ip any any -> any any (ftpdata_command:xxx; sid:5; rev:1;)");
de_ctx, "alert ip any any -> any any (ftpdata_command:xxx; sid:6; rev:1;)");
FAIL_IF_NOT_NULL(sig);
DetectEngineCtxFree(de_ctx);

Loading…
Cancel
Save