本文首發於:https://mp.weixin.qq.com/s?__biz=MjM5MTYxNjQxOA==&mid=2652850238&idx=1&sn=6f22d8ab7af687993330a2a1774a5579&chksm=bd5934f38a2ebde507c7964e5a0dcd4775dec3f62162a462d95814132a8cf546a9df1daa51e5&scene=0&xtrack=1#rd
某應用使用了版本爲6.0.2的guzzlehttp/guzzle代碼庫,而且在其代碼段中存在反序列化函數unserialize(),而且其入口參數爲咱們能夠控制的參數,那麼接下來咱們就須要在其內部尋找咱們能夠利用的類而且尋找能夠利用的反序列時將會觸發的__destruct()函數和__wakeup()函數,而後再在這兩類方法中找可能存在漏洞的點,咱們能夠在sublime中使用ctrl+shift+f鍵來在指定的文件夾下來查找咱們指定的函數,以下圖爲查找的效果php
咱們注意到vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php中存在__destruct()函數,而且咱們猜想filename屬於文件型參數,可能與文件操做相關,所以咱們即可以定位到FileCookieJar.php文件中進行審計html
函數體中存在save方法,所以咱們繼續跟進到save方法shell
咱們能夠看到save方法中存在file_put_contents()函數,咱們猜想是否是能夠在此進行寫shell,其中入口參數$filename爲類FileCookieJar的私有成員變量,是咱們能夠控制的,$json變量來自$cookie變量,而又由於$cookie變量調用的getExpires()函數和getDiscard()函數和toArray()函數均是在SetCookie這個類中進行定義的,因此$cookie變量確定是SetCookie類實例化後的對象,從而來調用類中的方法。而且此時咱們須要知足json
1.$cookie>getExpires() 返回Ture數組
2.$cookie>getDiscard() 返回Falsecookie
接下來咱們跟進到SetCookie.php中觀察類SetCookie是如何定義的,composer
其中在SetCookie類中的成員變量裏定義了私有靜態成員變量$defaults和私有成員變量$data,curl
、函數
而且在其構造方法中$defaults的值將被$data數組中的值進行替換,而且將替換的結果賦值給$data變量。工具
其中getExpires()函數和getDiscard()和toArray()函數的定義以下所示:
從上面三個函數的定義中能夠看到,上面兩個函數返回$data變量的兩個鍵值,下面的函數直接返回$data變量。那麼咱們可讓這上面兩個鍵值知足if條件,經過咱們實例化SetCookie類並傳給其一個$data數組便可在其構造方法中完成賦值操做。
到這裏,假設咱們已經進入第一個箭頭所指示的if條件語句中,那麼此時將把$cookie對象所調用的toArray()函數的返回值(也就是咱們上面所說的SetCookie類中所定義的$data變量的值)賦給$json變量,接下來就會將$json變量的值寫入變量$filename所對應的路徑中,到此pop鏈已經完成。
最後,咱們在本地測試咱們以上的思路以及構造的pop鏈是否正確,首先編輯composer.json文件並在其中包含咱們所測試的對應版本的代碼庫
接下來在composer的同級目錄中執行
1.curl -sS https://getcomposer.org/installer | php //安裝composer
2.php composer.phar install //依賴代碼庫的安裝
簡單說下composer,composer 是 PHP 的一個依賴管理工具。它容許咱們聲明項目所依賴的代碼庫,而且會在咱們的的項目中安裝所依賴的代碼庫。composer.json中定義的require鍵值表明的含義是咱們將要開發的應用,依賴於guzzlehttp的6.0.2版本,對於庫的自動加載信息,composer 生成了一個 vendor/autoload.php 文件,咱們能夠經過引入這個文件,從而實現開發中所須要的類的自動加載
接下來就能夠開始構造咱們的poc了,由於要用到上面說的類,因此咱們直接引入對應目錄下的autoload.php就能夠,這裏的兩條use語句只是使用了命名空間,具體的加載類交給咱們的autoload.php來完成,
接着咱們就能夠來構造咱們最終想要利用的file_put_contents()函數的文件路徑名和文件內容,首先進行分析
由於文件路徑名$filename參數是類FileCookieJar的私有成員變量,而且在其構造函數中將直接將入口參數賦值給了$filename,並在其析構函數中調用了$filename的值(也就是在反序列化時將會調用$filename的值),所以咱們經過實例化FileCookieJar的匿名對象,並將想要寫入的路徑名做爲其入口參數,就能夠完成對$filename的賦值。又由於save方法要用到$cookie變量的值,而且$cookie變量的值必須由類SetCookie的實例化後的對象來進行賦值操做,而FileCookieJar的父類是CookieJar,而且在其中存在setCookie()方法,其入口參數爲類SetCookie的實例化的對象,所以咱們成功地找到了爲$Cookie變量賦值的方法,就是經過類FileCookieJar的實例化對象來調用父類中所定義的setCookie()方法,並將其入口參數值設置爲類SetCookie的匿名實例化對象,從而實現$cookie變量的賦值。
接下來咱們就要構造$cookie變量的數據了,首先咱們須要瞭解setCookie方法,它的入口參數爲實例化的類SetCookie的匿名對象,其在函數中調用了validate函數對$cookie變量進行檢測,而且定義了設置二次設置$cookie時的判斷操做,這裏咱們構造poc時只須要調用一次setCookie()函數,因此不會進入foreach循環
也就是咱們的目標只有一個,那就是是必須使validate()函數返回True
而validate()函數要求咱們必須知足如下三個條件纔可以返回true:
1.$data[‘Name’]變量非空,而且不能爲數字,而且必須爲所規定的字符
2.$data[‘Value’]變量非空,而且不能爲數字
3.$data[‘Domain’]變量非空,而且不能爲數字
而且結合又由於$data[‘Expires’]不能爲null,所以咱們能夠肯定咱們必須須要設置的$data的鍵名爲以上四個,那麼接下來咱們就能夠繼續寫咱們的poc了,咱們在實例化類FileCookieJar時將咱們想要寫入shell的路徑名做爲入口參數傳遞進去,而後將php一句話寫到$data變量的Name,Value,Domain中的任何一個值中,接着經過讓類對象$tr1ple調用setCookie(),並將其入口參數設置爲類SetCookie的匿名實例化(其入口參數爲$data),就能夠完成對$cookie變量的賦值,由於$cookie值最終會被傳遞給$json變量並通過json_encode()函數編碼之後直接寫入到咱們指定的路徑中。
咱們的poc文件名爲poc.php,經過執行php poc.php將會生成exp文件,其中爲咱們序列化之後的exp數據
接下來咱們能夠反序列化exp中包含的數據來測試此exp可否執行成功
經過執行結果咱們能夠判斷出已經成功反序列數據並寫入shell了,說明咱們以前分析的思路和測試過程是正確的。