风炫安全Web安全学习第三十九节课 反序列化漏洞基础知识

风炫安全Web安全学习第三十九节课 反序列化漏洞基础知识

反序列化漏洞

0x01 序列化相关基础知识

0x01 01 序列化演示

序列化就是把本来不能直接存储的数据转换成可存储的数据,并且不会丢掉数据格式

序列化(Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。 在序列化期间,对象将其当前状态写入到临时或持久性存储区。 以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。 序列化使其他代码可以查看或修改,那些不序列化便无法访问的对象实例数据。

<?php
class test{
    
    
	private $flag = 'Inactice';
	protected $test = 'test';
	public $test1 = "test1";

	public function set_flag($flag){
    
    
		$this->flag = $flag;
	}	

	public function get_flag($flag){
    
    
		return $this->flag;
	}

}

$object = new test();
$object->set_flag('Active');
$data = serialize($object);
echo $data;
?>

那么这种将原本的数据通过某种手段进行“压缩”,并且按照一定的格式存储的过程就可以称之为"序列化"

O:4:"test":3:{s:10:"testflag";s:6:"Active";s:7:"*test";s:4:"test";s:5:"test1";s:5:"test1";}
对象类型:长度:"类名":类中变量的个数:{类型:长度:"值";类型:长度:"值";......}
此处输入图片的描述
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

0x01 02 php魔法方法

PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法

这里就不得不介绍几个我们必须知道的魔法方法了

__construct   当一个对象创建时被调用,
__destruct   当一个对象销毁时被调用,
__toString   当一个对象被当作一个字符串被调用。
__wakeup()   使用unserialize时触发
__sleep()    使用serialize时触发
__call()    在对象上下文中调用不可访问的方法时触发
__callStatic()    在静态上下文中调用不可访问的方法时触发
__get()    用于从不可访问的属性读取数据
__set()    用于将数据写入不可访问的属性
__isset()    在不可访问的属性上调用isset()empty()触发
__unset()     在不可访问的属性上使用unset()时触发
__invoke()   当脚本尝试将对象调用为函数时触发

其中我想特别说明一下第四点:

这个 __toString 触发的条件比较多,也因为这个原因容易被忽略,常见的触发条件有下面几种

(1)echo ($obj) / print($obj) 打印时会触发

(2)反序列化对象与字符串连接时

(3)反序列化对象参与格式化字符串时

扫描二维码关注公众号,回复: 12728659 查看本文章

(4)反序列化对象与字符串进行比较时(PHP进行比较的时候会转换参数类型)

(5)反序列化对象参与格式化SQL语句,绑定参数时

(6)反序列化对象在经过php字符串函数,如 strlen()、addslashes()时

(7)在in_array()方法中,第一个参数是反序列化对象,第二个参数的数组中有toString返回的字符串的时候toString会被调用

<?php
class test{
    
    
 public $varr1="abc";
 public $varr2="123";
 public function echoP(){
    
    
  echo $this->varr1."<br>";
 }

 public function __construct(){
    
    
  echo "__construct<br>";
 }

 public function __destruct(){
    
    
  echo "__destruct<br>";
 }

 public function __toString(){
    
    
  return "__toString<br>";
 }

 public function __sleep(){
    
    
  echo "__sleep<br>";
  return array('varr1','varr2');
 }

 public function __wakeup(){
    
    
  echo "__wakeup<br>";
 }
 
}

$obj = new test();  //实例化对象,调用__construct()方法,输出__construct
// $obj->echoP();   //调用echoP()方法,输出"abc"
// echo $obj;    //obj对象被当做字符串输出,调用__toString()方法,输出__toString
$s =serialize($obj);  //obj对象被序列化,调用__sleep()方法,输出__sleep
echo unserialize($s);  //$s首先会被反序列化,会调用__wake()方法,被反序列化出来的对象又被当做字符串,就会调用_toString()方法。
// 脚本结束又会调用__destruct()方法,输出__destruct
?>

参考:
http://blog.evalshell.com/2020/12/26/风炫安全web安全学习第三十九节课-反序列化漏洞基/

猜你喜欢

转载自blog.csdn.net/hyj123480/article/details/112253198