Skip to content

bad request leads to two responses #2514

Open
@pgajdos

Description

@pgajdos

Bug Description

After specific wrong request I get second response from Apache httpd server:

$ printf "GET / HTTP/1.1\r\nHost: localhost\r\nTransfer-Encoding: chunked\r\n\r\n\r\n" | nc localhost 60080
HTTP/1.1 400 Bad Request
Date: Thu, 11 Feb 2021 12:48:06 GMT
Server: Apache/2.4.46 (Linux/SUSE)
Connection: close
Content-Type: text/html; charset=iso-8859-1

<html>400</html>
<html>It works!</html>
$

Where

<html>It works!</html>

is content of index.html in docroot.

Logs and dumps

Not necessary.

To Reproduce

Minimal httpd config:

ServerName test
User user
Group users
Listen 60080
PidFile /tmp/apache-rex/poc/pid
ErrorLog /tmp/apache-rex/poc/error_log
LoadModule auth_basic_module /usr/lib64/apache2-prefork/mod_auth_basic.so
LoadModule dir_module /usr/lib64/apache2-prefork/mod_dir.so
LoadModule authz_host_module /usr/lib64/apache2-prefork/mod_authz_host.so
LoadModule authz_core_module /usr/lib64/apache2-prefork/mod_authz_core.so
LoadModule unique_id_module /usr/lib64/apache2-prefork/mod_unique_id.so
LoadModule security2_module /usr/lib64/apache2/mod_security2.so
LogLevel trace8
DocumentRoot /srv/www/htdocs
DirectoryIndex index.html

ErrorDocument 400 "<html>400</html>\n"

SecRuleEngine DetectionOnly
SecRequestBodyAccess on
SecAuditLogType Serial
SecAuditLog /tmp/apache-rex/poc/modsec_audit.log
SecTmpDir /tmp/
SecDataDir /tmp/

### example configuration

<Directory "/tmp/apache-rex/poc/htdocs">
  Require local
</Directory>

Expected behavior

$ printf "GET / HTTP/1.1\r\nHost: localhost\r\nTransfer-Encoding: chunked\r\n\r\n\r\n" | nc localhost 60080
HTTP/1.1 400 Bad Request
Date: Thu, 11 Feb 2021 12:48:06 GMT
Server: Apache/2.4.46 (Linux/SUSE)
Connection: close
Content-Type: text/html; charset=iso-8859-1

<html>400</html>

Server (please complete the following information):

  • ModSecurity version (and connector): ModSecurity v2.9.3, v2.9.2
  • WebServer: Apache httpd 2.4.46
  • OS (and distro): openSUSE Tumbleweed

Tested also with Ubuntu 20.04/http 2.4.41/mod_security 2.9.3 and fedora33/httpd 2.4.46/mod_security 2.9.3.

Patch

Yann Ylavic (@ylavic) wrote following patch:

diff -ru modsecurity-2.9.3.old/apache2/apache2_io.c modsecurity-2.9.3.new/apache2/apache2_io.c
--- modsecurity-2.9.3.old/apache2/apache2_io.c  2018-12-04 19:49:37.000000000 +0100
+++ modsecurity-2.9.3.new/apache2/apache2_io.c  2021-02-12 13:28:27.739749566 +0100
@@ -209,6 +209,10 @@
              *      too large and APR_EGENERAL when the client disconnects.
              */
             switch(rc) {
+                case AP_FILTER_ERROR :
+                    *error_msg = apr_pstrdup(msr->mp, "Error reading request body: filter error");
+                    return -8;
+
                 case APR_INCOMPLETE :
                     *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc));
                     return -7;
@@ -218,7 +222,7 @@
                 case APR_TIMEUP :
                     *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc));
                     return -4;
-                case AP_FILTER_ERROR :
+                case APR_ENOSPC:
                     *error_msg = apr_psprintf(msr->mp, "Error reading request body: HTTP Error 413 - Request entity too large. (Most likely.)");
                     return -3;
                 case APR_EGENERAL :
diff -ru modsecurity-2.9.3.old/apache2/mod_security2.c modsecurity-2.9.3.new/apache2/mod_security2.c
--- modsecurity-2.9.3.old/apache2/mod_security2.c       2018-12-04 19:49:37.000000000 +0100
+++ modsecurity-2.9.3.new/apache2/mod_security2.c       2021-02-12 13:34:22.940428406 +0100
@@ -1013,7 +1013,7 @@
     }

     rc = read_request_body(msr, &my_error_msg);
-    if (rc < 0 && msr->txcfg->is_enabled == MODSEC_ENABLED) {
+    if (rc < 0) {
         switch(rc) {
             case -1 :
                 if (my_error_msg != NULL) {
@@ -1021,6 +1021,21 @@
                 }
                 return HTTP_INTERNAL_SERVER_ERROR;
                 break;
+            case -2 : /* Bad request. */
+            case -6 : /* EOF when reading request body. */
+            case -7 : /* Partial recieved */
+                if (my_error_msg != NULL) {
+                    msr_log(msr, 4, "%s", my_error_msg);
+                }
+                r->connection->keepalive = AP_CONN_CLOSE;
+                return HTTP_BAD_REQUEST;
+                break;
+            case -3 : /* Apache's LimitRequestBody. */
+                if (my_error_msg != NULL) {
+                    msr_log(msr, 1, "%s", my_error_msg);
+                }
+                return HTTP_REQUEST_ENTITY_TOO_LARGE;
+                break;
             case -4 : /* Timeout. */
                 if (my_error_msg != NULL) {
                     msr_log(msr, 4, "%s", my_error_msg);
@@ -1042,19 +1057,11 @@
                     }
                 }
                 break;
-            case -6 : /* EOF when reading request body. */
-                if (my_error_msg != NULL) {
-                    msr_log(msr, 4, "%s", my_error_msg);
-                }
-                r->connection->keepalive = AP_CONN_CLOSE;
-                return HTTP_BAD_REQUEST;
-                break;
-            case -7 : /* Partial recieved */
+            case -8 : /* Filter error. */
                 if (my_error_msg != NULL) {
-                    msr_log(msr, 4, "%s", my_error_msg);
+                    msr_log(msr, 1, "%s", my_error_msg);
                 }
-                r->connection->keepalive = AP_CONN_CLOSE;
-                return HTTP_BAD_REQUEST;
+                return AP_FILTER_ERROR;
                 break;
             default :
                 /* allow through */

I can send a PR, but I am not the author.

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