Apache 's ..% 5C Vulnerability Cause Source Code Analysis

xiaoxiao2021-03-06  128

Below is the code for the process of 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-> pased_uri.path) {

/ * If it is not a proxy * /

Access_status = AP_UNESCAPE_URL (r-> pased_uri.path);

/ * Decoding%, RFC requirements * /

IF (Access_Status) {

AP_D

IE (Access_Status, R);

Return;

}

}

AP_GETPARENTS (R-> URI); / * OK --- Shrinking Transformations ... * /

/ * Treatment /../, error, did not consider the following /../ * /

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_HTTTP_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-1.0")) {

R-> proto_num = http_version (1,0);

}

/ *

* NB: Directory_walk () clears the per_dir_config, so we don't inherit

* from location_walk () Above

* /

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 Grou

PS 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-> pased_uri.scheme! = NULL

&& struct (r-> pased_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);

}

Below is the source code src / main / util.c processing /../ code:

API_EXPORT (VOID) AP_GETPARENTS (Char * Name)

{

INT L, W;

/ * Four Pases, 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 ../id /../) * /

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';

}

}

Everyone saw it, obviously did not consider "/../" below Windows, it seems that people who write this function are not familiar with the characteristics of Windows, which is a person who has been programmed under * UNIX. In fact, I didn't consider "/../" under Windows has already had a lot of problems. Then why didn't Telnet use "/../"? It seems that all "/" will be replaced with "/" before decoding. Obviously this conversion is that after decoding, it is estimated that "/../" is estimated that the reason is to be converted first, this is with IIS% C1% 1C

Vulnerability is the same. According to this, you must pay more attention to what is coded, decoded, must re-consider some of the tests, because you can't get it, you can re-encode anything that does not meet the previous test.

Look this is the process module "/" in the source code src / main / http_protocol.c into "/" to "/":

/ * Parse_uri: Break Apart The URI

* Side Effects:

* - sets r-> args to rest at '?' (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-> pased_uri);

} else {

/ * Simple Syntax Errors in Urls Are Trapped by Parse_uri_components (). * /

Status = AP_PARSE_URI_Components (r-> pool, uri, & r-> pased_uri);

}

IF (ap_is_http_success (status) {

/ * if it has a scheme we may need to do absoluteuri vhost stuff * /

IF (r-> pased_uri.scheme

&&! strcasecmp (r-> pased_uri.scheme, ap_http_method (r))) {r-> Hostname = r-> pased_uri.hostname;

} else if (r-> method_number == m_connect) {

R-> Hostname = r-> pased_uri.hostname;

}

R-> args = r-> pased_uri.query;

R-> URI = r-> pases_uri.path? r-> pased_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.net.com.cn/..///" from

* Returning a Directory for the root driving.

* /

{

Char * x;

For (x = r-> URI; (x = strchr (x, '//'))! = null;)

* x = '/';

/ * / Conversion to / * /

}

#ENDIF / * OS2 Win32 * /

}

Else {

R-> arggs = null;

R-> Hostname = NULL;

R-> status = status; / * set error status * /

R-> URI = AP_PSTRDUP (r-> pool, URI);

}

}

转载请注明原文地址:https://www.9cbs.com/read-101955.html

New Post(0)