Checklist

  • Confirm there is a filter before you fight it. Baseline a clean payload first.
  • Fingerprint the WAF so you pick known bypasses.
  • Change one variable at a time: encoding, casing, separators, spacing.
  • Keep an out of band probe so a blocked response still tells you something.
  • Record the exact bypass that worked for the report.

A bypass is only worth it once you know a filter is in the way. If a plain ;id works, do not complicate it.

WAF fingerprinting basics

  • Look at response differences: a 403, a scrubbed body, a block page, or a changed server header.
  • Send a known bad string (for example <script> or ../../etc/passwd) and see what trips it.
  • Note the WAF name from block pages, cookies, or headers when present (Cloudflare, Akamai, AWS WAF, ModSecurity, Coraza).
  • Behavior, not the name, drives the bypass. Test what is filtered: spaces, specific keywords, specific characters.

Command injection bypasses

When the obvious operators or keywords are filtered, change the shape without changing the meaning.

Spaces filtered:

  • ${IFS} is the field separator: cat${IFS}/etc/passwd.
  • Brace expansion: {cat,/etc/passwd}.
  • Tab or $IFS$9 in some shells.

Keyword filtered (for example cat):

  • Quotes inside the word: c""at, c'a't /etc/passwd.
  • Backslashes: c\at /etc/passwd.
  • Variable splitting: a=c;b=at;$a$b /etc/passwd.
  • Wildcards: /bin/c?t /etc/passwd, /???/??t /etc/passwd.

Encoding and rebuilding:

  • Base64 the whole command and decode at runtime: echo aWQK | base64 -d | sh.
  • Hex or octal through printf.
  • $(rev<<<'di') style reversal to rebuild a word.

Separators filtered:

  • Try the full set: ;, |, ||, &&, &, newline %0a, and command substitution $(...) or backticks.
  • Carriage return plus newline %0d%0a sometimes passes where %0a alone does not.

Case variation:

  • On case insensitive filters that still pass to a case sensitive shell, mixed case in keywords can slip through a naive regex, though the shell itself is case sensitive for binaries. More useful against the filter layer than the shell.

Comment insertion:

  • In SQL to RCE contexts, inline comments /**/ replace spaces and break keyword matching: UNION/**/SELECT.

Shell alias and builtin evasion

  • Call binaries by full path to dodge alias based blocklists: /bin/cat instead of cat.
  • Use alternate binaries for the same effect: head, tac, less, nl, od, xxd all read files.
  • Use shell builtins: while read l; do echo $l; done < /etc/passwd.
  • exec family and env to launch: env cat /etc/passwd.

trap command bypass

  • Some sandboxes wrap user commands and rely on shell traps or a restricted wrapper. A trap set by the wrapper can sometimes be cleared or redefined, or you can start a fresh shell (bash -c, sh, exec bash) that does not inherit the restriction.
  • Restricted shells (rbash) block cd, /, and redirection. Escape with a language one liner that spawns an unrestricted shell, for example python3 -c 'import os;os.system("bash")', or by invoking a program that can run commands (vi, awk, find -exec).

Pickle scanner bypass

  • Defensive tools scan pickles for dangerous opcodes and known callables such as os.system or subprocess.
  • Reach the same effect through less obvious callables: ctypes to call libc, or pydoc.locate("os.system") to resolve the function indirectly so the literal name does not appear.
  • builtins.eval or builtins.exec reached through attribute lookup can also sidestep name based blocklists.
  • The lesson for defenders: name based scanning is weak. Only unpickle trusted data.

SpEL WAF bypass

  • When T(java.lang.Runtime) is filtered, reach classes reflectively: ''.getClass().forName('java.lang.Runtime').
  • Rebuild blocked strings character by character with .charAt() and concatenation so the literal Runtime or exec never appears in the payload.
  • Use #this, #root, and nested property access to get to a loader when direct type references are blocked.
  • Same idea applies to OGNL and MVEL: build the dangerous reference at runtime instead of writing it literally.

Chunked transfer and request smuggling basics

  • Chunked Transfer-Encoding can split a payload across chunks so a WAF that inspects a single buffer misses the full string.
  • Request smuggling (CL.TE and TE.CL desync between a front proxy and the backend) can deliver a request the WAF never inspected, or poison the next user’s request. Confirm desync carefully with timing before weaponizing.
  • These are powerful and risky. Use them only in scope and document the exact frames.

Rate limit evasion

  • Rotate source IPs where allowed, and spread requests over time.
  • Vary the request enough that simple signature caches do not short circuit.
  • For OOB confirmation you often need only one request that lands, so patience beats volume.

Takeaway

Prove the filter, fingerprint it, then change one property at a time until the meaning survives. Keep the working bypass for the writeup. Continue to Reporting.