📄 hi_norm.c
字号:
if((u_char)iDir == '/') { /* ** We found a real live directory traversal ** so we reset the pointer to before the ** '/' and finish up after the return. */ if(hi_eo_generate_event(Session, ServerConf->directory.alert)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_DIR_TRAV, NULL, NULL); } *ptr = dir_ptr; return DIR_TRAV; } } *ptr = orig_ptr; return iChar; } else if((u_char)iDir == '/') { /* ** We got a self-referential directory traversal. ** ** Keep processing until we stop seeing self ** referential directories. */ if(hi_eo_generate_event(Session, ServerConf->directory.alert)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_SELF_DIR_TRAV, NULL, NULL); } continue; } } /* ** This means that we saw '.' and then another char, so ** it was just a file/dir that started with a '.'. */ *ptr = orig_ptr; return iChar; } } /* ** This is where we write the chars after the slash */ return iChar; } return END_OF_BUFFER;}/*** NAME** CheckLongDir::*//**** This function checks for long directory names in the request URI.** ** @param Session pointer to the session** @param norm_state pointer to the directory stack** @param ub_ptr current pointer in normalization buffer** ** @return integer** ** @retval HI_SUCCESS*/static int CheckLongDir(HI_SESSION *Session, URI_NORM_STATE *norm_state, u_char *ub_ptr){ int iDirLen; u_char *LastDir; /* ** First check that we are alerting on long directories and then ** check that we've seen a previous directory. */ if(Session->server_conf->long_dir && norm_state->dir_count && !norm_state->param) { LastDir = norm_state->dir_track[norm_state->dir_count - 1]; iDirLen = ub_ptr - LastDir; if(iDirLen > Session->server_conf->long_dir) hi_eo_client_event_log(Session, HI_EO_CLIENT_OVERSIZE_DIR, NULL, NULL); } return HI_SUCCESS;}/*** NAME** InspectUriChar::*//**** This function inspects the normalized chars for any other processing** that we need to do, such as directory traversals.** ** The main things that we check for here are '/' and '?'. There reason** for '/' is that we do directory traversals. If it's a slash, we call** the routine that will normalize mutli-slashes, self-referential dirs,** and dir traversals. We do all that processing here and call the** appropriate functions.** ** The '?' is so we can mark the parameter field, and check for oversize** directories one last time. Once the parameter field is set, we don't** do any more oversize directory checks since we aren't in the url** any more.** ** @param Session pointer to the current session** @param iChar the char to inspect** @param norm_state the normalization state** @param start the start of the URI buffer** @param end the end of the URI buffer** @param ptr the address of the pointer index into the URI buffer** @param ub_start the start of the norm buffer** @param ub_end the end of the norm buffer** @param ub_ptr the address of the pointer index into the norm buffer** ** @return integer** ** @retval END_OF_BUFFER we've reached the end of the URI or norm buffer** @retval HI_NONFATAL_ERR no special char, so just write the char and** increment the ub_ptr.** @retval HI_SUCCESS normalized the special char and already** incremented the buffers.*/static INLINE int InspectUriChar(HI_SESSION *Session, int iChar, URI_NORM_STATE *norm_state, u_char *start, u_char *end, u_char **ptr, u_char *ub_start, u_char *ub_end, u_char **ub_ptr){ HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iDir; /* ** Let's add absolute URI/proxy support everyone. */ if(!norm_state->dir_count && (u_char)iChar == ':' && hi_util_in_bounds(start, end, ((*ptr)+2))) { if(**ptr == '/' && *((*ptr)+1) == '/') { /* ** We've found absolute vodka. */ if(!hi_util_in_bounds(ub_start, ub_end, ((*ub_ptr)+2))) return END_OF_BUFFER; /* ** Write the : */ **ub_ptr = (u_char)iChar; (*ub_ptr)++; /* ** This increments us past the first slash, so at the next ** slash we will track a directory. ** ** The reason we do this is so that an attacker can't trick ** us into normalizing a directory away that ended in a :. ** For instance, if we got a URL that was separated in by a ** packet boundary like this, and we were looking for the ** URL real_dir:/file.html: ** real_dir://obfuscate_dir/../file.html ** we would normalize it with proxy support to: ** /file.html ** because we never tracked the :// as a valid directory. So ** even though this isn't the best solution, it is the best ** we can do given that we are working with stateless ** inspection. */ (*ptr)++; return HI_SUCCESS; } } /* ** Now that we have the "true" byte, we check this byte for other ** types of normalization: ** - directory traversals ** - multiple slashes */ if((u_char)iChar == '/') { /* ** First thing we do is check for a long directory. */ CheckLongDir(Session, norm_state, *ub_ptr); iDir = DirNorm(Session, start, end, ptr, norm_state); if(iDir == DIR_TRAV) { /* ** This is the case where we have a directory traversal. ** ** The DirTrav function will reset the ub_ptr to the previous ** slash. After that, we just continue through the loop because ** DirNorm has already set ptr to the slash, so we can just ** continue on. */ DirTrav(norm_state, ub_start, ub_ptr); } else { /* ** This is the case where we didn't have a directory traversal, ** and we are now just writing the char after the '/'. ** ** We call DirSet, because all this function does is write a ** '/' into the buffer and increment the ub_ptr. We then ** check the return code and return END_OF_BUFFER if ** needed. */ DirSet(norm_state, ub_ptr); if(iDir == END_OF_BUFFER) return END_OF_BUFFER; /* ** We check the bounds before we write the next byte */ if(!hi_util_in_bounds(ub_start, ub_end, *ub_ptr)) return END_OF_BUFFER; /* ** Set the char to what we got in DirNorm() */ /* ** Look for user-defined Non-Rfc chars. If we find them ** then log an alert. */ if(ServerConf->non_rfc_chars[(u_char)iDir]) { hi_eo_client_event_log(Session, HI_EO_CLIENT_NON_RFC_CHAR, NULL, NULL); } **ub_ptr = (u_char)iDir; (*ub_ptr)++; } return HI_SUCCESS; } if((u_char)iChar == '?') { /* ** We assume that this is the beginning of the parameter field, ** and check for a long directory following. Event though seeing ** a question mark does not guarantee the parameter field, thanks ** IIS. */ CheckLongDir(Session, norm_state, *ub_ptr); norm_state->param = *ub_ptr; } /* ** This is neither char, so we just bail and let the loop finish ** for us. */ return HI_NONFATAL_ERR;}/*** NAME** hi_norm_uri::*//**** Normalize the URI into the URI normalize buffer.** ** This is the routine that users call to normalize the URI. It iterates** through the URI buffer decoding the next character and is then checked** for any directory problems before writing the decoded character into the** normalizing buffer.** ** We return the length of the normalized URI buffer in the variable,** uribuf_size. This value is passed in as the max size of the normalization** buffer, which we then set in iMaxUriBufSize for later reference.** ** If there was some sort of problem during normalizing we set the normalized** URI buffer size to 0 and return HI_NONFATAL_ERR.** ** @param ServerConf the pointer to the server configuration** @param uribuf the pointer to the normalize uri buffer** @param uribuf_size the size of the normalize buffer** @param uri the pointer to the unnormalized uri buffer** @param uri_size the size of the unnormalized uri buffer** ** @return integer** ** @retval HI_NONFATAL_ERR there was a problem during normalizing, the** uribuf_size is also set to 0** @retval HI_SUCCESS Normalizing the URI was successful*/int hi_norm_uri(HI_SESSION *Session, u_char *uribuf, int *uribuf_size, u_char *uri, int uri_size){ HTTPINSPECT_CONF *ServerConf; int iChar; int iRet; int iMaxUriBufSize; URI_NORM_STATE norm_state; u_char *ub_ptr; u_char *ptr; u_char *start; u_char *end; u_char *ub_start; u_char *ub_end; ServerConf = Session->server_conf; iMaxUriBufSize = *uribuf_size; start = uri; end = uri + uri_size; ub_start = uribuf; ub_end = uribuf + iMaxUriBufSize; ub_ptr = uribuf; ptr = uri; /* ** Initialize the URI directory normalization state */ norm_state.dir_count = 0; norm_state.param = NULL; while(hi_util_in_bounds(ub_start, ub_end, ub_ptr)) { iChar = GetDecodedByte(Session, start, end, &ptr, &norm_state); if(iChar == END_OF_BUFFER) break; /* ** Look for user-defined Non-Rfc chars. If we find them ** then log an alert. */ if(ServerConf->non_rfc_chars[(u_char)iChar]) { hi_eo_client_event_log(Session, HI_EO_CLIENT_NON_RFC_CHAR, NULL, NULL); } if((iRet=InspectUriChar(Session, iChar, &norm_state, start, end, &ptr, ub_start, ub_end, &ub_ptr))) { if(iRet == END_OF_BUFFER) break; /* ** This is the default case when we don't want anything to do with ** the char besides writing the value into the buffer. */ *ub_ptr = (u_char)iChar; ub_ptr++; } } /* ** Now that we are done, let's make sure that we didn't just have a ** single large directory, with the rest in the next packet. */ CheckLongDir(Session, &norm_state, ub_ptr); /* ** This means that we got to the end of the URI, so we set the length, ** check it, and move on. */ *uribuf_size = ub_ptr - ub_start; if(*uribuf_size > uri_size || *uribuf_size < 1) return HI_NONFATAL_ERR; return HI_SUCCESS;}/*** NAME** hi_norm_init::*//**** Initialize the arrays neccessary to normalize the HTTP protocol fields.** ** Currently, we set a hex_lookup array where we can convert the hex encoding** that we encounter in the URI into numbers we deal with.** ** @param GlobalConf pointer to the global configuration of HttpInspect** ** @return HI_SUCCESS function successful*/int hi_norm_init(HTTPINSPECT_GLOBAL_CONF *GlobalConf){ int iCtr; int iNum; memset(hex_lookup, NO_HEX_VAL, sizeof(hex_lookup)); memset(valid_lookup, NO_HEX_VAL, sizeof(valid_lookup)); /* ** Set the decimal number values */ iNum = 0; for(iCtr = 48; iCtr < 58; iCtr++) { hex_lookup[iCtr] = iNum; valid_lookup[iCtr] = HEX_VAL; iNum++; } /* ** Set the upper case values. */ iNum = 10; for(iCtr = 65; iCtr < 71; iCtr++) { hex_lookup[iCtr] = iNum; valid_lookup[iCtr] = HEX_VAL; iNum++; } iNum = 16; for(iCtr = 71; iCtr < 91; iCtr++) { hex_lookup[iCtr] = iNum; valid_lookup[iCtr] = BASE36_VAL; iNum++; } /* ** Set the lower case values. */ iNum = 10; for(iCtr = 97; iCtr < 103; iCtr++) { hex_lookup[iCtr] = iNum; valid_lookup[iCtr] = HEX_VAL; iNum++; } iNum = 16; for(iCtr = 103; iCtr < 123; iCtr++) { hex_lookup[iCtr] = iNum; valid_lookup[iCtr] = BASE36_VAL; iNum++; } return HI_SUCCESS;}/*** NAME** hi_normalization::*//**** Wrap the logic for normalizing different inspection modes.** ** We call the various normalization modes here, and adjust the appropriate** Session constructs.** ** @param Session pointer to the session structure.** @param iInspectMode the type of inspection/normalization to do** ** @return integer** ** @retval HI_SUCCESS function successful** @retval HI_INVALID_ARG invalid argument*/int hi_normalization(HI_SESSION *Session, int iInspectMode){ int iRet; if(!Session) { return HI_INVALID_ARG; } /* ** Depending on the mode, we normalize the packet differently. ** Currently, we only have normalization routines for the client ** URI, so that's all we are interested in. ** ** HI_SI_CLIENT_MODE: ** Inspect for HTTP client communication. */ if(iInspectMode == HI_SI_CLIENT_MODE) { if((iRet = hi_client_norm((void *)Session))) { return iRet; } } return HI_SUCCESS;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -