📄 hi_norm.c
字号:
** This means that we have an invalid first sequence byte for ** a unicode sequence. So we just return the byte and move on. */ return iFirst; } /* ** This is the main loop for UTF-8 decoding. We check for the only ** valid sequence after the first byte whish is 0x80. Otherwise, ** it was invalid and we setnd a NON_ASCII_CHAR and continue on ** with our processing. */ for(iCtr = 0; iCtr < iNumBytes; iCtr++) { iByte = GetChar(Session, start, end, ptr, &iBareByte); if(iByte == END_OF_BUFFER || iBareByte) return NON_ASCII_CHAR; if((iByte & 0xc0) == 0x80) { iNorm <<= 6; iNorm |= (iByte & 0x3f); } else { /* ** This means that we don't have a valid unicode sequence, so ** we just bail. */ return NON_ASCII_CHAR; } } /* ** Check for unicode as ASCII and if there is not an ASCII char then ** we return the space holder char. */ if(iNorm > 0x7f) { if(ServerConf->iis_unicode.on) { iNorm = ServerConf->iis_unicode_map[iNorm]; if(iNorm == HI_UI_NON_ASCII_CODEPOINT) { iNorm = NON_ASCII_CHAR; } if(hi_eo_generate_event(Session, ServerConf->iis_unicode.alert)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_IIS_UNICODE, NULL, NULL); } return iNorm; } else { iNorm = NON_ASCII_CHAR; } } if(hi_eo_generate_event(Session, ServerConf->utf_8.alert)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_UTF_8, NULL, NULL); } return iNorm;}/*** NAME** UnicodeDecode::*//**** Checks for the ServerConf values before we actually decode.** ** This function is really a ServerConf wrapper for UTF8Decode.**** @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** ** @return integer** ** @retval char the decode/undecoded byte.** ** @see GetByte()*/static int UnicodeDecode(HI_SESSION *Session, u_char *start, u_char *end, u_char **ptr, int iFirst){ HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iNorm = iFirst; if(ServerConf->iis_unicode.on || ServerConf->utf_8.on) { iNorm = UTF8Decode(Session, start, end, ptr, iFirst); } return iNorm;}/*** NAME** GetByte::*//**** Handles the first stage of URI decoding for the case of IIS double** decoding.** ** The first stage consists of ASCII decoding and unicode decoding. %U** decoding is handled in the ASCII decoding.** ** @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** ** @return integer** ** @retval END_OF_BUFFER means that we've reached the end of buffer in** GetChar.** @retval iChar this is the character that was decoded.*/static int GetByte(HI_SESSION *Session, u_char *start, u_char *end, u_char **ptr){ int iChar; int iBareByte; iChar = GetChar(Session, start, end, ptr, &iBareByte); if(iChar == END_OF_BUFFER) return END_OF_BUFFER; /* ** We now check for unicode bytes */ if((iChar & 0x80) && (iChar != NON_ASCII_CHAR) && !iBareByte) { iChar = UnicodeDecode(Session, start, end, ptr, iChar); } return iChar;}/*** NAME** DoubleDecode::*//**** The double decoding routine for IIS good times.** ** Coming into this function means that we just decoded a % or that** we just saw two percents in a row. We know which state we are** in depending if the first char is a '%' or not.**** In the IIS world, there are two decodes, but only some of the decode** options are valid. All options are valid in the first decode** stage, but the second decode stage only supports:** - %u encoding** - ascii**** Knowing this, we can decode appropriately.** ** @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 ptr to the URI norm state** ** @return integer** ** @retval NON_ASCII_CHAR End of buffer reached while decoding** @retval char The decoded char*/static int DoubleDecode(HI_SESSION *Session, u_char *start, u_char *end, u_char **ptr, URI_NORM_STATE *norm_state){ HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iByte; int iNorm; u_char *orig_ptr; orig_ptr = *ptr; /* ** We now know that we have seen a previous % and that we need to ** decode the remaining bytes. We are in one of multiple cases: ** ** - %25xxxx ** - %%xx%xx ** - %u0025xxxx ** - etc. ** ** But, the one common factor is that they each started out with a ** % encoding of some type. ** ** So now we just get the remaining bytes and do the processing ** ourselves in this routine. */ iByte = GetByte(Session, start, end, ptr); if(iByte == END_OF_BUFFER) return NON_ASCII_CHAR; if(valid_lookup[(u_char)iByte] < 0) { if(ServerConf->u_encoding.on && (toupper(iByte) == 'U')) { iNorm = UDecode(Session, start, end, ptr, GetByte); if(iNorm == END_OF_BUFFER) { /* ** We have reached the end of the buffer while ** processing a U encoding. We keep the current ** pointer and return a NON_ASCII char for the ** bad encoding. */ return NON_ASCII_CHAR; } return iNorm; } return iByte; } iNorm = (hex_lookup[(u_char)iByte]<<4); iByte = GetByte(Session, start, end, ptr); if(iByte == END_OF_BUFFER) return NON_ASCII_CHAR; if(valid_lookup[(u_char)iByte] < 0) { return iByte; } iNorm = (iNorm | (hex_lookup[(u_char)iByte])) & 0xff; if(hi_eo_generate_event(Session, ServerConf->double_decoding.alert) && (norm_state->param == NULL)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_DOUBLE_DECODE, NULL, NULL); } 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, u_char *start, u_char *end, u_char **ptr, URI_NORM_STATE *norm_state){ HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iChar; iChar = GetByte(Session,start,end,ptr); 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)) { 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(URI_NORM_STATE *norm_state,u_char *ub_start,u_char **ub_ptr){ 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; } 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, u_char *start, u_char *end, u_char **ptr, URI_NORM_STATE *norm_state){ HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iChar; int iDir; u_char *orig_ptr; 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 == '/') { if(hi_eo_generate_event(Session, ServerConf->multiple_slash.alert)) { 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -