1

Details

I have an application running behind an Azure Web Application Firewall (WAF) on an Azure Application Gateway (AppGW) that was previously on an on-premises server. Since moving it to Azure, users and testers are now getting 403 Forbidden when attempting to send data to the service. I believe these are seen by the WAF as XSS or SQL Injection attacks, but I don't have a way to prove it.

So the question is, why are these requests being blocked by a WAF?

Note: These curl commands were generated by Postman. I took the JSON document and put it into a function.

Example callers:

#!/usr/bin/env bash

function json_document() {
  cat <<EOF
{
  "data": [
    {
      "code": "xxyyzz",
      "codeType": "aaabbbccc",
      "description": "some random string with >48 stuff, here"
    }
  ],
  "attributes": [
    {
      "vendorName": "a company",
      "url": "https://my.company.com/app/SSO/",
      "isDefault": true
    }
  ]
}
EOF
}

/usr/bin/curl \
  --location \
  --request POST \
  --url 'https://my.company.com/v1/csharp/app/resource' \
  --header "Authorization: Bearer ${AUTH_PAT}" \
  --header 'Content-Type: application/json' \
  --data-raw "$(json_document)"

The above curl command works if I remove the > and replace it with &gt;. Then the second example:

#!/usr/bin/env bash

function json_document() {
  cat <<EOF
{
  "name": "Item One (3 TIMES A DAY) (deferiprone) - Prior Authorization",
  "attributes": [
        {
      "vendorName": "Vendor Name",
      "url": "Vendor URL",
      "isDefault": true
    }
  ]
}
EOF
}

/usr/bin/curl \
  --location \
  --request POST \
  --url 'https://my.company.com/v1/csharp/app/resource' \
  --header "Authorization: Bearer ${AUTH_PAT}" \
  --header 'Content-Type: application/json' \
  --data-raw "$(json_document)"

The above works when we remove the DAY) ( portion or put it in a different spot in the string, which breaks some formatting rules later on.

Both of these get the following result:

<html>
  <head><title>403 Forbidden</title></head>
  <body>
    <center><h1>403 Forbidden</h1></center>
    <hr><center>Microsoft-Azure-Application-Gateway/v2</center>
  </body>
</html>

Question

Why are these being blocked for seemingly innocent strings?

4
  • I'm afraid --data-raw is not the right option, you should just the simple --data. With that, your first request is passed. But the second one triggers an error: [id "933210"] [msg "PHP Injection Attack: Variable Function Call Found"] [data "Matched Data: (3 TIMES A DAY) (deferiprone) found within ARGS:name: Item One (3 TIMES A DAY) (deferiprone) - Prior Authorization"]
    – airween
    Oct 5, 2022 at 9:58
  • Sorry, looks like some other rule triggered in your case - in 3.1, there wasn't the mentioned rule (933210). But unfortunately I do not have any 3.1 rule set...
    – airween
    Oct 5, 2022 at 10:02
  • @airween, how did you test that? I generated this curl call from Postman, so I didn't change the command very much beyond putting the JSON in a function.
    – FilBot3
    Oct 5, 2022 at 12:31
  • I have many running ModSecurity instance, and could check your request. For eg. if you have Docker, you can try hub.docker.com/r/owasp/modsecurity-crs or, but it doesn't seem to have 3.1 either. The other way is to use CRS Sandbox: coreruleset.org/20211209/introducing-the-crs-sandbox. It works without any installation, but perhaps the 3.1 is missing too.
    – airween
    Oct 5, 2022 at 17:22

2 Answers 2

2

If you have Docker, you can try CRS ModSecurity Docker, but it doesn't seem to have CRS 3.1. The other way is to use CRS Sandbox. It works without any installation, but perhaps the 3.1 is missing too. With these, you can check which rules were triggered.

2
  • It seems that the first cURL call is seen as a SQL Injection Attack: SQL Tautology Detected. I'll accept this answer, but my calls that are in the example are seen as SQL Injection Attacks plus too many SQL character sequences found.
    – FilBot3
    Oct 17, 2022 at 16:21
  • Check out my answer posted as well
    – FilBot3
    Oct 17, 2022 at 16:31
0

I used the solution proposed by here to figure out how to run the docker.io/owasp/modsecurity-crs:nginx-alpine container using Podman to test my calls.

So, I created this Kubernetes Deployment Manifest to have Podman play.

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: owasp-crs-demo
  labels:
    owasp: crs-podman
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: owasp-crs
  template:
    metadata:
      labels:
        app.kubernetes.io/name: owasp-crs
    spec:
      containers:
        - name: owaspcrsexample
          image: docker.io/owasp/modsecurity-crs:nginx-alpine
          ports:
            - containerPort: 80
              hostPort: 8080
              protocol: TCP
              name: crs-http
          env:
            - name: BACKEND
              value: http://127.0.0.1:5000
            - name: PARANOIA
              value: 5
        - name: philapp
          image: philflaskapp
          ports:
            - containerPort: 5000
              protocol: TCP
              name: flask-http
...

I then used the following command to bring up the Pod.

podman play kube --build --replace k8s-owasp-crs-setup.yaml

My philflaskapp is located here:

➜  k8s-owasp-crs-examples git:(main) 
> tree
.
├── README.md
├── Taskfile.yaml
├── examples
│   └── output
│       ├── modsecurity-crs-finding-output.json
│       └── modsecurity-crs-finding-output.yaml
├── k8s-owasp-crs-setup.yaml
├── philflaskapp
│   ├── Containerfile
│   ├── __pycache__
│   │   └── phil_flask_app.cpython-310.pyc
│   └── phil_flask_app.py
└── tags

4 directories, 9 files

Then I ran the bash script in the OP description. You should recieve:

<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.20.2</center>
</body>
</html>

To view these logs, use the following command:

podman logs owasp-crs-demo-pod-0-owaspcrsexample

From here, it may seem like a lot of jibberish, but if you copy out the Nginx access logs, you can use Vim and python -m json.tool to parse the JSON so it's readable. These should help you identify any WAF rule matches.

You can find the code above in this GitHub repository:

2
  • @airween This is the answer that I came up with. This helped me and my developers figure out what they were doing wrong and could fix in their application to better avoid these matches.
    – FilBot3
    Oct 17, 2022 at 16:30
  • 1
    thank, and congratulation! Also it's really-really good to see that you could solved this issue. I really hope that I could help something :)
    – airween
    Oct 17, 2022 at 18:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .