]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1731 in SNORT/snort3 from ~KAMURTHI/snort3:FTP_multi_split_resp...
authorShravan Rangarajuvenkata (shrarang) <shrarang@cisco.com>
Mon, 9 Sep 2019 16:15:09 +0000 (12:15 -0400)
committerShravan Rangarajuvenkata (shrarang) <shrarang@cisco.com>
Mon, 9 Sep 2019 16:15:09 +0000 (12:15 -0400)
Squashed commit of the following:

commit cfd2c0bea4045d59846a71a51070047d46dbd708
Author: Kanimozhi Murthi <kamurthi@cisco.com>
Date:   Tue Sep 3 16:29:52 2019 -0400

    appid: ftp banners on multiple packets with split response code

src/network_inspectors/appid/service_plugins/service_ftp.cc

index 600417a89bf4f26a548aedd4b247d0f7f1667b08..e34c039e03f523b0d7fada07d326d4194955e1e2 100644 (file)
@@ -48,7 +48,17 @@ enum FTPReplyState
     FTP_REPLY_BEGIN,
     FTP_REPLY_MULTI,
     FTP_REPLY_LONG,
-    FTP_REPLY_MID
+    FTP_REPLY_MID,
+    FTP_REPLY_PARTIAL_EOL,
+    FTP_REPLY_PARTIAL_RESP
+};
+
+enum FtpEolReturn
+{
+    FTP_FOUND_EOL,
+    FTP_NOT_FOUND_EOL,
+    FTP_PARTIAL_EOL,
+    FTP_INCORRECT_EOL,
 };
 
 enum FTPCmd
@@ -69,6 +79,9 @@ struct ServiceFTPData
     FTPCmd cmd;
     SfIp address;
     uint16_t port;
+    int part_code_resp = 0;
+    int part_code_len;
+    
 };
 
 #pragma pack(1)
@@ -294,7 +307,7 @@ static int CheckVendorVersion(const uint8_t* data, uint16_t init_offset,
     return 0;
 }
 
-static int ftp_parse_response(const uint8_t* data, uint16_t& offset, 
+static FtpEolReturn ftp_parse_response(const uint8_t* data, uint16_t& offset, 
     uint16_t size, ServiceFTPData& fd, FTPReplyState rstate)
 {
     for (; offset < size; ++offset)
@@ -302,31 +315,67 @@ static int ftp_parse_response(const uint8_t* data, uint16_t& offset,
         if (data[offset] == 0x0D)
         {
             if (++offset >= size)
-                return -1;
+                return FTP_PARTIAL_EOL;
             if (data[offset] == 0x0D)
             {
                 if (++offset >= size)
-                    return -1;
+                    return FTP_PARTIAL_EOL;
             }
             if (data[offset] != 0x0A)
-                return -1;
+                return FTP_INCORRECT_EOL;
             fd.rstate = rstate;
-            break;
+            return FTP_FOUND_EOL;
         }
         if (data[offset] == 0x0A)
         {
             fd.rstate = rstate;
+            return FTP_FOUND_EOL;
+        }
+    }
+    return FTP_NOT_FOUND_EOL;
+}
+
+static bool check_ret_digit_code(const uint8_t* code_raw, int start_digit_place, int end_digit_place, int& code, ServiceFTPData& fd)
+{
+    bool ret = true;
+    for (int index = 0; start_digit_place >= end_digit_place; start_digit_place--, index++)
+    {
+        switch (start_digit_place)
+        {
+        case 3:
+            if (code_raw[index] >='1' and code_raw[index] <= '5')
+                code += (code_raw[index] - '0') * 100;
+            else
+                ret = false;
+            break;    
+        case 2:
+            if (ret and fd.rstate == FTP_REPLY_BEGIN and  code_raw[index ] >='0' and code_raw[index] <= '5')
+                code += (code_raw[index] - '0') * 10;
+            else if (ret and fd.rstate != FTP_REPLY_BEGIN and  code_raw[index ] >='1' and code_raw[index] <= '5')
+                code += (code_raw[index] - '0') * 10;
+            else 
+                ret = false;
+            break;  
+        case 1:     
+            if (ret and isdigit(code_raw[index ]))
+                code += (code_raw[index] - '0') ;
+            else 
+                ret = false;
+            break;
+        default:
             break;
         }
     }
-    return 0;
+    
+    return ret;
 }
 
 static int ftp_validate_reply(const uint8_t* data, uint16_t& offset,
     uint16_t size, ServiceFTPData& fd)
 {
     const ServiceFTPCode* code_hdr;
-    int tmp;
+    int tmp = 0 ;
+    bool ret_code;
     FTPReplyState tmp_state;
 
     for (; offset < size; ++offset)
@@ -346,23 +395,17 @@ static int ftp_validate_reply(const uint8_t* data, uint16_t& offset,
 
             code_hdr = (const ServiceFTPCode*)(data + offset);
 
+            fd.code = 0;
+            ret_code = check_ret_digit_code(code_hdr->code, 3,1, fd.code, fd );
+            
+            if(!ret_code)
+                return -1; 
+
             if (code_hdr->sp == '-')
                 fd.rstate = FTP_REPLY_MULTI;
             else if (code_hdr->sp != ' ' and code_hdr->sp != 0x09)
                 return -1;
 
-            if (code_hdr->code[0] < '1' or code_hdr->code[0] > '5')
-                return -1;
-            fd.code = (code_hdr->code[0] - '0') * 100;
-
-            if (code_hdr->code[1] < '0' or code_hdr->code[1] > '5')
-                return -1;
-            fd.code += (code_hdr->code[1] - '0') * 10;
-
-            if (!isdigit(code_hdr->code[2]))
-                return -1;
-            fd.code += code_hdr->code[2] - '0';
-
             offset += sizeof(ServiceFTPCode);
             tmp_state = fd.rstate;
 
@@ -422,31 +465,41 @@ static int ftp_validate_reply(const uint8_t* data, uint16_t& offset,
             }
 
             fd.rstate = FTP_REPLY_MID;
-            if (ftp_parse_response(data, offset, size, fd, tmp_state))
+            
+            if ( ftp_parse_response(data, offset, size, fd, tmp_state ) == FTP_INCORRECT_EOL)
                 return -1;
             if (fd.rstate == FTP_REPLY_MID)
                 fd.rstate = FTP_REPLY_LONG;
+                 
             break;
         case FTP_REPLY_MULTI:
             if (size - offset < (int)sizeof(ServiceFTPCode))
             {
                 fd.rstate = FTP_REPLY_MID;
-                if (ftp_parse_response(data, offset, size, fd, FTP_REPLY_MULTI))
+                int temp = offset;
+                FtpEolReturn parse_ret = ftp_parse_response(data, offset, size, fd, FTP_REPLY_MULTI);
+                if( parse_ret == FTP_INCORRECT_EOL)
                     return -1;
+                else if (parse_ret == FTP_PARTIAL_EOL)
+                    fd.rstate = FTP_REPLY_PARTIAL_EOL;
+                else if (parse_ret == FTP_NOT_FOUND_EOL)
+                {
+                    check_ret_digit_code((data+temp), 3, 4 - (size - (temp)), fd.part_code_resp, fd );
+                    fd.rstate = FTP_REPLY_PARTIAL_RESP;
+                    fd.part_code_len = 3 - (size - (temp ));
+                }
+
                 if (fd.rstate == FTP_REPLY_MID)
                     fd.rstate = FTP_REPLY_LONG;
+                    
             }
             else
             {
                 code_hdr = (const ServiceFTPCode*)(data + offset);
-                if ((code_hdr->sp == ' ' or code_hdr->sp == 0x09) and
-                    code_hdr->code[0] >= '1' and code_hdr->code[0] <= '5' and
-                    code_hdr->code[1] >= '1' and code_hdr->code[1] <= '5' and
-                    isdigit(code_hdr->code[2]))
+                tmp = 0;
+
+                if (check_ret_digit_code(code_hdr->code, 3,1, tmp, fd) and (code_hdr->sp == ' ' or code_hdr->sp == 0x09))
                 {
-                    tmp = (code_hdr->code[0] - '0') * 100;
-                    tmp += (code_hdr->code[1] - '0') * 10;
-                    tmp += code_hdr->code[2] - '0';
                     if (tmp == fd.code)
                     {
                         offset += sizeof(ServiceFTPCode);
@@ -455,57 +508,72 @@ static int ftp_validate_reply(const uint8_t* data, uint16_t& offset,
                 }
                 tmp_state = fd.rstate;
                 fd.rstate = FTP_REPLY_MID;
-                if (ftp_parse_response(data, offset, size, fd, tmp_state))
+                if (ftp_parse_response(data, offset, size, fd, tmp_state) == FTP_INCORRECT_EOL)
                     return -1;
                 if (fd.rstate == FTP_REPLY_MID)
                     fd.rstate = FTP_REPLY_LONG;
             }
             break;
+        case FTP_REPLY_PARTIAL_EOL:
+        case FTP_REPLY_PARTIAL_RESP:
         case FTP_REPLY_LONG:
-            fd.rstate = FTP_REPLY_MID;
-            if (ftp_parse_response(data, offset, size, fd, FTP_REPLY_LONG))
-                return -1;
-            if (++offset >= size)
-            {
-                fd.rstate = FTP_REPLY_BEGIN;
-                break;
-            }
-            if (fd.rstate == FTP_REPLY_MID)
+            if (fd.rstate != FTP_REPLY_PARTIAL_RESP)
             {
-                fd.rstate = FTP_REPLY_LONG;
-                break;
+                fd.rstate = FTP_REPLY_MID;
+                if (ftp_parse_response(data, offset, size, fd, FTP_REPLY_LONG)== FTP_INCORRECT_EOL)
+                    return -1;
+                if (++offset >= size)
+                {
+                    fd.rstate = FTP_REPLY_BEGIN;
+                    break;
+                }
+                if (fd.rstate == FTP_REPLY_MID)
+                {
+                    fd.rstate = FTP_REPLY_LONG;
+                    break;
+                }
             }
             if (size - offset < (int)sizeof(ServiceFTPCode))
             {
                 fd.rstate = FTP_REPLY_MID;
-                if (ftp_parse_response(data, offset, size, fd, FTP_REPLY_LONG))
+                if (ftp_parse_response(data, offset, size, fd, FTP_REPLY_LONG)  == FTP_INCORRECT_EOL)
                     return -1;
                 if (fd.rstate == FTP_REPLY_MID)
                     fd.rstate = FTP_REPLY_LONG;
             }
             else
             {
-                code_hdr = (const ServiceFTPCode*)(data + offset);
-                if(code_hdr->code[0] >= '1' and code_hdr->code[0] <= '5' and
-                    code_hdr->code[1] >= '1' and code_hdr->code[1] <= '5' and
-                    isdigit(code_hdr->code[2]))
+                if (fd.rstate == FTP_REPLY_PARTIAL_RESP)
                 {
-                    tmp = (code_hdr->code[0] - '0') * 100;
-                    tmp += (code_hdr->code[1] - '0') * 10;
-                    tmp += code_hdr->code[2] - '0';
-                    if (tmp == fd.code)
+                    tmp = 0;
+                    ret_code = check_ret_digit_code(data + offset, fd.part_code_len ,1, tmp, fd);
+
+                    if(!ret_code)
+                        return -1;
+                    fd.code = tmp + fd.part_code_resp;
+                    fd.part_code_resp = 0; 
+                    if (ftp_parse_response(data, offset, size, fd, FTP_REPLY_LONG)  == FTP_INCORRECT_EOL)
+                        return -1;
+
+                }
+                else
+                {
+                    code_hdr = (const ServiceFTPCode*)(data + offset);
+                    tmp = 0;
+
+                    if (check_ret_digit_code(code_hdr->code, 3,1, tmp, fd) and tmp == fd.code)
                     {
                         offset += sizeof(ServiceFTPCode);
                         if (code_hdr->sp == ' ' or code_hdr->sp == 0x09)
                         {
                             fd.rstate = FTP_REPLY_MID;
-                            if (ftp_parse_response(data, offset, size, fd, FTP_REPLY_BEGIN))
+                            if (ftp_parse_response(data, offset, size, fd, FTP_REPLY_BEGIN) == FTP_INCORRECT_EOL)
                                 return -1;
                         }
                         else if (code_hdr->sp == '-')
                         {
                             fd.rstate = FTP_REPLY_MID;
-                            if (ftp_parse_response(data, offset, size, fd, FTP_REPLY_MULTI))
+                            if (ftp_parse_response(data, offset, size, fd, FTP_REPLY_MULTI) == FTP_INCORRECT_EOL)
                                 return -1;
                         }
                         if (fd.rstate == FTP_REPLY_MID)