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);
}
}