In this blog, we will be discussing the new functions we got to bypass PHP disable_functions and also the other tricks to do the same.
I (@TarunkantG) and one of my teammate (@__c3rb3ru5__ ) made lazyFuzzer
to fuzz the all PHP functions to check if they call execve
system call internally. In this blog mainly we will be discussing the difficulties we faced to make the Fuzzer and how we certainly solved those issues to get more new functions.
We also made a tool on the top of the findings this fuzzer did, here,
Announcing dfunc-bypasser for letting you know how strong your disable_function is and how you can bypass that. You can get the more details on the same while reading this blog.
Note: The functions we got are not in the default php installation, instead the php modules which get installed sometimes during normal installation.
So let’s dive into details:
How to Bypass PHP disable_functions
There are 3 ways(known to us) to bypass disable_functions:
Using
LD_PRELOAD
: You use the PHP function which callsexecve
syscall internally, and usingLD_PRELOAD
you overwrite the definition and get the shell. You can get the detailed writeup to do the same here. The known functions to do the same aremail
anderror_log
. Or you can usephp-imagick
library to change the file type, which sometimes callexecve
internally, overwrite any definition from them to get the shell, for this you can get the detailed writeup here.Using
PHP-FPM
: If thePHP-FPM
service is running in the server, you can use that to get the shell, you can use Gopherus to generate the payload ofFastCGI
then urldecode it and write that payload to the sock file or the port ofphp-fpm
usingfsockopen
andfwrite
. You can get the detailed writeup of the same here.Or use any N-Day PHP exploit, which is not fixed in the given version in order to get the shell.
How the idea came
While playing the a lot of CTFs, I have seen that, these time a lot of CTF challenges needed to bypass the disable_functions whereas the well-known function for doing the same are only two(mail
and error_log
). So that gave me the idea to fuzz all the php functions and check if they call execve
internally.
How we started
First, I installed all the php-modules on the server and thought of fuzzing the functions from it’s minimum arguments to max arguments with the flag range of (-10,10), so for this we needed to know which functions takes how many arguments to run and if the argument type is string then which string should go, if it is file then which file and so on we need to figure out for all argument type. So now I have following task to complete:
Getting the no. and type of arguments of the php functions
First thing was to find out the, what number of argument the function needs? so I used the error messages of the functions which says, at least
, at most
, exactly
the number of argument should be used.
Note: For this I could have also used ReflectionFunction class to find out the max and the least numbers of arguments needed.
Now, we needed to check, what type of input the function takes? that also we solved using error ;). But the problem here is, you can’t get the types of arguments all in the once. You have to set the arguments such that the php can check the next argument.
Note: For this you can’t use ReflectionFunction
class because, this class mainly works for user defined functions not for php pre-defined(internal) functions.
As this will be too much of the task to do, I went to find a interesting string which can satisfy all types.
Making of Input
This was trivial task to do.
As the 1st step gave us the type of arguments to be send to the function. The types can be one of these: int
,string
,file
,resource
,boolean
,float
,Array
,Object
,NULL
. So if you start fuzzing a function having argument type of int, string, file then your fuzzer will run for 3!
times(As described earlier).
Now the task to find the string which satisfy almost all of these argument types. So I came with interesting string
1 | '1/../../../../../../../etc/passwd' |
This String can be used as string
,int
,file
and bool
For the flag
argument, we will be using integers from the range of (-10,10).
For the Object
type argument, most of the time functions don’t take the input as Object.Null
is satisfied, because we fuzzed from min to max arguments.Array
we didn’t do because it’s not too common.
So now we have string which almost contains all of the types but not Resource
.
Why we couldn’t do fuzzing on resource type parameter
There are two best answer for this:
- The main problem on fuzzing resource type argument was, How we will get to know that what and whose resource does the argument need? Let’s say one example,
socket_connect
, this function need a resource argument, now how will you know that, which resource does this function need without checking the PHP manual of that ;).
Btw if anyone know how to find out using cli then please give me a ping. - And the second answer is itself the name,
lazyFuzzer
.
Result of Fuzzing
I got 4 new functions which can bypass PHP disable_functions using LD_PRELOAD
. All these functions are in different different modules of PHP.
mb_send_mail
: If your system hasphp-mbstring
module installed then this function can be used to bypass php disable_functions.imap_mail
: If your system hasphp-imap
module installed then this function also can be used to bypass the php disable_functions.libvirt_connect
: If your system hasphp-libvirt-php
module installed then this function also can be used to bypass disable_functions.gnupg_init
: If your system hasphp-gnupg
module installed then this function also can be used to bypass disable_functions.
You can get the file which has been used for this testing, here, lazyFuzzer.py.
dfunc-bypasser tool
This tool is to test how much strong your disable_functions is. The tool takes your input and tells you that, which function could possibly bypass the given disable_functions.
You can install this tool from here.