廠商phpwind昨日爆一高危漏洞如下:
披露狀態:
2016-02-14: 細節已通知廠商並且等待廠商處理中
2016-02-18: 廠商已經確認,細節僅向廠商公開
2016-02-21: 細節向第三方安全合作夥伴開放(綠盟科技、唐朝安全巡航、無聲信息)
2016-04-13: 細節向核心白帽子及相關領域專家公開
2016-04-23: 細節向普通白帽子公開
2016-05-03: 細節向實習白帽子公開
2016-05-18: 細節向公眾公開
簡要描述:
反序列化漏洞導致代碼執行。
GET型CSRF,直接插入帖子,管理員瀏覽後執行任意代碼。
效果類似: http://www.wooyun.org/bugs/wooyun-2014-064886
詳細說明:
這個洞其實很有意思,最可惜的地方就是其觸發位置在後臺,否則它將是一個絕無僅有的好洞。
0x01 後臺反序列化位置
首先縱覽整個phpwindv9,反序列化的位置很多,但基本都是從資料庫裡取出的,很難完全控制序列化字符串。最後,找到三處:
可惡的是,三處都在後臺的Task模塊下。Task模塊是『任務中心』功能,只有能進入後臺的用戶才可以訪問:
隨便打開一個, src/applications/task/admin/TaskConditionMemberController.php
beforeAction將會在實際執行Action之前執行。這裡$var = unserialize($this->getInput('var'));,從Input中獲取var參數的值,進行反序列化。這個Input可以來自get/post/cookie。我們只要在phpwind裡找到反序列化可以利用的點,就能在這裡觸發反序列化漏洞。
0x02 PwDelayRun類__destruct方法
全局搜一下關鍵詞__destruct,很快找到了PwDelayRun類:
可見__destruct方法,其中遍歷了_callback數組,用call_user_func_array執行任意函數。這裡如果_callback可控,那麼就可以直接執行assert+任意代碼了。原本是一個十分簡單的漏洞,但我們在TaskConditionMemberController::beforeAction::unserialize裡下斷點,執行var_dump(get_declared_classes());exit;,查看當前已經定義的類:
其中並沒有PwDelayRun類。看來在反序列化的時候,並沒有加載這個類,所以我即使構造了利用方法,也『造』不出PwDelayRun對象。那怎麼辦?
0x03 利用spl_autoload包含任意php文件
在Joomla那個反序列化漏洞( https://**.**.**.**/PENETRATION/joomla-unserialize-code-execute-vulnerability.html )裡,提到了一個方法。因為Joomla內的spl_autoload會根據類名自動加載文件,所以當時構造了一個JSimplepieFactory類對象,而factory.php中包含了import目標類的方法:
所以成功反序列化了simplepie類。回到Phpwind。同道理,我們在Phpwind中看看哪些文件包含了PwDelayRun:
靜態包含PwDelayRun的就只有PwConfigService類。我在剛才獲得的類裡看看,不幸的是,PwConfigService也沒有加載。繼續查找PwConfigService,並沒有靜態加載這個類的方法:
所以我們這個鏈就斷了。但利用spl_autoload這個思路不能斷,我們思考一下,現代php框架中必然存在autoload,在反序列化的過程中發現了不存在的類『PwDelayRun』,就會直接傳入註冊好的spl_autoload函數中。我在 /wind/Wind.php 中,可以找到spl_autoload_register函數的調用:
將Wind::autoload註冊為自動加載函數。跟進Wind::autoLoad
autoLoad第二個參數是沒有值的,所以這裡,最後會走到這一步:include $className . '.' . self::$_extensions;。看到include我就有點激動,但靜下心想一下發現還是有問題的。因為這裡的className是沒有路徑的,而PwDelayRun類在src/library/utility/PwDelayRun.php文件中,我需要傳入路徑才可以包含到這個類。雖然類名不能包含特殊字符,但其實類名中是可以包含\的:
這涉及到php中的命名空間的知識。學過新型框架的同學肯定對命名空間十分熟悉,所以我沒必要多介紹。命名空間中可以包含\,而在windows下,\也可以作為路徑的分隔符。(由此可見,這個漏洞僅限於Windows伺服器)所以這裡,我可以將類名設置為src\library\utility\PwDelayRun(其實就是src\library\utility命名空間下的PwDelayRun類),最後在Wind::autoload裡進行包含 include src\library\utility\PwDelayRun.php
0x04 利用數組+命名空間加載相同名字的類
還有一個問題,我們這裡將類名設置為src\library\utility\PwDelayRun,而:整個phpwind全局是沒有使用命名空間的,也就是默認命名空間為\,但現在的PwDelayRun類所在的命名空間為src\library\utility。
這樣,即使我包含了src\library\utility\PwDelayRun.php文件,反序列化的時候是實例化的src\library\utility\PwDelayRun類。但phpwind的命名空間是\,上下文存在的類是\PwDelayRun類,還是無法正常進行(因為找不到src\library\utility\PwDelayRun類)。
我想了一下,其實也好辦,只要變通一下。我們只要生成src\library\utility\PwDelayRun類和\PwDelayRun類兩個對象,放在一個數組中,在反序列化前者的過程中include目標文件,在反序列化後者的過程中拿到PwDelayRun對象。我構造了一個POC:
執行test1.php即可拿到POC對象。
將這個字符串傳入var參數,結果……
啥事也沒發生……這是什麼情況?
0x05 利用stdClass代替數組繞過限制
我們回看TaskConditionMember類,看看反序列化的那個beforeAction函數:
後面有個判斷is_array,是它在搗鬼。如果var是數組的話,就設置到output裡。所以,最後該對象並沒有銷毀,沒有銷毀那麼實際上就沒有調用__destruct函數,所以也無法執行任意代碼了。要讓is_array返回false,只需序列化一個非數組對象即可。其實在php源碼層,對象是用數組來模擬的,我們只需要用一個對象代替數組即可。php最簡單的對象就是stdClass,我將POC改為如下即可:
生成序列化字符串:
傳入var參數:
萬事大吉,成功!管理員只需擁有後臺『論壇任務』功能,即可直接執行任意代碼。
0x06 前臺利用CSRF起飛
這個漏洞本是一個利用技巧很妙的漏洞,但最關鍵的問題是其出現在後臺,利用門檻太高。但這個漏洞又有一個特點,那就是其為GET方法,只需要一個URL即可觸發。所以,我們可以用類似Discuz這個漏洞的方法: http://**.**.**.**/bugs/wooyun-2014-064886 ,將URL插入前臺帖子的圖片中:
結果……phpwind給我把&都轉義了,無法正常執行。不過沒關係,只要我寫一個302跳轉,跳轉到目標URL即可:
將這個php作為圖片地址寫入帖子:
管理員瀏覽:
獲得webshell:
漏洞證明:
漏洞來源:phith0n@烏雲
安裝雲鎖,完美防禦上述漏洞!