未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,一个反序列化漏洞造成要有魔术方法,恰好魔术方法里面有危险函数,比如危险函数文件读取,命令执行,反序列化在数据传递,可能触发危险函数
1、什么是反序列化操作?-格式转换
2、为什么会出现安全漏洞?-魔术方法
3、反序列化漏洞如何发现? -对象逻辑
4、反序列化漏洞如何利用?-POP链构造
补充:反序列化利用大概分类三类
魔术方法的调用逻辑-如触发条件
语言原生类的调用逻辑-如SoapClient
语言自身的安全缺陷-如CVE-2016-7124
序列化:对象转换为数组或字符串等格式
反序列化:将数组或字符串等格式转换成对象
serialize()//将一个对象转换成一个字符串
unserialize()//将字符串还原成一个对象
方便记忆以后记忆 反序列化就是加un的
反序列化一般是在白盒里面,就是代码给到你的情况下分析,在黑盒里面发现几乎不可能的
class info{
public $name='qian';
public $age=18;
}
O:4:"info":2:(s:4:"name";s:4:"qian";s:3:"age";i:2:18;}
object 长度 info 2个变量 string类型 长度 name
class info{
public $name;
public 19;
}
触发:unserialize函数的变量可控,文件中存在可利用的类,类中有魔术方法:
__construct(): //构造函数,当对象new的时候会自动调用
__destruct()://析构函数当对象被销毁时会被自动调用
__wakeup(): //unserialize()时会被自动调用
__invoke(): //当尝试以调用函数的方法调用一个对象时,会被自动调用
__call(): //在对象上下文中调用不可访问的方法时触发
__callStatci(): //在静态上下文中调用不可访问的方法时触发
__get(): //用于从不可访问的属性读取数据
__set(): //用于将数据写入不可访问的属性
__isset(): //在不可访问的属性上调用isset()或empty()触发
__unset(): //在不可访问的属性上使用unset()时触发
__toString(): //把类当作字符串使用时触发
__sleep(): //serialize()函数会检查类中是否存在一个魔术方法__sleep() 如果存在,该方法会被优先调用
对象变量属性:
public(公共的):在本类内部、外部类、子类都可以访问
protect(受保护的):只有本类或子类或父类中可以访问
private(私人的):只有本类内部可以使用
序列化数据显示:
private属性序列化的时候格式是 *%00类名%00成员名* 在原本上加2
protect属性序列化的时候格式是 *%00*%00成员名* 在原本上加3
为了区分公有私有保护 ,让人很容易看出来是什么类型的
header("Content-type: text/html; charset=utf-8");
//public private protected说明
class test{
public $name="xiaodi";
private $age="29"; //两个%00,在原本上加2 就是9个
protected $sex="man"; //两个%00一个*, 在原本上加3 就是6个
}
$a=new test();
$a=serialize($a);
print_r($a);
?>
class A{
public $var='echo test';
public function test(){
echo $this->var;
}
public function __destruct(){
//对象被销毁会被调用, 疑问?没有看见销毁代码啊.其实程序执行结束都会自动销毁
echo '__destruct'.'
';
}
public function __construct(){
//当对象new的时候会调用
echo '__construct'.'
';
}
public function __toString(){
return '__toString'.'
';
}
}
$a=new A();
?>
//无需函数,创建对象触发魔术方法
访问结果
class A{
public $var='echo test';
public function test(){
echo $this->var;
}
public function __destruct(){
//对象被销毁会被调用
echo '__destruct'.'
';
}
public function __construct(){
//当对象new的时候会调用
echo '__construct'.'
';
}
public function __toString(){
return '__toString'.'
';
}
}
$a=new A();
echo serialize($a).''; //输入反序列化结果
?>
class A{
public $var='echo test';
public function test(){
echo $this->var;
}
public function __destruct(){
//对象被销毁会被调用
echo '__destruct'.'
';
}
public function __construct(){
//当对象new的时候会调用
echo '__construct'.'
';
}
public function __toString(){
return '__toString'.'
';
}
}
$t=unserialize($_GET['x']);
?>
//触发__destruct
http://127.0.0.1/demo.php?x=O:1:“A”:1:{
s:3:“var”;s:9:“echo test”;}
相当于传递public $var=‘echo test’;
虽然没有new对象,但是传递了数据,只要传递数据,程序就会执行,执行就有销毁,触发__destruct()函数
class A{
public $var='echo test';
public function test(){
echo $this->var;
echo '';
}
public function __destruct(){
echo '__destruct'.'
';
}
public function __construct(){
echo '__construct'.'
';
}
public function __toString(){
return '__toString'.'
';
}
}
$a=new A();
$a->test(); //触发test 前提是new了一个对象,才可以指向test方法
?>
class A{
public $var='echo test';
public function test(){
echo $this->var;
echo '';
}
public function __destruct(){
echo '__destruct'.'
';
}
public function __construct(){
echo '__construct'.'
';
}
public function __toString(){
return '__toString'.'
';
}
}
$a=new A();
echo $a;//触发__toString __toString触发条件:把类当作字符串使用时触发 echo输出的都是字符串
?>
class B{
public function __destruct(){
system('ipconfig');
}
public function __construct(){
echo 'qian'.'
';
}
}
$b=new b(); //执行__destruct和__construct
echo serialize($b); //输出O:1:"B":0:{}
?>
class B{
public function __destruct(){
system('ipconfig');
}
public function __construct(){
echo 'qian'.'
';
}
}
//$b=new b(); //执行__destruct和__construct
//echo serialize($b); //输出O:1:"B":0:{}
unserialize($_GET[x]); //传递O:1:"B":0:{} 执行ipconfig
?>
class C{
public $cmd='ipconfig';
public function __destruct(){
system($this->cmd);
}
public function __construct(){
echo 'qian'.'
';
}
}
//函数引用,无对象创建触发魔术方法自定义变量
unserialize($_GET[c]); //?c=O:1:"C":1:{s:3:"cmd";s:3:"ver";} 修改$cmd的参数,让其执行其它命令,这也是反序列化的核心点
?>
header("Content-type: text/html; charset=utf-8");
//__construct __destruct 魔术方法 创建调用__construct 2种销毁调用__destruct
class Test{
public $name;
public $age;
public $string;
// __construct:实例化对象时被调用.其作用是拿来初始化一些值。
public function __construct($name, $age, $string){
echo "__construct 初始化"."
"