Preface
Serialization gives us a simple way to pass objects: Serialize () converts an object into a string, unserialize () restores a string to an object. The use of such functions is harmless, but there is a vulnerability when the string user passing in the deserialization function is under control -- PHP object injection
POP chain
The key of serialization is to find a controllable pop chain in the target code. The pop chain is that class a calls the method of class B, and class B calls other methods, in which the parameters of deserialization can be controlled. Class A contains magic methods that use unsafe functions, which is a pop chain
Serialization of different data types
- Can be used to deserialize PHP variables that have been serialized
Can be used to deserialize PHP variables that have been serialized
- Support for multiple types of PHP variables
Support for multiple types of PHP variables
Can be used to deserialize PHP variables that have been serialized
Support for multiple types of PHP variables
- integers / floats / boolean
integers / floats / boolean
- strings / array / objects
strings / array / objects
- Wait...
Wait...
integers / floats / boolean
strings / array / objects
Wait...
Boolean
Int
Object
NULL
String
Array
POP chain demo
Poc.php:
The above is a constructed pop chain. When the object instantiated by this class is serialized and then deserialized, the write file operation will be triggered
POC.php
After running the code, the pop_serialized.txt file is generated in the current directory, and the serialized string of the popdemo object is stored in the file memory
pop_serialized.txt
pop_serialized.txt
pop_unserialize.php
After running the pop_unserialize.php file, a demo file will be generated in the current directory with the content of demo
When we can control the serialized string, there will be a vulnerability of arbitrary file write operation in this place
POP demo2
Serialization vulnerability exploitation methods do not appear directly in magic methods. If the key code is not in magic methods, but in the ordinary methods of a class, it is necessary to find the same function name to associate the properties of a class with those of a sensitive function
Blbana.php
Under normal circumstances, blbana will instantiate an object of normal class in the constructor, call the action method of the object in the destructor, and finally print the Hello string. There is no sensitive operation
normal
action
normal
action
Exp.php
Run exp.php to generate a payload. The content is:
Try to attack, pass payload through get request to get request parameter D of blbana.php
GET请求参数d里去
GET请求参数d里去
Successfully called action method in evil like
evil
evil
Sensitive operations don't have to be in magic methods. After finding magic methods, if there are sensitive operations, you can analyze whether the parameters are controllable. If there are common methods with sensitive operations, you can analyze whether there are magic methods with the same name called, hijack the running process of the code, and trigger the vulnerability code
Vulnerability code
Exploit conditions
- There is a PHP magic method in the program, such as "wake up" or "destroy". We need to use this method to attack;
There is a PHP magic method in the program, such as "wake up" or "destroy". We need to use this method to attack;
- Unserialize() function with PHP deserialization in the program
Unserialize() function with PHP deserialization in the program
unserialize()
- The unserialize() parameter is controllable and can control the serialization string in the incoming function
The unserialize() parameter is controllable and can control the serialization string in the incoming function
unserialize()
There is a PHP magic method in the program, such as "wake up" or "destroy". We need to use this method to attack;
Unserialize() function with PHP deserialization in the program
unserialize()
unserialize()
unserialize()
unserialize()
At this time, our code already has the above conditions, and we can inject PHP objects.
Exp content
O:3:"foo":2:{s:4:"file";s:9:"shell.php";s:4:"data";s:4:"webshell";}
O:3:"foo":2:{s:4:"file";s:9:"shell.php";s:4:"data";s:4:"webshell";}
O:3:"foo":2:{s:4:"file";s:9:"shell.php";s:4:"data";s:4:"webshell";}
When we execute exp successfully, we will generate a file named shell.php in the same directory, and the content of the file is webshell
Loophole utilization
We first upload the exp.txt to the server through upload and other methods. We can see it through the code. Finally, the program will read the contents of the file through the file get contents() function. When the program is finished, the code execution is triggered by the "destroy" method.
A shell.php is generated in the same level directory, and the content is AAAA
Vulnerability analysis
When this vulnerability occurs, we can use it to write a shell to the target server:
Through this exp, we write a sentence in shell.php.
It should be noted that in the string, the number in front represents the number of characters in the following string. If the number does not match the number of characters, an error will be reported and the initial content "text" will be written to shell.php. I tested this error in different versions of PHP.
When testing in the above two versions, if our serialized string does not meet the requirements, an error will be thrown and the initial value will be written to shell.php.
However, in this version of PHP, no error is reported, but the initial value is still written in shell.php. Therefore, we need to pay attention to the above content when making use of it to prevent the failure of loophole recurrence
In some programs, the value of member variable will be assigned by calling \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
Now let's analyze some details of the vulnerability. This is because we passed the parameter to session filename through get, which caused the subsequent function file get contents to read the string in exp.txt, and then the string was deserialized to the object of foo, which led to code execution.
The object generated after being inverted is equivalent to that we use new foo() to become an object:
So that the malicious content we passed in overwrites the original object initial value
The specific serialized string is shown above.
We have successfully modified the values of the variables $file and $data. At this time, we need to execute the magic method "destruct(), which has the following centralized methods:
1. After the normal execution of the program, all objects are destroyed, and the destructor is called (this is the method here)
2. When the object does not point to it, it is destroyed
The destructor executes
3. Use unset variable to destroy the variable pointing to the object. Note that unset destroys the variable pointing to the object, not the object. The destructor will only execute when all variables pointing to the same object are destroyed. That is, when the object is destroyed, the destructor is called.
Deserialization vulnerability mining
The main purpose of deserialization vulnerability mining is to find the pop components that can be utilized in the code. The specific ideas are as follows:
- Using the text search tool, search in the target code, such magic methods as * * wakeup and * * destruct * *
Using the text search tool, search in the target code, such magic methods as * * wakeup and * * destruct * *
- Trace the method, see if there are some places available in magic method, and find the pop components available
Trace the method, see if there are some places available in magic method, and find the pop components available
- Build the serialization string POC according to the structure definition of the class
Build the serialization string POC according to the structure definition of the class
Using the text search tool, search in the target code, such magic methods as * * wakeup and * * destruct * *
Trace the method, see if there are some places available in magic method, and find the pop components available
Build the serialization string POC according to the structure definition of the class
Bug repair
- Filter the strings passed in the unserialize() function to prevent object injection
Filter the strings passed in the unserialize() function to prevent object injection
unserialize()
- Avoid using sensitive operations in magic methods
Avoid using sensitive operations in magic methods
- Avoid the common method and the magic method in sensitive operation and call the same name in the magic method, thus the attacker hijacked the code process, causing harm.
Avoid the common method and the magic method in sensitive operation and call the same name in the magic method, thus the attacker hijacked the code process, causing harm.
Filter the strings passed in the unserialize() function to prevent object injection
unserialize()
unserialize()
Avoid using sensitive operations in magic methods
Avoid the common method and the magic method in sensitive operation and call the same name in the magic method, thus the attacker hijacked the code process, causing harm.