Source code analysis of Apache .. % 5c vulnerability causes

Source: Internet
Author: User
Tags rfc
The following code processes the request in the source code src/main/http_request.c:

Static void process_request_internal (request_rec * r)
{
Int access_status;

/* Ignore embedded % 2f's in path for proxy requests */
If (R-> proxyreq = not_proxy & R-> parsed_uri.path ){
/* If it is not a proxy */
Access_status = ap_unescape_url (R-> parsed_uri.path );
/* Decoding %, RFC requirements */
If (access_status ){
Ap_die (access_status, R );
Return;
}
}

Ap_getparents (R-> URI);/* OK --- shrinking transformations ...*/
/* Process/../, error, not considering/../*/under Windows /../*/

If (access_status = location_walk (R ))){
Ap_die (access_status, R );
Return;
}

If (access_status = ap_translate_name (R ))){
Decl_die (access_status, "translate", R );
Return;
}

If (R-> proxyreq = not_proxy ){
/*
* We don't want trace to run through the normal handler set, we
* Handle it specially.
*/
If (R-> method_number = m_trace ){
If (access_status = ap_send_http_trace (R )))
Ap_die (access_status, R );
Else
Ap_finalize_request_protocol (R );
Return;
}
}

If (R-> proto_num> http_version (1.0) & ap_table_get (R-> subprocess_env, "downgrade ")){
R-> proto_num = http_version (1, 0 );
}

/*
* NB: directory_walk () clears the per_dir_config, so we don't inherit
* From location_walk () abve
*/

If (access_status = directory_walk (R ))){
Ap_die (access_status, R );
Return;
}

If (access_status = file_walk (R ))){
Ap_die (access_status, R );
Return;
}

If (access_status = location_walk (R ))){
Ap_die (access_status, R );
Return;
}

If (access_status = ap_header_parse (R ))){
Ap_die (access_status, R );
Return;
}

Switch (ap_satisfies (R )){
Case satisfy_all:
Case satisfy_nospec:
If (access_status = ap_check_access (R ))! = 0 ){
Decl_die (access_status, "Check access", R );
Return;
}
If (ap_some_auth_required (R )){
If (access_status = ap_check_user_id (R ))! = 0 )! Ap_auth_type (R )){
Decl_die (access_status, ap_auth_type (r)
? "Check user. No user file? "
: "Perform authentication. authtype not set! ", R );
Return;
}
If (access_status = ap_check_auth (R ))! = 0 )! Ap_auth_type (R )){
Decl_die (access_status, ap_auth_type (r)
? "Check access. No groups file? "
: "Perform authentication. authtype not set! ", R );
Return;
}
}
Break;
Case satisfy_any:
If (access_status = ap_check_access (R ))! = 0 )! Ap_auth_type (R )){
If (! Ap_some_auth_required (R )){
Decl_die (access_status? Access_status:
Http_internal_server_error,
Ap_auth_type (r )? "Check access"
: "Perform authentication. authtype not set! ", R );
Return;
}
If (access_status = ap_check_user_id (R ))! = 0 )! Ap_auth_type (R )){
Decl_die (access_status, ap_auth_type (r)
? "Check user. No user file? "
: "Perform authentication. authtype not set! ", R );
Return;
}
If (access_status = ap_check_auth (R ))! = 0 )! Ap_auth_type (R )){
Decl_die (access_status, ap_auth_type (r)
? "Check access. No groups file? "
: "Perform authentication. authtype not set! ", R );
Return;
}
}
Break;
}

If (! (R-> proxyreq! = Not_proxy
& R-> parsed_uri.scheme! = NULL
& Strcmp (R-> parsed_uri.scheme, "HTTP") = 0 )){
If (access_status = ap_find_types (R ))! = 0 ){
Decl_die (access_status, "Find types", R );
Return;
}
}

If (access_status = ap_run_fixups (R ))! = 0 ){
Ap_die (access_status, R );
Return;
}

If (access_status = ap_invoke_handler (R ))! = 0 ){
Ap_die (access_status, R );
Return;
}

/* Take care of little things that need to happen when we're done */
Ap_finalize_request_protocol (R );
}

The following code processes the source code src/main/util. c:

Api_export (void) ap_getparents (char * name)
{
Int L, W;

/* Four paseses, as per RFC 1808 */
/* A) Remove./path segments */

For (L = 0, W = 0; name [l]! = '/0 ';){
If (name [l] = '. '& name [L + 1] ='/'& (L = 0 name [L-1] = '/'))
L + = 2;
Else
Name [W ++] = Name [L ++];
}

/* B) Remove trailing. Path, segment */
If (W = 1 & name [0] = '.')
W --;
Else if (W> 1 & name [w-1] = '.' & name [w-2] = '/')
W --;
Name [w] = '/0 ';

/* C) Remove all XX/../segments. (including leading.../AND /../)*/
L = 0;

While (name [l]! = '/0 '){
If (name [l] = '.' & name [L + 1] = '.' & name [L + 2] = '/'&&
(L = 0 name [L-1] = '/')){
Register int M = L + 3, N;

L = L-2;
If (L> = 0 ){
While (L> = 0 & name [l]! = '/')
L --;
L ++;
}
Else
L = 0;
N = L;
While (name [N] = Name [m])
(++ N, ++ m );
}
Else
+ + L;
}

/* D) Remove trailing XX/... segment .*/
If (L = 2 & name [0] = '.' & name [1] = '.')
Name [0] = '/0 ';
Else if (L> 2 & name [L-1] = '. '& name [L-2] = '. '& name [L-3] = '/'){
L = L-4;
If (L> = 0 ){
While (L> = 0 & name [l]! = '/')
L --;
L ++;
}
Else
L = 0;
Name [l] = '/0 ';
}
}

As you can see, the "/../" under Windows is obviously not taken into account. It seems that the person who compiled this function is not familiar with the features of windows and is a programmer who has been programming under * UNIX for a long time. In fact, there have been many problems with "/../" under windows. Why can't I use "/../" for telnet? It seems that all "/" is replaced with "/" before decoding. Obviously, this conversion should be performed after decoding. It is estimated that "/.../" is not detected because the conversion has been performed first, which is the same as the % C1 % 1C vulnerability in IIS. In this way, you must pay attention to the previous checks if there is any encoding or decoding. If not, you must re-encode the detected items.

Here is the processing module for converting "/" In Uri into "/" in the source code src/main/http_protocol.c:

/* Parse_uri: break apart the URI
* Side effects:
*-Sets R-> ARGs to rest after '? '(Or null if no '? ')
*-Sets R-> URI to request URI (without R-> ARGs part)
*-Sets R-> hostname (if not set already) from request (scheme: // host: Port)
*/
Core_export (void) ap_parse_uri (request_rec * r, const char * URI)
{
Int status = http_ OK;

R-> unparsed_uri = ap_pstrdup (R-> pool, Uri );

If (R-> method_number = m_connect ){
Status = ap_parse_hostinfo_components (R-> pool, Uri, & R-> parsed_uri );
} Else {
/* Simple syntax errors in URLs are trapped by parse_uri_components ().*/
Status = ap_parse_uri_components (R-> pool, Uri, & R-> parsed_uri );
}

If (ap_is_http_success (Status )){
/* If it has a scheme we may need to do absoluteuri vhost stuff */
If (R-> parsed_uri.scheme
&&! Strcasecmp (R-> parsed_uri.scheme, ap_http_method (R ))){
R-> hostname = r-> parsed_uri.hostname;
} Else if (R-> method_number = m_connect ){
R-> hostname = r-> parsed_uri.hostname;
}
R-> ARGs = r-> parsed_uri.query;
R-> uri = r-> parsed_uri.path? R-> parsed_uri.path
: Ap_pstrdup (R-> pool ,"/");
# If defined (os2) defined (win32)
/* Handle path translations for OS/2 and plug security hole.
* This will prevent "http://www.enet.com.cn/../..//" from
* Returning a directory for the root drive.
*/
{
Char * X;

For (x = r-> URI; (x = strchr (x ,'//'))! = NULL ;)
* X = '/';
/*/Convert /*/

}
# Endif/* os2 Win32 */
}
Else {
R-> ARGs = NULL;
R-> hostname = NULL;
R-> Status = status;/* set error status */
R-> uri = ap_pstrdup (R-> pool, Uri );
}
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.