EnableSecurity/wafw00f

wafw00f does not detect Azion's WAF anymore

pedro823 opened this issue · 6 comments

Describe the bug
wafw00f's AzionCDN detection code cannot detect any Azion WAFs. This is because they've changed their header settings, not sending Server: Azion anymore.

To Reproduce
I've set up an Azion WAF on this test domain: robert.garrucho.com.br. To reproduce, just run wafw00f https://robert.garrucho.com.br and see that it doesn't detect the WAF.

image

Expected behavior
Here's a code that does detect the WAF:

curl <HOST> -H 'pragma: azion-debug-cache' -o /dev/null -v 2>&1 | grep 'x-cache-location'

By sending pragma: azion-debug-cache as a header, Azion returns debug headers, one of which is the WAF ruleset.

image

Note that www.garrucho.com.br, a website that does not have a WAF set up, returns /.

image

P.S.

I can create a PR and fix this myself! But to do that, I need a little bit of context.

  • How can a plugin ask for the main WAFW00F class to send an additional request with a special header? Does the code have that hability already?

This Azion WAF looks weird. In your case a specific header needs to be sent in the request. However for a sample I found in the wild, it returned the same header in response that you're sending in the request.

$ curl https://www.████████████.com.br/ -sD - -o /dev/null
HTTP/2 200 
date: Mon, 13 Sep 2021 15:40:27 GMT
content-type: text/html
content-length: 184201
x-amz-id-2: 2VIN9/GF0NC3Z6ley37Gf85VPog5q7GPljMyKPKqP0tiI4VS0djLSwdrCxgUtahZuZ5EvZtvdF4=
x-amz-request-id: MVQFXD1XP8KEHY1R
last-modified: Mon, 13 Sep 2021 15:21:55 GMT
x-amz-version-id: null
etag: "66ffa3ecb9f5844391be4c32b2a46320"
server: AmazonS3
cache-control: public, max-age=120, s-maxage=604801
x-varnish: 78778159 66602919
age: 123
via: 1.1 varnish-v4
x-ua-device: desktop
x-host: ██████████.amazonaws.com
x-url: /home/correio/public_html/_conteudo/home/index.html
x-url-without-qs: /
access-control-allow-origin: *
access-control-allow-methods: GET, OPTIONS
access-control-allow-headers: Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token
x-cache2: HIT
pragma: azion-debug-cache
content-security-policy: upgrade-insecure-requests
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
strict-transport-security: max-age=63072000;includeSubDomains;preload
accept-ranges: bytes

Notice that the Pragma: azion-debug-cache is returned in the response by default. Not sure whats up.

Wow, this is by far the weirdest response headers I've ever seen.

for once, server: AmazonS3 implies it's an S3 origin. However, it also has an x-varnish header, and AWS doesn't use (or at least, they don't say that they use) varnish proxies on S3. Azion uses nginx proxies.

also, Pragma: azion-debug-cache is a request header, not a response header. Azion does not return that pragma in any response.

My best guess of that setup is the routing Azion -> varnish -> S3, and that varnish is adding that Pragma response header, as someone didn't know how to configure it.

Just to be sure, does dig CNAME www.<hidden-domain>.com.br +short return something like *.ha.azioncdn.net. or *.map.azionedge.net?

It points to *.ha.azioncdn.net.

dig www.████████████.com.br CNAME +short
225659z.ha.azioncdn.net.

Does that make a difference anyhow? :)

Other variants of responses that I've seen include these headers:

Server: Azion Ipath Server
Server: Azion IMS
Server: azion webserver

I think the best we can do is include all these headers as checks in the response. We can craft an additional request for sure if needed, please take a look at customRequest() function in main.py#L47.

Let me know what do you think about this.

It points to *.ha.azioncdn.net.

dig www.████████████.com.br CNAME +short
225659z.ha.azioncdn.net.

Does that make a difference anyhow? :)

Well, if the domain wasn't even pointed to Azion, there would be no way for them to be using the Azion WAF, so just a sanity check 😅

These headers you've shown, by the way, do not necessarily mean that they're using a WAF, but it strongly points to whether they're using Azion as a CDN or not.

This customRequest() function seems sufficient for this case. I know we should avoid adding new custom requests because it significantly slows down the recognition and raises more red flags, so I'll see if there is any other way out.

Closing this issue as a edge-case for now, please feel free to reopen this issue if there are any new findings. Thanks! :)