"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/dynamic-preprocessors/appid/service_plugins/service_rshell.c" (16 Oct 2020, 11334 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "service_rshell.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.9.16.1_vs_2.9.17.

    1 /*
    2 ** Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
    3 ** Copyright (C) 2005-2013 Sourcefire, Inc.
    4 **
    5 ** This program is free software; you can redistribute it and/or modify
    6 ** it under the terms of the GNU General Public License Version 2 as
    7 ** published by the Free Software Foundation.  You may not use, modify or
    8 ** distribute this program under any other version of the GNU General
    9 ** Public License.
   10 **
   11 ** This program is distributed in the hope that it will be useful,
   12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 ** GNU General Public License for more details.
   15 **
   16 ** You should have received a copy of the GNU General Public License
   17 ** along with this program; if not, write to the Free Software
   18 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   19 */
   20 
   21 
   22 #include <ctype.h>
   23 #include <string.h>
   24 #include <stdlib.h>
   25 #include <stddef.h>
   26 #include <sys/types.h>
   27 #include <netinet/in.h>
   28 
   29 #include "appIdApi.h"
   30 #include "appInfoTable.h"
   31 #include "flow.h"
   32 #include "service_api.h"
   33 
   34 #define RSHELL_PORT  514
   35 #define RSHELL_MAX_PORT_PACKET 6
   36 
   37 typedef enum
   38 {
   39     RSHELL_STATE_PORT,
   40     RSHELL_STATE_SERVER_CONNECT,
   41     RSHELL_STATE_USERNAME,
   42     RSHELL_STATE_USERNAME2,
   43     RSHELL_STATE_COMMAND,
   44     RSHELL_STATE_REPLY,
   45     RSHELL_STATE_DONE,
   46     RSHELL_STATE_BAIL,
   47     RSHELL_STATE_STDERR_CONNECT_SYN,
   48     RSHELL_STATE_STDERR_CONNECT_SYN_ACK,
   49     RSHELL_STATE_STDERR_WAIT,
   50     RSHELL_STATE_STDERR_DONE
   51 } RSHELLState;
   52 
   53 typedef struct _SERVICE_RSHELL_DATA
   54 {
   55     RSHELLState state;
   56     struct _SERVICE_RSHELL_DATA *parent;
   57     struct _SERVICE_RSHELL_DATA *child;
   58 } ServiceRSHELLData;
   59 
   60 static int rshell_init(const InitServiceAPI * const init_api);
   61 static int rshell_validate(ServiceValidationArgs* args);
   62 
   63 static tRNAServiceElement svc_element =
   64 {
   65     .next = NULL,
   66     .validate = &rshell_validate,
   67     .detectorType = DETECTOR_TYPE_DECODER,
   68     .name = "rshell",
   69     .ref_count = 1,
   70     .current_ref_count = 1,
   71 };
   72 
   73 static RNAServiceValidationPort pp[] =
   74 {
   75     {&rshell_validate, RSHELL_PORT, IPPROTO_TCP},
   76     {NULL, 0, 0}
   77 };
   78 
   79 tRNAServiceValidationModule rshell_service_mod =
   80 {
   81     "RSHELL",
   82     &rshell_init,
   83     pp
   84 };
   85 
   86 static tAppRegistryEntry appIdRegistry[] = {{APP_ID_SHELL, APPINFO_FLAG_SERVICE_ADDITIONAL}};
   87 
   88 static int16_t app_id = 0;
   89 
   90 static int rshell_init(const InitServiceAPI * const init_api)
   91 {
   92     unsigned i;
   93 #ifdef TARGET_BASED
   94     app_id = init_api->dpd->addProtocolReference("rsh-error");
   95 #endif
   96 
   97     for (i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
   98     {
   99         _dpd.debugMsg(DEBUG_LOG,"registering appId: %d\n",appIdRegistry[i].appId);
  100         init_api->RegisterAppId(&rshell_validate, appIdRegistry[i].appId, appIdRegistry[i].additionalInfo, init_api->pAppidConfig);
  101     }
  102 
  103     return 0;
  104 }
  105 
  106 static void rshell_free_state(void *data)
  107 {
  108     ServiceRSHELLData *rd = (ServiceRSHELLData *)data;
  109 
  110     if (rd)
  111     {
  112         if (rd->parent)
  113         {
  114             rd->parent->child = NULL;
  115             rd->parent->parent = NULL;
  116         }
  117         if (rd->child)
  118         {
  119             rd->child->parent = NULL;
  120             rd->child->child = NULL;
  121         }
  122         free(rd);
  123     }
  124 }
  125 
  126 /* Both the control & data sessions need to go to success else we bail.
  127    Let the control/data session know that we're bailing */
  128 static void rshell_bail(ServiceRSHELLData *rd, tAppIdData *flowp)
  129 {
  130     clearAppIdFlag(flowp, APPID_SESSION_REXEC_STDERR);
  131 
  132     if (!rd) return;
  133 
  134     rd->state = RSHELL_STATE_BAIL;
  135     if (rd->child) rd->child->state = RSHELL_STATE_BAIL;
  136     if (rd->parent) rd->parent->state = RSHELL_STATE_BAIL;
  137 }
  138 
  139 static int rshell_validate(ServiceValidationArgs* args)
  140 {
  141     ServiceRSHELLData *rd = NULL;
  142     ServiceRSHELLData *tmp_rd;
  143     int i;
  144     uint32_t port;
  145     tAppIdData *pf;
  146     tAppIdData *flowp = args->flowp;
  147     const uint8_t *data = args->data;
  148     SFSnortPacket *pkt = args->pkt; 
  149     const int dir = args->dir;
  150     uint16_t size = args->size;
  151     bool app_id_debug_session_flag = args->app_id_debug_session_flag;
  152     char* app_id_debug_session = args->app_id_debug_session;
  153 
  154     rd = rshell_service_mod.api->data_get(flowp, rshell_service_mod.flow_data_index);
  155     if (!rd)
  156     {
  157         if (!size)
  158             goto inprocess;
  159         rd = calloc(1, sizeof(*rd));
  160         if (!rd)
  161             return SERVICE_ENOMEM;
  162         if (rshell_service_mod.api->data_add(flowp, rd, rshell_service_mod.flow_data_index, &rshell_free_state))
  163         {
  164             free(rd);
  165             return SERVICE_ENOMEM;
  166         }
  167         rd->state = RSHELL_STATE_PORT;
  168     }
  169 
  170     if (app_id_debug_session_flag)
  171         _dpd.logMsg("AppIdDbg %s rshell state %d\n", app_id_debug_session, rd->state);
  172 
  173     switch (rd->state)
  174     {
  175     case RSHELL_STATE_PORT:
  176         if (dir != APP_ID_FROM_INITIATOR) goto fail;
  177         if (size > RSHELL_MAX_PORT_PACKET) goto bail;
  178         if (data[size-1]) goto bail;
  179         port = 0;
  180         for (i=0; i<size-1; i++)
  181         {
  182             if (!isdigit(data[i])) goto bail;
  183             port *= 10;
  184             port += data[i] - '0';
  185         }
  186         if (port > 65535) goto bail;
  187         if (port)
  188         {
  189             sfaddr_t *sip;
  190             sfaddr_t *dip;
  191 
  192             dip = GET_DST_IP(pkt);
  193             sip = GET_SRC_IP(pkt);
  194             pf = rshell_service_mod.api->flow_new(flowp, pkt, dip, 0, sip, (uint16_t)port, IPPROTO_TCP, app_id, APPID_EARLY_SESSION_FLAG_FW_RULE);
  195             if (pf)
  196             {
  197                 tmp_rd = calloc(1, sizeof(ServiceRSHELLData));
  198                 if (tmp_rd == NULL)
  199                     return SERVICE_ENOMEM;
  200                 tmp_rd->state = RSHELL_STATE_STDERR_CONNECT_SYN;
  201                 tmp_rd->parent = rd;
  202 
  203                 if (rshell_service_mod.api->data_add(pf, tmp_rd, rshell_service_mod.flow_data_index, &rshell_free_state))
  204                 {
  205                     pf->rnaServiceState = RNA_STATE_FINISHED;
  206                     free(tmp_rd);
  207                     return SERVICE_ENOMEM;
  208                 }
  209                 if (rshell_service_mod.api->data_add_id(pf, (uint16_t)port, &svc_element))
  210                 {
  211                     pf->rnaServiceState = RNA_STATE_FINISHED;
  212                     tmp_rd->state = RSHELL_STATE_DONE;
  213                     tmp_rd->parent = NULL;
  214                     return SERVICE_ENOMEM;
  215                 }
  216                 pf->rnaClientState = RNA_STATE_FINISHED;
  217                 pf->scan_flags |= SCAN_HOST_PORT_FLAG;
  218                 PopulateExpectedFlow(flowp, pf,
  219                                      APPID_SESSION_CONTINUE |
  220                                      APPID_SESSION_REXEC_STDERR |
  221                                      APPID_SESSION_NO_TPI |
  222                                      APPID_SESSION_NOT_A_SERVICE |
  223                                      APPID_SESSION_PORT_SERVICE_DONE, 
  224                                      APP_ID_FROM_RESPONDER);
  225                 pf->rnaServiceState = RNA_STATE_STATEFUL;
  226                 rd->child = tmp_rd;
  227                 rd->state = RSHELL_STATE_SERVER_CONNECT;
  228                 setAppIdFlag(flowp, APPID_SESSION_CONTINUE);
  229                 goto success; 
  230             }
  231             else
  232                 rd->state = RSHELL_STATE_USERNAME;
  233         }
  234         else rd->state = RSHELL_STATE_USERNAME;
  235         break;
  236     case RSHELL_STATE_SERVER_CONNECT:
  237         if (!size) break;
  238         /* The only valid way out of this state is for the child flow to change it. */
  239         goto fail;
  240     case RSHELL_STATE_USERNAME:
  241         if (!size) break;
  242         if (dir != APP_ID_FROM_INITIATOR) goto fail;
  243         for (i=0; i<size && data[i]; i++)
  244             if (!isprint(data[i]) || isspace(data[i])) goto bail;
  245         rd->state = RSHELL_STATE_USERNAME2;
  246         if (i >= size) goto bail;
  247         i++;
  248         data += i;
  249         size -= i;
  250         /* Fall through */
  251     case RSHELL_STATE_USERNAME2:
  252         if (!size) break;
  253         if (dir != APP_ID_FROM_INITIATOR) goto fail;
  254         for (i=0; i<size && data[i]; i++)
  255             if (!isprint(data[i]) || isspace(data[i])) goto bail;
  256         rd->state = RSHELL_STATE_COMMAND;
  257         if (i >= size) goto bail;
  258         i++;
  259         data += i;
  260         size -= i;
  261         /* Fall through */
  262     case RSHELL_STATE_COMMAND:
  263         if (!size) break;
  264         if (dir != APP_ID_FROM_INITIATOR) goto fail;
  265         for (i=0; i<size && data[i]; i++)
  266             if (!isprint(data[i])) goto bail;
  267         rd->state = RSHELL_STATE_COMMAND;
  268         if (i >= size) goto bail;
  269         i++;
  270         data += i;
  271         size -= i;
  272         if (!size)
  273         {
  274             rd->state = RSHELL_STATE_REPLY;
  275             break;
  276         }
  277         if (data[size-1]) goto bail;
  278         /* stdin */
  279         for (i=0; i<size && data[i]; i++)
  280         {
  281             if (!isprint(data[i])) goto bail;
  282         }
  283         i++;
  284         if (i != size) goto bail;
  285         rd->state = RSHELL_STATE_REPLY;
  286         break;
  287     case RSHELL_STATE_REPLY:
  288         if (!size) goto inprocess;
  289         if (dir != APP_ID_FROM_RESPONDER) goto fail;
  290         if (size == 1 || *data == 0x01)
  291         {
  292             if (size != 1)
  293             {
  294                 data++;
  295                 size--;
  296                 for (i=0; i<size && data[i]; i++)
  297                 {
  298                     if (!isprint(data[i]) && data[i] != 0x0A && data[i] != 0x0D && data[i] != 0x09) goto fail;
  299                 }
  300             }
  301             if (rd->child)
  302             {
  303                 if (rd->child->state == RSHELL_STATE_STDERR_WAIT)
  304                     rd->child->state = RSHELL_STATE_STDERR_DONE;
  305                 else
  306                     goto fail;
  307             }
  308             clearAppIdFlag(flowp, APPID_SESSION_CONTINUE);
  309             goto success;
  310         }
  311         goto fail;
  312     case RSHELL_STATE_STDERR_CONNECT_SYN:
  313         rd->state = RSHELL_STATE_STDERR_CONNECT_SYN_ACK;
  314         break;
  315     case RSHELL_STATE_STDERR_CONNECT_SYN_ACK:
  316         if (rd->parent && rd->parent->state == RSHELL_STATE_SERVER_CONNECT)
  317         {
  318             rd->parent->state = RSHELL_STATE_USERNAME;
  319             rd->state = RSHELL_STATE_STDERR_WAIT;
  320             break;
  321         }
  322         goto bail;
  323     case RSHELL_STATE_STDERR_WAIT:
  324         /* The only valid way out of this state is for the parent flow to change it. */
  325         if (!size) break;
  326         goto bail;
  327     case RSHELL_STATE_STDERR_DONE:
  328         clearAppIdFlag(flowp, APPID_SESSION_REXEC_STDERR | APPID_SESSION_CONTINUE);
  329         goto success;
  330     case RSHELL_STATE_BAIL:
  331     default:
  332         goto bail;
  333     }
  334 
  335 inprocess:
  336     rshell_service_mod.api->service_inprocess(flowp, pkt, dir, &svc_element, NULL);
  337     return SERVICE_INPROCESS;
  338 
  339 success:
  340     rshell_service_mod.api->add_service(flowp, pkt, dir, &svc_element,
  341                                         APP_ID_SHELL, NULL, NULL, NULL, NULL);
  342     return SERVICE_SUCCESS;
  343 
  344 bail:
  345     rshell_bail(rd, flowp);
  346     rshell_service_mod.api->incompatible_data(flowp, pkt, dir, &svc_element,
  347                                               rshell_service_mod.flow_data_index, args->pConfig, NULL);
  348     return SERVICE_NOT_COMPATIBLE;
  349 
  350 fail:
  351     rshell_bail(rd, flowp);
  352     rshell_service_mod.api->fail_service(flowp, pkt, dir, &svc_element,
  353                                          rshell_service_mod.flow_data_index, args->pConfig, NULL);
  354     return SERVICE_NOMATCH;
  355 }
  356