Skip to content

Commit 272fb68

Browse files
committed
ftp: support LIST and MLSD data channels
Support LIST and MLSD on the ftp data channel. Ticket: OISF#8664
1 parent fc2c38d commit 272fb68

4 files changed

Lines changed: 48 additions & 5 deletions

File tree

rust/src/ftp/constant.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,5 @@ pub enum FtpRequestCommand {
8484
FTP_COMMAND_UMASK,
8585
FTP_COMMAND_USER,
8686
FTP_COMMAND_EPRT,
87+
FTP_COMMAND_MLSD,
8788
}

rust/src/ftp/ftp.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ lazy_static! {
7878
FtpCommand::new("MDTM", FtpRequestCommand::FTP_COMMAND_MDTM),
7979
FtpCommand::new("MKD", FtpRequestCommand::FTP_COMMAND_MKD),
8080
FtpCommand::new("MLFL", FtpRequestCommand::FTP_COMMAND_MLFL),
81+
FtpCommand::new("MLSD", FtpRequestCommand::FTP_COMMAND_MLSD),
8182
FtpCommand::new("MODE", FtpRequestCommand::FTP_COMMAND_MODE),
8283
FtpCommand::new("MRCP", FtpRequestCommand::FTP_COMMAND_MRCP),
8384
FtpCommand::new("MRSQ", FtpRequestCommand::FTP_COMMAND_MRSQ),

src/app-layer-ftp.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -481,8 +481,10 @@ static AppLayerResult FTPParseRequest(Flow *f, void *ftp_state, AppLayerParserSt
481481
* control direction.
482482
*/
483483
if ((state->active && state->command == FTP_COMMAND_STOR) ||
484-
(!state->active && (state->command == FTP_COMMAND_RETR ||
485-
state->command == FTP_COMMAND_NLST))) {
484+
(!state->active &&
485+
(state->command == FTP_COMMAND_RETR || state->command == FTP_COMMAND_NLST ||
486+
state->command == FTP_COMMAND_LIST ||
487+
state->command == FTP_COMMAND_MLSD))) {
486488
direction = STREAM_TOCLIENT;
487489
}
488490

@@ -527,7 +529,9 @@ static AppLayerResult FTPParseRequest(Flow *f, void *ftp_state, AppLayerParserSt
527529
}
528530
has_file = true;
529531
/* fallthrough */
530-
case FTP_COMMAND_NLST: {
532+
case FTP_COMMAND_NLST:
533+
case FTP_COMMAND_LIST:
534+
case FTP_COMMAND_MLSD: {
531535
/* Ensure a port has been negotiated. */
532536
if (state->dyn_port == 0) {
533537
SCAppLayerDecoderEventsSetEventRaw(&tx->tx_data.events, FtpEventFileBeforePort);
@@ -1100,6 +1104,16 @@ static AppLayerResult FTPDataParse(Flow *f, FtpDataState *ftpdata_state,
11001104
SCLogDebug("NLST data to %s",
11011105
(ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient");
11021106
break;
1107+
case FTP_COMMAND_LIST:
1108+
ftpdata_state->direction = data->direction;
1109+
SCLogDebug("LIST data to %s",
1110+
(ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient");
1111+
break;
1112+
case FTP_COMMAND_MLSD:
1113+
ftpdata_state->direction = data->direction;
1114+
SCLogDebug("MLSD data to %s",
1115+
(ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient");
1116+
break;
11031117
default:
11041118
break;
11051119
}
@@ -1457,6 +1471,12 @@ bool EveFTPDataAddMetadata(void *vtx, SCJsonBuilder *jb)
14571471
case FTP_COMMAND_NLST:
14581472
JB_SET_STRING(jb, "command", "NLST");
14591473
break;
1474+
case FTP_COMMAND_LIST:
1475+
JB_SET_STRING(jb, "command", "LIST");
1476+
break;
1477+
case FTP_COMMAND_MLSD:
1478+
JB_SET_STRING(jb, "command", "MLSD");
1479+
break;
14601480
default:
14611481
break;
14621482
}

src/detect-ftpdata.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
/**
3838
* \brief Regex for parsing our keyword options
3939
*/
40-
#define PARSE_REGEX "^\\s*(stor|retr|nlst)\\s*$"
40+
#define PARSE_REGEX "^\\s*(stor|retr|nlst|list|mlsd)\\s*$"
4141
static DetectParseRegex parse_regex;
4242

4343
/* Prototypes of functions registered in DetectFtpdataRegister below */
@@ -147,6 +147,10 @@ static DetectFtpdataData *DetectFtpdataParse(const char *ftpcommandstr)
147147
ftpcommandd->command = FTP_COMMAND_RETR;
148148
} else if (!strcmp(arg1, "nlst")) {
149149
ftpcommandd->command = FTP_COMMAND_NLST;
150+
} else if (!strcmp(arg1, "list")) {
151+
ftpcommandd->command = FTP_COMMAND_LIST;
152+
} else if (!strcmp(arg1, "mlsd")) {
153+
ftpcommandd->command = FTP_COMMAND_MLSD;
150154
} else {
151155
SCLogError("Invalid command value");
152156
goto error;
@@ -213,6 +217,16 @@ static int DetectFtpdataParseTest01(void)
213217
FAIL_IF_NULL(ftpcommandd);
214218
FAIL_IF(!(ftpcommandd->command == FTP_COMMAND_STOR));
215219
DetectFtpdataFree(NULL, ftpcommandd);
220+
221+
ftpcommandd = DetectFtpdataParse("list");
222+
FAIL_IF_NULL(ftpcommandd);
223+
FAIL_IF(!(ftpcommandd->command == FTP_COMMAND_LIST));
224+
DetectFtpdataFree(NULL, ftpcommandd);
225+
226+
ftpcommandd = DetectFtpdataParse("mlsd");
227+
FAIL_IF_NULL(ftpcommandd);
228+
FAIL_IF(!(ftpcommandd->command == FTP_COMMAND_MLSD));
229+
DetectFtpdataFree(NULL, ftpcommandd);
216230
PASS;
217231
}
218232

@@ -225,7 +239,14 @@ static int DetectFtpdataSignatureTest01(void)
225239
FAIL_IF_NULL(sig);
226240
sig = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (ftpdata_command:retr; sid:2; rev:1;)");
227241
FAIL_IF_NULL(sig);
228-
sig = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (ftpdata_command:xxx; sid:3; rev:1;)");
242+
sig = DetectEngineAppendSig(
243+
de_ctx, "alert ip any any -> any any (ftpdata_command:list; sid:3; rev:1;)");
244+
FAIL_IF_NULL(sig);
245+
sig = DetectEngineAppendSig(
246+
de_ctx, "alert ip any any -> any any (ftpdata_command:mlsd; sid:4; rev:1;)");
247+
FAIL_IF_NULL(sig);
248+
sig = DetectEngineAppendSig(
249+
de_ctx, "alert ip any any -> any any (ftpdata_command:xxx; sid:5; rev:1;)");
229250
FAIL_IF_NOT_NULL(sig);
230251

231252
DetectEngineCtxFree(de_ctx);

0 commit comments

Comments
 (0)