table of Contents
Array deserialization instance
Examples of objects deserialized
Serialized string format analysis
The difference between public, private, and protected after serialization
Principle of deserialization vulnerability
What is php serialization?
The two functions used
serialize() //函数用于序列化对象或数组,并返回一个字符串。
unserialize() //函数用于将通过 serialize() 函数序列化后的对象或数组进行反序列化,并返回原始的对象结构。
serialize() instance
Array serialization instance
After serializing a set of arrays, get a string of strings
<?php
highlight_file(__FILE__);
$a = array('a' => 'Apple' ,'b' => 'banana' , 'c' => 'Coconut');
$s = serialize($a);
echo $s;
//a:3:{s:1:"a";s:5:"Apple";s:1:"b";s:6:"banana";s:1:"c";s:7:"Coconut";}
?>
Object serialization instance
After serializing an object, get a string of strings
<?php
highlight_file(__FILE__);
class test_class{ //创建类
var $test = '123'; //在类中新建一个test变量
}
$class1 = new test_class; //创建对象
$class_str = serialize($class1);//序列化对象
echo $class_str;//输出序列化后的字符串
//O:10:"test_class":1:{s:4:"test";s:3:"123";}
?>
unserialize() instance
Array deserialization instance
Deserialize a serialized string in a standard format, and you will get the following array
<?php
highlight_file(__FILE__);
$str = 'a:3:{s:1:"a";s:5:"Apple";s:1:"b";s:6:"banana";s:1:"c";s:7:"Coconut";} ';
$un_str=unserialize($str);
var_dump($un_str);
?>
Object deserialization instance
Deserialize a serialized string in a standard format to obtain a new object
<?php
highlight_file(__FILE__);
$str = 'O:10:"test_class":1:{s:4:"test";s:3:"123";}';
$un_str=unserialize($str);
var_dump($un_str);
?>
Serialized string format analysis
O:10:"test_class":1:{s:4:"test";s:3:"123";}
Object type: class name length : class name: number of variables in the class : {variable: variable name length: variable name; variable type : variable content length : variable content }
a:3:{s:1:"a";s:5:"Apple";s:1:"b";s:6:"banana";s:1:"c";s:7:"Coconut";}
Array type: number of arrays : {variable: variable name length : variable name ; variable type : variable content length : variable content ;...}
- There are two types of serialization:
- Object type
- Array type
- It can be seen that in the braces, two semicolons (;) form a group, and the two semicolons represent the content of a variable.
- {s:4:"test";s:3:"123";}
Variable type
Different storage types will be converted into different letters after serialization
a - array b - boolean
d - double i - integer
o - common object r - reference
s - string C - custom object
O - class N - null
R - pointer reference U - unicode string
The difference between public, private, and protected after serialization
- Public (public): can be accessed within this class, external classes, and subclasses
- Private (private): only available inside this class
- Protected (protected): only this class or subclass or parent can access
After serializing according to the above 3 modifiers, the following results are obtained:
O:10:"test_class":3:{
s:6:"test_1";s:3:"str";
s:18:"test_classtest_3";i:123;
s:9:"*test_2";i:123;
}
- public: basically no change after serialization
- private: After serialization, the name of the class will be added to the variable name, and the length of the variable name will also increase
- protected: After serialization, there will be an extra * before the variable name, but why does the length of the variable name become 9 bytes?
- In fact, when the protected attribute is serialized, the format is %00*%00 member name
Magic method
When using PHP deserialization, it is often necessary to use the magic method in deserialization to check whether there are sensitive operations in the method.
PHP reserves all class methods starting with __ (two underscores) as magic methods.
Common magic methods
__construct()//创建对象时触发
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__invoke() //当脚本尝试将对象调用为函数时触发
__sleep() //此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。
__wakeup() //经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。
php magic method official document
Method call example
__sleep()
The serialize() function checks whether there is a magic method __sleep() in the class. If it exists, the method will be called first before the serialization operation is performed. This function can be used to clean up the object and return an array containing the names of all variables in the object that should be serialized. If the method does not return anything, NULL is serialized and an E_NOTICE level error is generated.
__wakeup()
unserialize() will check if there is a __wakeup() method. If it exists, the __wakeup method will be called first to prepare the resources needed by the object in advance.
__toString()
The __toString() method is used to respond when a class is treated as a string. For example echo $obj; what should be displayed. This method must return a string, otherwise a fatal error of E_RECOVERABLE_ERROR level will be issued.
Principle of deserialization vulnerability
When the parameters of deserialization unserialize() are controllable, we can construct a serialized string to modify the internal variables and even functions of the object.
Case:
<?php
error_reporting(0);
show_source(__FILE__);
class c{
public $str = 111;
function __wakeup(){
echo $this->str;
}
}
$str = $_GET['str'];
if (isset($str)){
unserialize($str);
}
?>
When we can control deserialization, we will be able to modify the contents of variables in the class
poc
?str=O:1:"c":1:{s:3:"str";s:3:"123";}
Of course it’s not that simple, just modify the content of the value, we can also type xss
poc
?str=O:1:"c":1:{s:3:"str";s:24:"<script>alert()</script>";}
Of course, this is just a simple case, I will explain the advanced knowledge of php deserialization next time.