ftp: support LIST and MLSD data channels

Support LIST and MLSD on the ftp data channel.

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

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

@ -84,4 +84,5 @@ pub enum FtpRequestCommand {
FTP_COMMAND_UMASK,
FTP_COMMAND_USER,
FTP_COMMAND_EPRT,
FTP_COMMAND_MLSD,
}

@ -78,6 +78,7 @@ lazy_static! {
FtpCommand::new("MDTM", FtpRequestCommand::FTP_COMMAND_MDTM),
FtpCommand::new("MKD", FtpRequestCommand::FTP_COMMAND_MKD),
FtpCommand::new("MLFL", FtpRequestCommand::FTP_COMMAND_MLFL),
FtpCommand::new("MLSD", FtpRequestCommand::FTP_COMMAND_MLSD),
FtpCommand::new("MODE", FtpRequestCommand::FTP_COMMAND_MODE),
FtpCommand::new("MRCP", FtpRequestCommand::FTP_COMMAND_MRCP),
FtpCommand::new("MRSQ", FtpRequestCommand::FTP_COMMAND_MRSQ),

@ -481,8 +481,10 @@ static AppLayerResult FTPParseRequest(Flow *f, void *ftp_state, AppLayerParserSt
* control direction.
*/
if ((state->active && state->command == FTP_COMMAND_STOR) ||
(!state->active && (state->command == FTP_COMMAND_RETR ||
state->command == FTP_COMMAND_NLST))) {
(!state->active &&
(state->command == FTP_COMMAND_RETR || state->command == FTP_COMMAND_NLST ||
state->command == FTP_COMMAND_LIST ||
state->command == FTP_COMMAND_MLSD))) {
direction = STREAM_TOCLIENT;
}
@ -523,7 +525,9 @@ static AppLayerResult FTPParseRequest(Flow *f, void *ftp_state, AppLayerParserSt
}
has_file = true;
/* fallthrough */
case FTP_COMMAND_NLST: {
case FTP_COMMAND_NLST:
case FTP_COMMAND_LIST:
case FTP_COMMAND_MLSD: {
/* Ensure a port has been negotiated. */
if (state->dyn_port == 0) {
SCAppLayerDecoderEventsSetEventRaw(&tx->tx_data.events, FtpEventFileBeforePort);
@ -1096,6 +1100,16 @@ static AppLayerResult FTPDataParse(Flow *f, FtpDataState *ftpdata_state,
SCLogDebug("NLST data to %s",
(ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient");
break;
case FTP_COMMAND_LIST:
ftpdata_state->direction = data->direction;
SCLogDebug("LIST data to %s",
(ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient");
break;
case FTP_COMMAND_MLSD:
ftpdata_state->direction = data->direction;
SCLogDebug("MLSD data to %s",
(ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient");
break;
default:
break;
}
@ -1453,6 +1467,12 @@ bool EveFTPDataAddMetadata(void *vtx, SCJsonBuilder *jb)
case FTP_COMMAND_NLST:
JB_SET_STRING(jb, "command", "NLST");
break;
case FTP_COMMAND_LIST:
JB_SET_STRING(jb, "command", "LIST");
break;
case FTP_COMMAND_MLSD:
JB_SET_STRING(jb, "command", "MLSD");
break;
default:
break;
}

@ -37,7 +37,7 @@
/**
* \brief Regex for parsing our keyword options
*/
#define PARSE_REGEX "^\\s*(stor|retr|nlst)\\s*$"
#define PARSE_REGEX "^\\s*(stor|retr|nlst|list|mlsd)\\s*$"
static DetectParseRegex parse_regex;
/* Prototypes of functions registered in DetectFtpdataRegister below */
@ -147,6 +147,10 @@ static DetectFtpdataData *DetectFtpdataParse(const char *ftpcommandstr)
ftpcommandd->command = FTP_COMMAND_RETR;
} else if (!strcmp(arg1, "nlst")) {
ftpcommandd->command = FTP_COMMAND_NLST;
} else if (!strcmp(arg1, "list")) {
ftpcommandd->command = FTP_COMMAND_LIST;
} else if (!strcmp(arg1, "mlsd")) {
ftpcommandd->command = FTP_COMMAND_MLSD;
} else {
SCLogError("Invalid command value");
goto error;
@ -213,6 +217,16 @@ static int DetectFtpdataParseTest01(void)
FAIL_IF_NULL(ftpcommandd);
FAIL_IF(!(ftpcommandd->command == FTP_COMMAND_STOR));
DetectFtpdataFree(NULL, ftpcommandd);
ftpcommandd = DetectFtpdataParse("list");
FAIL_IF_NULL(ftpcommandd);
FAIL_IF(!(ftpcommandd->command == FTP_COMMAND_LIST));
DetectFtpdataFree(NULL, ftpcommandd);
ftpcommandd = DetectFtpdataParse("mlsd");
FAIL_IF_NULL(ftpcommandd);
FAIL_IF(!(ftpcommandd->command == FTP_COMMAND_MLSD));
DetectFtpdataFree(NULL, ftpcommandd);
PASS;
}
@ -225,7 +239,14 @@ static int DetectFtpdataSignatureTest01(void)
FAIL_IF_NULL(sig);
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:xxx; sid:3; rev:1;)");
sig = DetectEngineAppendSig(
de_ctx, "alert ip any any -> any any (ftpdata_command:list; sid:3; rev:1;)");
FAIL_IF_NULL(sig);
sig = DetectEngineAppendSig(
de_ctx, "alert ip any any -> any any (ftpdata_command:mlsd; sid:4; rev:1;)");
FAIL_IF_NULL(sig);
sig = DetectEngineAppendSig(
de_ctx, "alert ip any any -> any any (ftpdata_command:xxx; sid:5; rev:1;)");
FAIL_IF_NOT_NULL(sig);
DetectEngineCtxFree(de_ctx);

Loading…
Cancel
Save