Skip to content

Apache httpd does not execute ErrorDocument directive if response code is changed during phase 4 #2849

@TomasKorbar

Description

@TomasKorbar

Describe the bug
When response code is changed during phase 4 and the original response code is other than 200, Apache httpd does not execute ErrorDocument directive and bad response is generated.

Logs and dumps

Output of:

  1. DebugLogs (level 9)

modsec_debug.log

  1. AuditLogs

modsec_audit.log

  1. Error logs

error_log.txt

To Reproduce

  1. Add following configuration:
 ProxyPass /helloworld http://localhost:9090/unavaible ErrorDocument 403 /custompage.html SecRule RESPONSE_PROTOCOL "@contains HTTP" "id:'4',phase:4,auditlog,log,deny,status:403,msg:'yay!'" 
  1. Create and place custompage.html page to server root.
  2. execute $ curl -v localhost/helloworld

Actual behavior

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>403 Forbidden</title> </head><body> <h1>Forbidden</h1> <p>You don't have permission to access this resource.</p> <p>Additionally, a 503 Service Unavailable error was encountered while trying to use an ErrorDocument to handle the request.</p> </body></html> 

Expected behavior
Proper rewritten response with custom error document:

Server (please complete the following information):

  • ModSecurity version (and connector): mod_security-2.9.6
  • WebServer: httpd-2.4.37
  • OS (and distro): Linux Fedora

Rule Set (please complete the following information):

  • Running any public or commercial rule set? No

Additional context

In my opinion, this is caused by apache httpds assumption that changed status of request which got through filter is a recursive error which occured during handling of previous errors.
See ap_die_r function in http module of apache, particularly this part of code:

 /* * The following takes care of Apache redirects to custom response URLs * Note that if we are already dealing with the response to some other * error condition, we just report on the original error, and give up on * any attempt to handle the other thing "intelligently"... */ if (recursive_error != HTTP_OK) { while (r_1st_err->prev && (r_1st_err->prev->status != HTTP_OK)) r_1st_err = r_1st_err->prev; /* Get back to original error */ if (r_1st_err != r) { /* The recursive error was caused by an ErrorDocument specifying * an internal redirect to a bad URI. ap_internal_redirect has * changed the filter chains to point to the ErrorDocument's * request_rec. Back out those changes so we can safely use the * original failing request_rec to send the canned error message. * * ap_send_error_response gets rid of existing resource filters * on the output side, so we can skip those. */ update_r_in_filters(r_1st_err->proto_output_filters, r, r_1st_err); update_r_in_filters(r_1st_err->input_filters, r, r_1st_err); } custom_response = NULL; /* Do NOT retry the custom thing! */ } else { int error_index = ap_index_of_response(type); custom_response = ap_response_code_string(r, error_index); recursive_error = 0; } 

Clearing the original response code with f->r->status = 200; in send_error_bucket function appears to fix this issue.

This issue is a continuation of #533 and extends findings of Marc Stern in #533 (comment)

Metadata

Metadata

Assignees

No one assigned

    Labels

    2.xRelated to ModSecurity version 2.xPlatform - ApachebugIt is a confirmed bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions