📄 hi_norm.c
字号:
} return iNorm;}/*** NAME** GetDecodedByte::*//**** This is the final GetByte routine. The value that is returned from this** routine is the final decoded byte, and normalization can begin. This** routine handles the double phase of decoding that IIS is fond of.** ** So to recap all the decoding up until this point.** ** The first phase is to call GetByte(). GetByte() returns the first stage** of decoding, which handles the UTF-8 decoding. If we have decoded a** % of some type, then we head into DoubleDecode() if the ServerConf** allows it.** ** What returns from DoubleDecode is the final result.** ** @param ServerConf the server configuration** @param start the start of the URI** @param end the end of the URI** @param ptr the current pointer into the URI** @param norm_state the pointer to the URI norm state** ** @return integer** ** @retval END_OF_BUFFER While decoding, the end of buffer was reached.** @retval char The resultant decoded char.** ** @see DoubleDecode();** @see GetByte();*/static int GetDecodedByte(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_NORM_STATE *norm_state){ HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iChar; iChar = GetByte(Session,start,end,ptr, norm_state); if(iChar == END_OF_BUFFER) return END_OF_BUFFER; if(ServerConf->double_decoding.on && (u_char)iChar == '%') { iChar = DoubleDecode(Session,start,end,ptr, norm_state); } /* ** Let's change '\' to '/' if possible */ if(ServerConf->iis_backslash.on && (u_char)iChar == 0x5c) { if(hi_eo_generate_event(Session, ServerConf->iis_backslash.alert) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_IIS_BACKSLASH, NULL, NULL); } iChar = 0x2f; } return iChar;}/*** NAME** DirTrav::*//**** Set the ub_ptr and update the URI_NORM_STATE.** ** The main point of this function is to take care of the details in** updating the directory stack and setting the buffer pointer to the** last directory.** ** @param norm_state pointer to the normalization state struct** @param ub_ptr double pointer to the normalized buffer** ** @return integer** ** @retval HI_SUCCESS function successful** ** @see hi_norm_uri()*/static int DirTrav(HI_SESSION *Session, URI_NORM_STATE *norm_state, u_char *ub_start,u_char **ub_ptr){ HTTPINSPECT_CONF *ServerConf = Session->server_conf; hi_stats.dir_trav++; if(norm_state->dir_count) { *ub_ptr = norm_state->dir_track[norm_state->dir_count - 1]; /* ** Check to make sure that we aren't at the beginning */ if(norm_state->dir_count >= 1) { norm_state->dir_count--; } } else { /* ** This is a special case where there was no / seen before ** we see a /../. When this happens, we just reset the ub_ptr ** back to the beginning of the norm buffer and let the slash ** get written on the next iteration of the loop. */ *ub_ptr = ub_start; /* ** Let's put the alert here for webroot dir traversal. */ if(hi_eo_generate_event(Session, ServerConf->webroot.alert) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_WEBROOT_DIR, NULL, NULL); } } return HI_SUCCESS; }/*** NAME** DirSet::*//**** Set the directory by writing a '/' to the normalization buffer and** updating the directory stack.** ** This gets called after every slash that isn't a directory traversal. We** just write a '/' and then update the directory stack to point to the** last directory, in the case of future directory traversals.** ** @param norm_state pointer to the normalization state struct** @param ub_ptr double pointer to the normalized buffer** ** @return integer** ** @retval HI_SUCCESS function successful** ** @see hi_norm_uri()*/static int DirSet(URI_NORM_STATE *norm_state, u_char **ub_ptr){ /* ** Write the '/'. Even if iDir is the END_OF_BUFFER we still ** write it because the '/' came before the END_OF_BUFFER. */ **ub_ptr = '/'; if(!norm_state->param) { norm_state->dir_track[norm_state->dir_count] = *ub_ptr; if(norm_state->dir_count < MAX_DIRS) norm_state->dir_count++; } (*ub_ptr)++; return HI_SUCCESS;}/*** NAME** DirNorm::*//**** The main function for dealing with multiple slashes, self-referential** directories, and directory traversals.** ** This routine does GetDecodedByte() while looking for directory foo. It's** called every time that we see a slash in the main hi_norm_uri. Most of** the time we just enter this loop, find a non-directory-foo char and ** return that char. hi_norm_uri() takes care of the directory state** updating and so forth.** ** But when we run into trouble with directories, this function takes care** of that. We loop through multiple slashes until we get to the next** directory. We also loop through self-referential directories until we** get to the next directory. Then finally we deal with directory ** traversals.** ** With directory traversals we do a kind of "look ahead". We verify that** there is indeed a directory traversal, and then set the ptr back to** the beginning of the '/', so when we iterate through hi_norm_uri() we** catch it.** ** The return value for this function is usually the character after** the directory. When there was a directory traversal, it returns the** value DIR_TRAV. And when END_OF_BUFFER is returned, it means that we've** really hit the end of the buffer, or we were looping through multiple** slashes and self-referential directories until the end of the URI** buffer.** ** @param ServerConf pointer to the Server configuration** @param start pointer to the start of the URI buffer** @param end pointer to the end of the URI buffer** @param ptr pointer to the index in the URI buffer** ** @return integer** ** @retval END_OF_BUFFER we've reached the end of buffer** @retval DIR_TRAV we found a directory traversal** @retval char return the next char after the directory** ** @see hi_norm_uri()** @see GetDecodedByte()*/static int DirNorm(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_NORM_STATE *norm_state){ HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iChar; int iDir; const u_char *orig_ptr; const u_char *dir_ptr; while((iChar = GetDecodedByte(Session, start, end, ptr, norm_state)) != END_OF_BUFFER) { orig_ptr = *ptr; /* ** This is kind of a short cut to get out of here as soon as we ** can. If the character is over 0x2f then we know that is can't ** be either the '.' or the '/', so we break and return the ** char. */ if((u_char)iChar < 0x30) { /* ** We check for multiple slashes. If we find multiple slashes ** then we just continue on until we find something interesting. */ if(ServerConf->multiple_slash.on && (u_char)iChar == '/') { hi_stats.slashes++; if(hi_eo_generate_event(Session, ServerConf->multiple_slash.alert) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_MULTI_SLASH, NULL, NULL); } continue; } /* ** This is where we start looking for self-referential dirs ** and directory traversals. */ else if(ServerConf->directory.on && (u_char)iChar == '.' && !norm_state->param) { iDir = GetDecodedByte(Session,start,end,ptr,norm_state); if(iDir != END_OF_BUFFER) { if((u_char)iDir == '.') { /* ** This sets the dir_ptr to the beginning of the ** byte that may be a dir. So if it is a slash, ** we can get back to that slash and continue ** processing. */ dir_ptr = *ptr; iDir = GetDecodedByte(Session,start,end,ptr,norm_state); if(iDir != END_OF_BUFFER) { if((u_char)iDir == '/') { hi_stats.self_ref++; /* ** 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) && !norm_state->param) { 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) && !norm_state->param) { 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_generate_event(Session, HI_EO_CLIENT_OVERSIZE_DIR) && !norm_state->param) { 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -