Create How To Exploit PHP Remotely To Bypass Filters & WAF Rules.md

from: https://tutorialboy24.medium.com/how-to-exploit-php-remotely-to-bypass-filters-waf-rules-46dc597cf322
author: TutorialBoy
This commit is contained in:
tennc 2022-08-30 23:27:59 +08:00 committed by GitHub
parent b37de05dbb
commit 3021d176c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -0,0 +1,90 @@
![](https://miro.medium.com/max/1400/0*YS9Xgpo65DOnibMh.png)
This is the first of two vulnerable PHP scripts that Im going to use for all tests. This script is definitely too easy and dumb but its just to reproducing a remote code execution vulnerability scenario (probably in a real scenario, youll do a little bit more work to reach this situation):
![](https://miro.medium.com/proxy/1*8642MMLA0kKXigNugsntpA.png)
Obviously, the sixth line is pure evil. The third line tries to intercept functions like system, exec or passthru (therere many other functions in PHP that can execute system commands but lets focus on these three). This script is running in a web server behind the Cloudflare WAF (as always, Im using Cloudflare because its easy and widely known by the people, this doesnt mean that Cloudflare WAF is not secure. All other WAF have the same issues, more or less…). The second script will be behind ModSecurity + OWASP CRS3.
For the first test, I try to read /etc/passwd using system() function by the request /cfwaf.php?code=system(“cat /etc/passwd”);
![](https://miro.medium.com/proxy/1*Z7_QAFUWfTuGkkXC5iTIYQ.png)
As you can see, CloudFlare blocks my request (maybe because of the “/etc/passwd”) but, if you have read my last article about uninitialized variables, I can easily bypass it with something like cat /etc$u/passwd
![](https://miro.medium.com/proxy/1*XjThoSZZVxdHPsc7yvr3cA.png)
Cloudflare WAF has been bypassed but the check on the users input blocked my request because Im trying to use the “system” function. Is there a syntax that let me use the system function without using the “system” string? Lets take a look at the PHP [documentation about strings!](https://secure.php.net/manual/en/language.types.string.php)
PHP String escape sequences
* \\\[07\]{1,3} sequence of characters in octal notation, which silently overflows to fit in a byte (e.g. “\\400” === “\\000”)
* \\x\[09A-Fa-f\]{1,2} sequence of characters in hexadecimal notation (e.g. “\\x41”)
* \\u{\[09A-Fa-f\]+} sequence of Unicode codepoint, which will be output to the string as that codepoints UTF-8 representation (added in PHP 7.0.0)
Not everyone knows that PHP has a lot of syntaxes for representing a string, and with the “PHP Variable functions” it becomes our Swiss Army knife for bypassing filters and rules.
PHP supports the concept of variable functions. This means that if a variable name has parentheses appended to it, PHP will look for a function with the same name as whatever the variable evaluates to, and will attempt to execute it. Among other things, this can be used to implement callbacks, function tables, and so forth.
this means that syntaxes like $var(args); and “string”(args); are equal to function(args);. If I can call a function by using a variable or a string, it means that I can use an escape sequence instead of the name of a function. Here an example:
![](https://miro.medium.com/proxy/1*6tj_EG6wcNf1cZTx6mGcQw.jpeg)
the third syntax is an escape sequence of characters in a hexadecimal notation that PHP converts to the string “system” and then it converts to the function system with the argument “ls”. Lets try with our vulnerable script:
![](https://miro.medium.com/proxy/1*cyDR__qU4qIfwRbHq0Fsdg.png)
This technique doesnt work for all PHP functions, variable functions wont work with language constructs such as echo, print, unset(), isset(), empty(), include, require and the like. Utilize wrapper functions to make use of any of these constructs as variable functions.
What happens if I exclude characters like double and single quotes from the user input on the vulnerable script? Is it possible to bypass it even without using double quotes? Lets try:
![](https://miro.medium.com/proxy/1*xaTUZpVHH-CwqDLSvLC2LA.png)
as you can see on the third line, now the script prevents the use of “ and inside the $\_GET\[code\] query string parameter. My previous payload should be blocked now:
![](https://miro.medium.com/proxy/1*qNE1auDSwwnzBVwO174kXw.png)
Luckily, in PHP, we dont always need quotes to represent a string. PHP makes you able to declare the type of an element, something like $a = (string)foo; in this case, $a contains the string “foo”. Moreover, whatever is inside round brackets without a specific type declaration, is treated as a string:
![](https://miro.medium.com/proxy/1*GKGsbLzK70i4qo_eg8Irhg.jpeg)
In this case, weve two ways to bypass the new filter: the first one is to use something like (system)(ls); but we cant use “system” inside the code parameter, so we can concatenate strings like (sy.(st).em)(ls);. The second one is to use the $\_GET variable. If I send a request like ?a=system&b=ls&code=$\_GET\[a\]($\_GET\[b\]); the result is: $\_GET\[a\] will be replaced with the string “system” and $\_GET\[b\] will be replaced with the string “ls” and Ill able to bypass all filters!
![](https://miro.medium.com/proxy/1*NcvPl-CRHy2Cm5xUsbSFGw.jpeg)
Lets try with the first payload (sy.(st).em)(whoami);
![](https://miro.medium.com/proxy/1*DiaoAKPA5blRp3PCkCwf4w.png)
and the second payload ?a=system&b=cat+/etc&c=/passwd&code=$\_GET\[a\]($\_GET\[b\].$\_GET\[c\]);
![](https://miro.medium.com/proxy/1*8AiSFSkm98axKo_7YUJf9w.png)
In this case, is not useful, but you can even insert comments inside the function name and inside the arguments (this could be useful in order to bypass WAF Rule Set that blocks specific PHP function names). All following syntaxes are valid:
This PHP function returns a multidimensional array containing a list of all defined functions, both built-in (internal) and user-defined. The internal functions will be accessible via $arr\[“internal”\], and the user-defined ones using $arr\[“user”\]. For example:
![](https://miro.medium.com/proxy/1*WRxh720WAmWz-PdAEjUQ0Q.png)
This could be another way to reach the system function without using its name. If I grep for “system” I can discover its index number and use it as a string for my code execution:
![](https://miro.medium.com/proxy/1*GJpCkpPrYRtTfUNgd680hw.png)
obviously, this should work against our Cloudflare WAF and script filters:
![](https://miro.medium.com/proxy/1*eBOSkK_YZA5S5mLAlGwsmg.png)
Each string in PHP can be used as an array of characters (almost like Python does) and you can refer to a single string character with the syntax $string\[2\] or $string\[-3\]. This could be another way to elude rules that block PHP functions names. For example, with this string $a=”elmsty/ “; I can compose the syntax system(“ls /tmp”);
![](https://miro.medium.com/proxy/1*FhshSF88OXuviKoG1Sf-Gw.png)
If youre lucky you can find all the characters you need inside the script filename. With the same technique, you can pick all chars you need with something like
![](https://miro.medium.com/proxy/1*Pqo5eWcCrAzO_798EN-bpQ.png)
![](https://miro.medium.com/proxy/1*v_5x3PDduhRhkLjNZ7caCg.png)
Let me say that with the OWASP CRS3 all become harder. First, with the techniques seen before I can bypass only the first paranoia level, and this is amazing! Because Paranoia Level 1 is just a little subset of rules of what we can find in the CRS3, this level is designed to prevent any false positives. With a Paranoia Level 2 all things become hard because of the rule 942430 “Restricted SQL Character Anomaly Detection (args): # of special characters exceeded”. What I can do is just execute a single command without arguments like “ls”, “whoami”, etc.. but I cant execute something like system(“cat /etc/passwd”) as done with Cloudflare WAF:
![](https://miro.medium.com/proxy/1*eyUzRsmsvGABNyRoRiqcXQ.png)
![](https://miro.medium.com/proxy/1*9wRqE3kCK07cS0xId6T_xg.png)