thinkphp3.2.3反序列化利用链分析
前置知识:
- PHP反序列化原理
PHP反序列化就是在读取一段字符串然后将字符串反序列化成php对象。 - 在PHP反序列化的过程中会自动执行一些魔术方法
方法名 ---------------调用条件
__call 调用不可访问或不存在的方法时被调用
__callStatic 调用不可访问或不存在的静态方法时被调用
__clone 进行对象clone时被调用,用来调整对象的克隆行为
__constuct 构建对象的时被调用;
__debuginfo 当调用var_dump()打印对象时被调用(当你不想打印所有属性)适用于PHP5.6版本
__destruct 明确销毁对象或脚本结束时被调用;
__get 读取不可访问或不存在属性时被调用
__invoke 当以函数方式调用对象时被调用
__isset 对不可访问或不存在的属性调用isset()或empty()时被调用
__set 当给不可访问或不存在属性赋值时被调用
__set_state 当调用var_export()导出类时,此静态方法被调用。用__set_state的返回值做为var_export的返回值。
__sleep 当使用serialize时被调用,当你不需要保存大对象的所有数据时很有用
__toString 当一个类被转换成字符串时被调用
__unset 对不可访问或不存在的属性进行unset时被调用
__wakeup 当使用unserialize时被调用,可用于做些对象的初始化操作
- 反序列化的常见起点
__wakeup 一定会调用
__destruct 一定会调用
__toString 当一个对象被反序列化后又被当做字符串使用
4.反序列化的常见中间跳板:
__toString 当一个对象被当做字符串使用
__get 读取不可访问或不存在属性时被调用
__set 当给不可访问或不存在属性赋值时被调用
__isset 对不可访问或不存在的属性调用isset()或empty()时被调用
形如 $this->$func();
5.反序列化的常见终点:
__call 调用不可访问或不存在的方法时被调用
call_user_func 一般php代码执行都会选择这里
call_user_func_array 一般php代码执行都会选择这里
6.Phar反序列化原理以及特征
phar://伪协议会在多个函数中反序列化其metadata部分
受影响的函数包括不限于如下:
copy,file_exists,file_get_contents,file_put_contents,file,fileatime,filectime,filegroup,
fileinode,filemtime,fileowner,fileperms,
fopen,is_dir,is_executable,is_file,is_link,is_readable,is_writable,
is_writeable,parse_ini_file,readfile,stat,unlink,exif_thumbnailexif_imagetype,
imageloadfontimagecreatefrom,hash_hmac_filehash_filehash_update_filemd5_filesha1_file,
get_meta_tagsget_headers,getimagesizegetimagesizefromstring,extractTo
环境:
搭建
先到thinkphp官网去下载thinkphp_v3.2.3完整版源码(https://www.thinkphp.cn/Down),然后解压到phpstudy网站根目录下。
利用条件
具有反序列化入口
入口
先写一个反序列化入口,在控制器写入:
//Application/Home/Controller/HelloController.class.php
<?php
namespace Home\Controller;
use Think\Controller;
class HelloController extends Controller
{
public function index(){
echo base64_decode($_GET['Ufgnix']);
unserialize(base64_decode($_GET['Ufgnix']));
}
}
分析过程
由上面的前置知识知道,反序列化头一般在__destruct方法,因此全局搜索__destruct()
一个个查看,以可控变量尽量多的原则进行筛选,最终找到:ThinkPHP/Library/Think/Image/Driver/Imagick.class.php
文件中,具有可控变量的析构函数方法:
分析:
如果我们对 img
属性赋一个对象,那么它会调用 destroy()
方法,因此继续往下走,我们全局搜索具有 destroy()
方法的类
注意:
在PHP7版本中,如果无参调用一个含参方法,ThinkPHP会报错,而在PHP5版本中不会报错
我们全局搜索destroy()
方法的类,找到的的结果如下:ThinkPHP/Library/Think/Session/Driver/Memcache.class.php
<?php
namespace Think\Session\Driver;
class Memcache {
protected $lifeTime = 3600;
protected $sessionName = '';
protected $handle = null;
public function destroy($sessID) {
return $this->handle->delete($this->sessionName.$sessID);