TSRC challenge: getshell defense ideas in PHP scenarios
1. Background
WEB application vulnerabilities often cause intrusions. scanners and WAF cannot solve all the problems, so they try to provide a defense solution for the PHP environment on the host side. It is a great honor to invite some white hats in TSRC for a confrontation drill. This article mainly shares their defense ideas.
The defense solution mainly aims to solve problems such as getshell and host sensitive file leakage. The following is a question: deploy the Nginx + php web environment of the Defense solution and provide an upload portal for uploading arbitrary files. Finding a flag file in the WEB directory to read the content is a breakthrough.
2 PHP Extension
The defense scheme uses PHP extensions to complete blocking. The PHP kernel supports C/C ++ to develop some extension functions, and provides a framework-ext_skel to help generate basic code for simplified development. Because PHP extension does not involve underlying resource management, therefore, compiling a PHP extension is the same as compiling a C application. Shows the structural hierarchy of PHP extensions. extensions are located between the PHP kernel ZEND and the PHP application layer code. You can use PHP extensions:
1) monitor the execution details of PHP application-layer code, including the execution of CGI, function names, parameters, and so on;
2) Call the API interfaces provided by the PHP kernel ZEND, including the disabling class and modifying configuration options.
Figure 1 Structure of PHP
3. Related Knowledge
3.1 HOOKPHP code
PHP is an interpreted language. The code is translated into an intermediate bytecode and parsed and executed by the ZEND engine. PHP calls the intermediate bytecode OPCODE. Each OPCODE corresponds to a processing function at the bottom layer of ZEND. The ZEND engine finally executes this processing function. To implement the HOOK function, you only need to change the handler corresponding to the hook opcode. ZEND provides a ready-made interface: zend_set_user_opcode_handler. The defense scheme only needs to HOOK the following three Opcodes:
ZEND_INCLUDE_OR_EVAL-eval, require, etc.
ZEND_DO_FCALL-function Execution system
ZEND_DO_FCALL_BY_NAME-Variable Function execution $ func = "system"; $ func ();
Example:
The OPCODE of ZEND_DO_FCALL corresponds to function call. If you need to HOOK all function calls:
1) Use zend_set_user_opcode_handler in the module initialization function to change ZEND_DO_FCALL to mysub:
PHP_MINIT_FUNCTION(phpips){ zend_set_user_opcode_handler(ZEND_DO_FCALL, mysub); return SUCCESS;}
2) implement the functions required by the User-Defined Function and return the original processing function:
Void mysub (){
Custom functions;
Return ZEND_USER_OPCODE_DISPATCH;
}
3.2 ZEND Interface
You also need to obtain some basic information or functions, such:
1) obtain the name of the executed PHP script. You can call zend_get_executed_filename of ZEND:
Char * cgi_name = (char *) zend_get_executed_filename (TSRMLS_C );
2) Disable some class libraries and use the zend_disable_class interface;
ZEND provides many interfaces that can be called as needed.
3.3 Data Structure
PHP is a weak type language, its upper layer does not distinguish the variable type, the underlying variable corresponds to a union struct, take the php-5.3.6 version for example, struct in Zend/zend. the content in the H file is as follows:
typedef union _zvalue_value { long lval; /* longvalue */ double dval; /* double value */ struct { char *val; int len; } str; HashTable *ht; /* hash table value*/ zend_object_value obj;} zvalue_value;
PHP separates the variable types at the underlying layer. In the union struct, there is a very important struct HashTable. in PHP, the array structure is implemented using the HashTable struct. If the variable is an array, to retrieve the variable content, you need to traverse this HashTable. The data structure is not described too much. ZEND uses the zval struct to store variables at the underlying layer. ZEND also provides several macros to easily convert zval to specific data types, such as converting zval to string-zval el; z_STRVAL_P (el), commonly used:
Z_LVAL_P, Z_DVAL_P, Z_ARRVAL_P, etc. The above macro list is defined in Zend/zend_operators.h.
4. Rule policies
4.1 Basic Ideas
The problem we need to solve is getshell, host sensitive file leakage, and so on. If you restrict the PHP script to execute commands and read files, the goal is achieved. At the same time, because there are many interfaces for reading files and there are many application scenarios, you can disable the Open Directory Interface to prohibit reading files on the side. You cannot retrieve the file name without traversing the directory, can effectively achieve the goal. Therefore, the final strategy is as follows:
1) disable the interface for executing commands
2) disable the directory opening Interface
You need to pay attention to the following issues when disabling a function:
1) PHP interfaces are still complicated. Apart from common functions such as system, exec, opendir, and scandir, Some uncommon functions such as glob should be fully considered, there are also some callback functions and reflection classes (PS: Some considerations are not completely bypassed by blackeye and snowman)
2) some class libraries provided by php spl have file management functions and need to be disabled, such as DirectoryIterator (but it seems that no SPL has been used by white hats)
4.2 against Deformation
PHP uses assert or preg_replace/e to execute code. The PHP Script Name obtained by calling zend_get_executed_filename has a identification ID. assert corresponds to assert code and preg_replace corresponds to regexp code; when these special scripts are found to execute high-risk functions such as system 4.1, they are directly blocked. Take nonalphanumeric-webshell as an example:
The parsed form of the deformed webshell is similar to that of $ _ GET [1] ($ _ GET [2]). For example, you can input 1 = assert & 2 = system (whoami) to execute the code, the PHP extension layer monitors the execution of the system function and finds that the PHP script name carries the regexp code identifier. It is clear that the preg_replace code calls the system and blocks the system. The same is true for the Assert function. Conclusion: expansion does not focus on coding or encryption on the static layer. Expansion only monitors the final behavior, so it can solve the current deformation problem well.
Figure 2 nonalphanumeric-webshell
4.3 Reduce false positives
Sometimes a normal PHP script also needs the command execution function. How can we ensure that it runs normally without being blocked by our defense policy? Three ideas are provided here:
1) The write permission and the command execution permission are mutually exclusive.
Considering that most of the files obtained by intruders using the upload vulnerability or other 0DAY getshell have W write permissions, the defender often wants to prevent these files from having excessive permissions.
Therefore, we can remove the write permission of normal PHP scripts, and then only implement command execution and other blocking logic of defense policies for PHP scripts with write permission. This will not affect the use of the business, but also achieve the protection goal of the preset scenario. However, you need to disable functions such as chmod that can modify file permissions.
2) use the whitelist Logic
You can use a whitelist of file names, that is, files reported by the business are not blocked, and other unknown files are prohibited. You can use a whitelist of function parameters elegantly. For example, you can extract the parameters or code features of commands executed by normal PHP scripts to allow them to pass through. All features that you do not know are blocked.
3) use the blacklist Logic
Set the black feature parameters of known malicious scripts, similar to the pattern concept of anti-virus software in the early days.
The above ideas need to be fully cooperated with the business during enterprise promotion, and there are still imperfections. If you have more solutions or ideas, please discuss them with me.
5. Future
PHP extension can be used for many tasks, such as vulnerability detection, database function parameter filtering, blocking SQL injection, and blocking stored XSS. Even in code auditing, we can consider that there is already a mature open-source product in China, TAINT (Author: laruence), and everyone may be familiar with it, I will not repeat it for the moment.
The text is too hasty. If you have any shortcomings, please forgive me. If you have any questions or suggestions, please contact pandas for discussion.