coreruleset / nextcloud-rule-exclusions-plugin

Rule exclusion plugin for Nextcloud
Apache License 2.0
11 stars 7 forks source link

Rules 921110, 921130 hit with the Nextcloud Deck app when trying to add code blocks to cards #80

Closed jessebot closed 2 months ago

jessebot commented 2 months ago

Hi core rule set friends!

I tried to create a card in Nextcloud's Deck app with the following code block:

2024/07/02 15:21:45 [error] 1908#1908: *2728331 [client 192.168.1.1] ModSecurity: Access denied with code 403 (phase 2). Matched "Operator `Ge' with parameter `5' against variable `TX:ANOMALY_SCORE' (Value: `5' ) [file "/etc/nginx/owasp-modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "81"] [id "949110"] [rev ""] [msg "Inbound Anomaly Score Exceeded (Total Score: 5)"] [data ""] [severity "2"] [ver "OWASP_CRS/3.3.5"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "10.42.0.34"] [uri "/_matrix/media/r0/upload"] [unique_id "171992650595.932620"] [ref ""], client: 192.168.1.1, server: xxxxxx.xxxxxx.xxxxxx, request: "POST /_matrix/media/r0/upload HTTP/1.1", host: "xxxxxx.xxxxxx.xxxxxx"

It was actually a card for fixing another modsecurity issue with matrix haha, but it gave me this error:

{
  "transaction": {
    "client_ip": "192.168.1.1",
    "time_stamp": "Tue Jul  2 15:30:46 2024",
    "server_id": "fade3de079ac9ce77586b1809c4a4",
    "client_port": 38057,
    "host_ip": "10.42.0.46",
    "host_port": 443,
    "unique_id": "171992704647.640017",
    "request": {
      "method": "PUT",
      "http_version": 2,
      "uri": "/apps/deck/cards/175",
      "body": "{\"id\":175,\"title\":\"fix modSecurity rule exception for matrix photo uploads\",\"description\":\"Moved matrix, grafana, and postgresql rules into their own plugins in this commit:  \\n<https://github.com/small-hack/argocd-apps/commit/3b10470ae85b81d2452106c2094814f0713b3f48>\\n\\nhad to reopen this\\n\\n```\\n2024/07/02 15:21:45 [error] 1908#1908: *2728331 [client 192.168.1.1] ModSecurity: Access denied with code 403 (phase 2). Matched \\\"Operator `Ge' with parameter `5' against variable `TX:ANOMALY_SCORE' (Value: `5' ) [file \\\"/etc/nginx/owasp-modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf\\\"] [line \\\"81\\\"] [id \\\"949110\\\"] [rev \\\"\\\"] [msg \\\"Inbound Anomaly Score Exceeded (Total Score: 5)\\\"] [data \\\"\\\"] [severity \\\"2\\\"] [ver \\\"OWASP_CRS/3.3.5\\\"] [maturity \\\"0\\\"] [accuracy \\\"0\\\"] [tag \\\"application-multi\\\"] [tag \\\"language-multi\\\"] [tag \\\"platform-multi\\\"] [tag \\\"attack-generic\\\"] [hostname \\\"10.42.0.34\\\"] [uri \\\"/_matrix/media/r0/upload\\\"] [unique_id \\\"171992650595.932620\\\"] [ref \\\"\\\"], client: 192.168.1.1, server: xxxxxx.xxxxxx.xxxxxx, request:\\\"POST /_matrix/media/r0/upload HTTP/1.1\\\", host: \\\"xxxxxx.xxxxxx.xxxxxx\\\"\\n```\",\"stackId\":43,\"type\":\"plain\",\"lastModified\":1719927039.722,\"lastEditor\":null,\"createdAt\":1719915377,\"labels\":[{\"id\":50,\"title\":\"matrix \",\"color\":\"0082c9\",\"boardId\":37,\"cardId\":175,\"lastModified\":0,\"ETag\":\"cfcd208495d565ef66e7dff9f98764da\"},{\"id\":145,\"title\":\"modsecurity\",\"color\":\"3e253a\",\"boardId\":37,\"cardId\":175,\"lastModified\":0,\"ETag\":\"cfcd208495d565ef66e7dff9f98764da\"}],\"assignedUsers\":[{\"id\":170,\"participant\":{\"primaryKey\":\"myuser\",\"uid\":\"myuser\",\"displayname\":\"my user\",\"type\":0},\"cardId\":175,\"type\":0}],\"attachments\":null,\"attachmentCount\":0,\"owner\":{\"primaryKey\":\"myuser\",\"uid\":\"myuser\",\"displayname\":\"my user\",\"type\":0},\"order\":0,\"archived\":false,\"done\":\"2024-07-02T10:41:06+00:00\",\"duedate\":null,\"deletedAt\":0,\"commentsUnread\":0,\"commentsCount\":0,\"ETag\":\"514f35643b51eb2c03b0829c3ba69a75\",\"overdue\":0}",
      "headers": {
        "origin": "https://cloud.mydomain.com",
        "dnt": "1",
        "requesttoken": "xxxxx/xxxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxxxx=:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "x-requested-with": "XMLHttpRequest, XMLHttpRequest",
        "content-type": "application/json",
        "accept-encoding": "gzip, deflate, br, zstd",
        "cookie": "__Host-nc_sameSiteCookielax=true; __Host-nc_sameSiteCookiestrict=true; oc_sessionPassphrase=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; xxxxxxxxxxxx=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; VouchCookie=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "content-length": "1962",
        "accept-language": "en-US,en;q=0.5",
        "te": "trailers",
        "accept": "application/json, text/plain, */*",
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:127.0) Gecko/20100101 Firefox/127.0",
        "sec-fetch-site": "same-origin",
        "host": "cloud.mydomain.com",
        "sec-fetch-dest": "empty",
        "sec-fetch-mode": "cors"
      }
    },
    "response": {
      "body": "<html>\r\n<head><title>403 Forbidden</title></head>\r\n<body>\r\n<center><h1>403 Forbidden</h1></center>\r\n<hr><center>nginx</center>\r\n</body>\r\n</html>\r\n",
      "http_code": 403,
      "headers": {
        "Server": "",
        "Date": "Tue, 02 Jul 2024 13:30:46 GMT",
        "Content-Length": "146",
        "Content-Type": "text/html",
        "Connection": "close",
        "Strict-Transport-Security": "max-age=31536000; includeSubDomains"
      }
    },
    "producer": {
      "modsecurity": "ModSecurity v3.0.12 (Linux)",
      "connector": "ModSecurity-nginx v1.0.3",
      "secrules_engine": "Enabled",
      "components": [
        "OWASP_CRS/3.3.5\""
      ]
    },
    "messages": [
      {
        "message": "HTTP Request Smuggling Attack",
        "details": {
          "match": "Matched \"Operator `Rx' with parameter `(?:get|post|head|options|connect|put|delete|trace|track|patch|propfind|propatch|mkcol|copy|move|lock|unlock)\\s+(?:\\/|\\w)[^\\s]*(?:\\s+http\\/\\d|[\\r\\n])' against variable `REQUEST_BODY' (Value: `{\"id\":175,\"title\":\"fix modSecurity rule exception for matrix photo uploads\",\"description\":\"Moved mat (1862 characters omitted)' )",
          "reference": "o923,36v17,992t:urlDecodeUni,t:htmlEntityDecode,t:lowercaseo1058,36v1228,1962t:urlDecodeUni,t:htmlEntityDecode,t:lowercase",
          "ruleId": "921110",
          "file": "/etc/nginx/owasp-modsecurity-crs/rules/REQUEST-921-PROTOCOL-ATTACK.conf",
          "lineNumber": "34",
          "data": "Matched Data: post /_matrix/media/r0/upload http/1 found within REQUEST_BODY: {\"id\":175,\"title\":\"fix modsecurity rule exception for matrix photo uploads\",\"description\":\"moved matrix, grafana, and postgresql rules into their own plugins in this commit:  \\n<https://github.com/small-hack/argocd-apps/commit/3b10470ae85b81d2452106c2094814f0713b3f48>\\n\\nhad to reopen this\\n\\n```\\n2024/07/02 15:21:45 [error] 1908#1908: *2728331 [client 192.168.1.1] modsecurity: access denied with code 403 (phase 2). matched \\\"operator `ge' with parameter `5' against variable `tx:anomaly_score' (value: `5' ) [file \\\"/etc/nginx/owasp-modsecurity-crs/rules/request-949-blocking-evaluation.conf\\\"] [line \\\"81\\\"] [id \\\"949110\\\"] [rev \\\"\\\"] [msg \\\"inbound anomaly score exceeded (total score: 5)\\\"] [data \\\"\\\"] [severity \\\"2\\\"] [ver \\\"owasp_crs/3.3.5\\\"] [maturity \\\"0\\\"] [accuracy \\\"0\\\"] [tag \\\"application-multi\\\"] [tag \\\"language-multi\\\"] [tag \\\"platform-multi\\\"] [tag \\\"attack-generic\\\"] [hostname \\\"10.42.0.34\\\"] [uri \\\"/_matrix/media/r0/upload\\\"] [unique_id \\\"171992650595.932620\\\"] [ref \\\"\\\"], client: 192.168.1.1, server: xxxxxx.xxxxxx.xxxxxx, request: \\\"post /_matrix/media/r0/upload http/1.1\\\", host: \\\"xxxxxx.xxxxxx.xxxxxx\\\"\\n```\",\"stackid\":43,\"type\":\"plain\",\"lastmodified\":1719927039.722,\"lasteditor\":null,\"createdat\":1719915377,\"labels\":[{\"id\":50,\"title\":\"matrix \",\"color\":\"0082c9\",\"boardid\":37,\"cardid\":175,\"lastmodified\":0,\"etag\":\"cfcd208495d565ef66e7dff9f98764da\"},{\"id\":145,\"title\":\"modsecurity\",\"color\":\"3e253a\",\"boardid\":37,\"cardid\":175,\"lastmodified\":0,\"etag\":\"cfcd208495d565ef66e7dff9f98764da\"}],\"assignedusers\":[{\"id\":170,\"participant\":{\"primarykey\":\"myuser\",\"uid\":\"myuser\",\"displayname\":\"my user\",\"type\":0},\"cardid\":175,\"type\":0}],\"attachments\":null,\"attachmentcount\":0,\"owner\":{\"primarykey\":\"myuser\",\"uid\":\"myuser\",\"displayname\":\"my user\",\"type\":0},\"order\":0,\"archived\":false,\"done\":\"2024-07-02t10:41:06 00:00\",\"duedate\":null,\"deletedat\":0,\"commentsunread\":0,\"commentscount\":0,\"etag\":\"514f35643b51eb2c03b0829c3ba69a75\",\"overdue\":0}",
          "severity": "2",
          "ver": "OWASP_CRS/3.3.5",
          "rev": "",
          "tags": [
            "application-multi",
            "language-multi",
            "platform-multi",
            "attack-protocol",
            "paranoia-level/1",
            "OWASP_CRS",
            "capec/1000/210/272/220/33"
          ],
          "maturity": "0",
          "accuracy": "0"
        }
      },
      {
        "message": "HTTP Response Splitting Attack",
        "details": {
          "match": "Matched \"Operator `Rx' with parameter `(?:\\bhttp/\\d|<(?:html|meta)\\b)' against variable `ARGS:json.description' (Value: `Moved matrix, grafana, and postgresql rules into their own plugins in this commit:  \\x0a<https://git (913 characters omitted)' )",
          "reference": "o953,6v17,992t:urlDecodeUni,t:htmlEntityDecode,t:lowercase",
          "ruleId": "921130",
          "file": "/etc/nginx/owasp-modsecurity-crs/rules/REQUEST-921-PROTOCOL-ATTACK.conf",
          "lineNumber": "89",
          "data": "Matched Data: http/1 found within ARGS:json.description: moved matrix, grafana, and postgresql rules into their own plugins in this commit:  \n<https://github.com/small-hack/argocd-apps/commit/3b10470ae85b81d2452106c2094814f0713b3f48>\n\nhad to reopen this\n\n```\n2024/07/02 15:21:45 [error] 1908#1908: *2728331 [client 192.168.1.1] modsecurity: access denied with code 403 (phase 2). matched \"operator `ge' with parameter `5' against variable `tx:anomaly_score' (value: `5' ) [file \"/etc/nginx/owasp-modsecurity-crs/rules/request-949-blocking-evaluation.conf\"] [line \"81\"] [id \"949110\"] [rev \"\"] [msg \"inbound anomaly score exceeded (total score: 5)\"] [data \"\"] [severity \"2\"] [ver \"owasp_crs/3.3.5\"] [maturity \"0\"] [accuracy \"0\"] [tag \"application-multi\"] [tag \"language-multi\"] [tag \"platform-multi\"] [tag \"attack-generic\"] [hostname \"10.42.0.34\"] [uri \"/_matrix/media/r0/upload\"] [unique_id \"171992650595.932620\"] [ref \"\"], client: 192.168.1.1, server: xxxxxx.xxxxxx.xxxxxx, request: \"post /_matrix/media/r0/upload http/1.1\", host: \"xxxxxx.xxxxxx.xxxxxx\"\n```",
          "severity": "2",
          "ver": "OWASP_CRS/3.3.5",
          "rev": "",
          "tags": [
            "application-multi",
            "language-multi",
            "platform-multi",
            "attack-protocol",
            "paranoia-level/1",
            "OWASP_CRS",
            "capec/1000/210/272/220/34"
          ],
          "maturity": "0",
          "accuracy": "0"
        }
      },
      {
        "message": "Inbound Anomaly Score Exceeded (Total Score: 15)",
        "details": {
          "match": "Matched \"Operator `Ge' with parameter `5' against variable `TX:ANOMALY_SCORE' (Value: `15' )",
          "reference": "",
          "ruleId": "949110",
          "file": "/etc/nginx/owasp-modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf",
          "lineNumber": "81",
          "data": "",
          "severity": "2",
          "ver": "OWASP_CRS/3.3.5",
          "rev": "",
          "tags": [
            "application-multi",
            "language-multi",
            "platform-multi",
            "attack-generic"
          ],
          "maturity": "0",
          "accuracy": "0"
        }
      }
    ]
  }
}

Looks like it hit the following rules: 921110, 921130, 949110.

would it make sense to have something like this added to the plugin?

SecRule REQUEST_URI "@beginsWith /apps/deck/cards" \
    "id:1000,\
    phase:1,\
    pass,\
    nolog,\
    ctl:ruleRemoveById=921110"

SecRule REQUEST_URI "@beginsWith /apps/deck/cards" \
    "id:1000,\
    phase:1,\
    pass,\
    nolog,\
    ctl:ruleRemoveById=921130"

SecRule REQUEST_URI "@beginsWith /apps/deck/cards" \
    "id:1000,\
    phase:1,\
    pass,\
    nolog,\
    ctl:ruleRemoveById=949110"

If so, I could try and submit a PR for this. If not, please let me know what the best course of action is šŸ™

Env info

CRS version: 3.3.5 ModSecurity version: ModSecurity v3.0.12 (Linux) type of web server: ingress-nginx controller via k8s

jessebot commented 2 months ago

Also, to note, this happens when I try to put most json code blocks into Nextcloud Deck cards too.

EsadCetiner commented 2 months ago

@jessebot Thanks for the report

I see that your using CRS 3.3.5, plugins are only supported in CRS 4.x and newer releases. I recommend upgrading to the latest CRS 4.4 for proper support for plugins.

would it make sense to have something like this added to the plugin?

I see a few issues with the rules that you wrote, most notably you are disabling 949110 which is an anomoly scoring rule, disabling 949110 disables CRS. You only want to disable rules that contribute to the anomoly score, like you did with 921130 and 921110. Never disable 949110 unless you want to disable the CRS.

When disabling rules, it's generally not a good idea to disable them completely, this can introduce bypasses. You should instead disable rules for a specific target, this is the safest way to disable a rule. See this example in the docs on how to do this https://coreruleset.org/docs/concepts/false_positives_tuning/#example-7-ctlruleremovetargetbyid

The issue you reported should have been caught by our testing, I added an extra test to make sure this doesn't occur in the future.

I have a PR open that should fix this issue, I found a few more false positives in my own testing: #81

jessebot commented 2 months ago

I see that your using CRS 3.3.5, plugins are only supported in CRS 4.x and newer releases. I recommend upgrading to the latest CRS 4.4 for proper support for plugins.

I was using 3.3.5 only until this PR for the ingress-nginx controller gets released as the docs still say:

Plugins are not part of the CRS 3.3.x release line. They are released officially with CRS 4.0. In the meantime, plugins can be used with one of the stable releases by following the instructions presented below.

Until that PR is released, I can't upgrade the CRS unfortunately :( It is merged though, so I am hopeful it makes it into a release in the next month or so šŸ¤ž

I see a few issues with the rules that you wrote, most notably you are disabling 949110 which is an anomoly scoring rule, disabling 949110 disables CRS. You only want to disable rules that contribute to the anomoly score, like you did with 921130 and 921110. Never disable 949110 unless you want to disable the CRS.

Oh, thank you for letting me know! šŸ™

The issue you reported should have been caught by our testing, I added an extra test to make sure this doesn't occur in the future.

I have a PR open that should fix this issue, I found a few more false positives in my own testing: https://github.com/coreruleset/nextcloud-rule-exclusions-plugin/pull/81

Thank you so much!

jessebot commented 2 months ago

I also wanted to note that using Deck, also get ModSecurity rule exceptions when trying to click the complete button or clicking the card's menu and hitting "mark as done" (hits rule 911100) in a deck card, though it looks like you got that one in #81 šŸŽ‰

I also get a rule hit when trying to change a tag (also hits rule 911100). In case you didn't know how to edit a tag if you want to reproduce (because I didn't until today):

Screenshot 2024-07-04 at 20 14 21 of finding tag edit button in top right Screenshot 2024-07-04 at 20 15 02 of finding tag edit button part 2 in list
EsadCetiner commented 2 months ago

@jessebot Thanks, I've pushed a few more fixes along with what you reported.