owasp-modsecurity / ModSecurity-nginx

ModSecurity v3 Nginx Connector
Apache License 2.0
1.48k stars 274 forks source link

Strange behaviour if `modsecurity off|on` set on `server` and `location` levels. #292

Open remort opened 1 year ago

remort commented 1 year ago

Let's look the example nginx config:

server {
    modsecurity on;
    error_log /var/log/nginx/error.log info;

    location /a {
        error_log /var/log/nginx/a.log info;
        modsecurity on;
        include lua_code_with_proxy_pass_to_python_web_server;
        proxy_pass 1.0.0.1;
    }

    location /b {
        error_log /var/log/nginx/b.log info;
        modsecurity off;
        include lua_code_with_proxy_pass_to_python_web_server;
        proxy_pass 1.0.0.1;
    }

   location /send-to-python-server {
       proxy_pass 1.0.0.2:8080;
   }
}

Issue is reproducible only when modsecurity is On on the server block and Off on one of the locations inside the server block.

Location /a works fine, as expected:

Location /b behavior seems to be broken in case of malicious request:

Lua code in lua_code_with_proxy_pass_to_python_web_server is somewhat like:

location / {
  rewrite_by_lua_block {
    local python_server_res = ngx.location.capture(
          "/send-to-python-server",
          { method = ngx.HTTP_POST, always_forward_body = true }
    )
    ngx.var.result = python_server_res.header["Result"]
    if ngx.var.result then
        ngx.exit(ngx.HTTP_FORBIDDEN)
    else
        ngx.exit(ngx.HTTP_OK)
    end
  }
}

Yes: location / inside locations /a and /b. It works fine. This code is not reachable if modsecurity is on on the server block and off on the location block in case of malicious request.

So, as for me, during the buggy case, modsecurirty triggers on server level. Writes an event to server-level log file. Affects end of request handling somehow. Doesn't block the request since modsec is off on the corresponding location, then request goes to proxy_pass of the location. No intermediary lua code is being executed. Some strange hierarchical logic in modsec seems to fire up here. I need the request being send furtherto python service to block it there, which doesn't happen. Changing rewrite_by_lua_block to content_by_lua_block doesn't matter.

If we have no modsecurity directive on server block (or modsecurity off) - any request (legitimate or malicious) is being handled by lua code with any state of modsecurity directive on the location (either on or off) on any location. Everything works as expected.

martinhsv commented 1 year ago

Hello @remort ,

Thanks for the detailed report.

I seem to recall an earlier report of some inheritance issues between blocks, that may have been resolved by my predecessor in an experimental branch. I'll have a look and see if I can find it.

remort commented 1 year ago

Hello, @martinhsv. Any updates on the issue?