📄 pp_ftp.c
字号:
dirPtr = strtok(NULL, "/"); } /* If reset == 1, there was a mismatch of what we * had before. Update it now */ while (dirPtr && reset) { iLen = strlen(dirPtr); thisNode = malloc(sizeof(FTP_DIR_NODE)); thisNode->name = calloc(sizeof(char), iLen + 1); memcpy(thisNode->name, dirPtr, iLen); if (!Session->curr_directory) { Session->curr_directory = thisNode; Session->head_directory = thisNode; thisNode->parent = NULL; thisNode->next = NULL; } else { thisNode->parent = Session->curr_directory; thisNode->next = NULL; Session->curr_directory->next = thisNode; Session->curr_directory = thisNode; } dirPtr = strtok(NULL, "/"); } } break; }}#endif /* MAINTAIN_DIR_STATE *//* * Function: do_stateful_checks(FTP_SESSION *Session, Packet *p, * FTP_CLIENT_REQ *req, int rsp_code) * * Purpose: Handle stateful checks and state updates for FTP response * packets. * * Arguments: Session => Pointer to session info * p => Pointer to the current packet struct * req => Pointer to current response from packet * (this function may be called multiple * times for pipelined requests). * rsp_code => Integer response value for server response * * Returns: int => return code indicating error or success * */int do_stateful_checks(FTP_SESSION *Session, SFSnortPacket *p, FTP_CLIENT_REQ *req, int rsp_code){ int iRet = FTPP_SUCCESS; if (Session->server_conf->data_chan) { if (rsp_code == 226) { /* Just ignore this code -- end of transfer... * If we saw all the other dat for this channel * Session->data_chan_state should be NO_STATE. */ } else if (Session->data_chan_state & DATA_CHAN_PASV_CMD_ISSUED) { if (ftp_cmd_pipe_index == Session->data_chan_index) { if (Session->data_xfer_index == -1) ftp_cmd_pipe_index = 0; Session->data_chan_index = -1; if (rsp_code == 227) { u_int32_t ip=0; u_int16_t port=0; char *ip_begin = req->param_begin; Session->data_chan_state &= ~DATA_CHAN_PASV_CMD_ISSUED; Session->data_chan_state |= DATA_CHAN_PASV_CMD_ACCEPT; Session->data_chan_index = -1; /* Interpret response message to identify the * Server IP/Port. Server response is inside * a pair of ()s. Find the left (, and use same * means to find IP/Port as is done for the PORT * command. */ while ((*ip_begin != '(') && (ip_begin < req->param_end)) { ip_begin++; } if (ip_begin < req->param_end) { ip_begin++; iRet = getIP(&ip_begin, req->param_end, ')', &ip, &port); if (iRet == FTPP_SUCCESS) { Session->serverIP = htonl(ip); Session->serverPort = port; Session->clientIP = 0; Session->clientPort = 0; } } else { iRet = FTPP_MALFORMED_FTP_RESPONSE; } } else { Session->data_chan_index = -1; Session->data_chan_state &= ~DATA_CHAN_PASV_CMD_ISSUED; } } } else if (Session->data_chan_state & DATA_CHAN_PORT_CMD_ISSUED) { if (ftp_cmd_pipe_index == Session->data_chan_index) { if (Session->data_xfer_index == -1) ftp_cmd_pipe_index = 0; Session->data_chan_index = -1; if (rsp_code == 200) { Session->data_chan_state &= ~DATA_CHAN_PORT_CMD_ISSUED; Session->data_chan_state |= DATA_CHAN_PORT_CMD_ACCEPT; Session->data_chan_index = -1; } else if (ftp_cmd_pipe_index == Session->data_chan_index) { Session->data_chan_index = -1; Session->data_chan_state &= ~DATA_CHAN_PORT_CMD_ISSUED; } } } else if (Session->data_chan_state & DATA_CHAN_XFER_CMD_ISSUED) { if (ftp_cmd_pipe_index == Session->data_xfer_index) { if (Session->data_chan_index == -1) ftp_cmd_pipe_index = 0; Session->data_xfer_index = -1; if ((rsp_code == 150) || (rsp_code == 125)) { struct in_addr client, server; Session->data_chan_state &= ~DATA_CHAN_XFER_CMD_ISSUED; Session->data_chan_state = DATA_CHAN_XFER_STARTED; if (Session->serverIP == 0) { /* This means we're not in passive mode. */ /* Server is listening/sending from its own IP, * FTP Port -1 */ /* Client IP, Port specified via PORT command */ Session->serverIP = p->ip4_header->source.s_addr; /* Can't necessarily guarantee this, especially * in the case of a proxy'd connection where the * data channel might not be on port 20 (or server * port-1). Comment it out for now. */ /* Session->serverPort = ntohs(p->tcph->th_sport) -1; */ } if (Session->clientIP == 0) { /* This means we're in passive mode. */ /* Server info is known. */ /* Client IP is known from response packet, but * port is unknown */ Session->clientIP = p->ip4_header->destination.s_addr; } client.s_addr = Session->clientIP; server.s_addr = Session->serverIP; if (Session->server_conf->data_chan) { /* Call into Streams to mark data channel as something * to ignore. */ _dpd.streamAPI->ignore_session(Session->clientIP, Session->clientPort, Session->serverIP, Session->serverPort, p->ip4_header->proto, SSN_DIR_BOTH, 0 /* Not permanent */ ); } } /* Clear the session info for next transfer --> * reset host/port */ Session->serverIP = Session->clientIP = 0; Session->serverPort = Session->clientPort = 0; Session->data_chan_state = NO_STATE; } } } /* if (Session->server_conf->data_chan) */ if (Session->global_conf->encrypted.on) { switch(Session->encr_state) { case AUTH_TLS_CMD_ISSUED: if (rsp_code == 234) { /* Could check that response msg includes "TLS" */ Session->encr_state = AUTH_TLS_ENCRYPTED; if (Session->global_conf->encrypted.alert) { /* Alert on encrypted channel */ ftp_eo_event_log(Session, FTP_EO_ENCRYPTED, NULL, NULL); } DEBUG_WRAP(_dpd.debugMsg(DEBUG_FTPTELNET, "FTP stream is now TLS encrypted\n");); } break; case AUTH_SSL_CMD_ISSUED: if (rsp_code == 234) { /* Could check that response msg includes "SSL" */ Session->encr_state = AUTH_SSL_ENCRYPTED; if (Session->global_conf->encrypted.alert) { /* Alert on encrypted channel */ ftp_eo_event_log(Session, FTP_EO_ENCRYPTED, NULL, NULL); } DEBUG_WRAP(_dpd.debugMsg(DEBUG_FTPTELNET, "FTP stream is now SSL encrypted\n");); } break; case AUTH_UNKNOWN_CMD_ISSUED: if (rsp_code == 234) { Session->encr_state = AUTH_UNKNOWN_ENCRYPTED; if (Session->global_conf->encrypted.alert) { /* Alert on encrypted channel */ ftp_eo_event_log(Session, FTP_EO_ENCRYPTED, NULL, NULL); } DEBUG_WRAP(_dpd.debugMsg(DEBUG_FTPTELNET, "FTP stream is now encrypted\n");); } break; } } /* if (Session->global_conf->encrypted.on) */#ifdef MAINTAIN_USER_STATE switch (Session->user_state) { case USER_CMD_ISSUED: if (rsp_code == 331) Session->user_state = PASS_REQUIRED; else if (rsp_code == 230) Session->user_state = USER_LOGGED_IN; else { Session->user_state = NO_STATE; if (Session->user) { free(Session->user); Session->user = NULL; } } break; case PASS_CMD_ISSUED: if (rsp_code == 230) Session->user_state = USER_LOGGED_IN; else { Session->user_state = NO_STATE; if (Session->user) { free(Session->user); Session->user = NULL; } } break; case USER_LOGGED_IN: case PASS_REQUIRED: /* Uh, shouldn't get here */ /* Lost state */ break; }#endif#ifdef MAINTAIN_DIR_STATE switch(Session->dir_state) { case PWD_CMD_ISSUED: if (rsp_code == Session->expected_dir_response) { adjust_dir(Session, PWD_CMD_ISSUED, req->param_begin, req->param_size); } Session->expected_dir_response = 0; Session->dir_state = NO_STATE; break; case CWD_CMD_ISSUED: if (rsp_code == Session->expected_dir_response) { adjust_dir(Session, CWD_CMD_ISSUED, NULL, 0); } free(Session->dir_adjust); Session->dir_adjust = NULL; Session->expected_dir_response = 0; Session->dir_state = NO_STATE; break; case CDUP_CMD_ISSUED: if (rsp_code == Session->expected_dir_response) { adjust_dir(Session, CDUP_CMD_ISSUED, NULL, 0); } Session->expected_dir_response = 0; Session->dir_state = NO_STATE; break; }#endif return iRet;}/* * Function: check_ftp(FTP_SESSION *Session, Packet *p, int iMode) * * Purpose: Handle some trivial validation checks of an FTP packet. Namely, * check argument length and some protocol enforcement. * * Wishful: This results in exposing the FTP command (and looking * at the results) to the rules layer. * * Arguments: Session => Pointer to session info * p => pointer to the current packet struct * iMode => Mode indicating server or client checks * * Returns: int => return code indicating error or success * */#define NUL 0x00#define CR 0x0d#define LF 0x0a#define SP 0x20#define DASH 0x2D#define FTP_CMD_OK 0#define FTP_CMD_INV 1#define FTP_RESPONSE_INV 1#define FTP_RESPONSE 2#define FTP_RESPONSE_2BCONT 2#define FTP_RESPONSE_CONT 3#define FTP_RESPONSE_CONT 3#define FTP_RESPONSE_ENDCONT 4int check_ftp(FTP_SESSION *ftpssn, SFSnortPacket *p, int iMode){ int iRet = FTPP_SUCCESS; int encrypted = 0; int space = 0; long state = FTP_CMD_OK; int rsp_code = 0; FTP_CLIENT_REQ *req; FTP_CMD_CONF *CmdConf = NULL; unsigned char *read_ptr; unsigned char *end = p->payload + p->payload_size; if (p->flags & FLAG_ALT_DECODE) end = _dpd.altBuffer + p->normalized_payload_size; if (iMode == FTPP_SI_CLIENT_MODE) { req = &ftpssn->client.request; ftp_cmd_pipe_index = 0; } else if (iMode == FTPP_SI_SERVER_MODE) req = (FTP_CLIENT_REQ *)&ftpssn->server.response; else return FTPP_INVALID_ARG; while (req->pipeline_req) { state = FTP_CMD_OK; read_ptr = req->pipeline_req; /* Starts at the beginning of the buffer/line, * so next up is a command */ req->cmd_begin = read_ptr; while ((*read_ptr != SP) && (*read_ptr != CR) && (*read_ptr != LF) && /* Check for LF when there wasn't a CR, * protocol violation, but accepted by * some servers. */ (*read_ptr != DASH) && (read_ptr < end)) { /* If the first char is a digit this is a response * in server mode. */ if (isdigit(*read_ptr) && (iMode == FTPP_SI_SERVER_MODE)) { state = FTP_RESPONSE; } /* Or, if this is not a char, this is garbage in client mode */ else if (!isalpha(*read_ptr) && (iMode == FTPP_SI_CLIENT_MODE)) { state = FTP_CMD_INV; } read_ptr++; } req->cmd_end = read_ptr; req->cmd_size = req->cmd_end - req->cmd_begin; if (iMode == FTPP_SI_CLIENT_MODE) { if ( ((req->cmd_size != 4) && (req->cmd_size != 3)) || (state == FTP_CMD_INV) ) { /* Uh, something is very wrong... * nonalpha char seen or cmd is not 3 or 4 chars. * See if this might be encrypted, ie, non-alpha bytes. */ char *ptr = req->cmd_begin; while (ptr < req->cmd_end) { if (!isalpha(*ptr)) { encrypted = 1; break; } ptr++; } } if (encrypted) { /* If the session wasn't already marked as encrypted... * Don't want to double-alert if we've already * determined the session is encrypted and we're * checking encrypted sessions. */ if (ftpssn->encr_state == 0) { ftpssn->encr_state = AUTH_UNKNOWN_ENCRYPTED; if (ftpssn->global_conf->encrypted.alert) { /* Alert on encrypted channel */ ftp_eo_event_log(ftpssn, FTP_EO_ENCRYPTED, NULL, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -