技術分析:剖析HikaShop PHP對象注入漏洞
HikaShop是基于著名開源CMS Joomla!的電子商務程序,可以幫助用戶輕松的開發電子商務網站或網店。
距離上次我們發現Joomla!的HikaShop擴展對象注入漏洞(影響版本<2.3.3)已經兩月有余了。今天要講的這個漏洞允許黑客向網站發送惡意指令,從而造成遠程代碼執行。
小科普
由于本篇文技術含量稍高,這里小編做一些術語科普,希望對大家有用:
魔術方法:在 PHP中以兩個下劃線開頭的方法,調用時需要在類中預定義。 析構函數:當對象脫離其作用域時,系統自動執行析構函數,做好“清理善后”的工作。 回調函數:把函數的指針(地址)作為參數傳遞給另一個函數,該指針被用來調用其所指向的函數。 序列化:將對象的狀態信息轉換為可以存儲或傳輸的形式。 類實例:必須通過對象名來訪問,也就是說要想使用類實例,必須創建對象。
對象注入的原理
對象注入通常發生在用戶的輸入,被傳遞給unserialize()函數然后進行調用的時候。黑客可以通過構造輸入內容,向WEB服務器發送當前WEB應用下的一個序列化的類實例,保證這些被定義為魔術方法的類,在特定的時候會被觸發,從而執行其中的惡意代碼。
漏洞的罪魁禍首
代碼中的124行和132行有兩個重要的點值得我們注意,$infos變量被設置為JRequest::getVar()的返回值,這就意味著它可以接收$_GET['infos']或者$_POST['infos']的值。接著,$infos的值被base64編碼后,會傳遞給unserialize()函數。
Hikashop漏洞的攻擊利用方法如圖:
我們在了解這些信息后,就需要想辦法達成我們的邪惡目的。在我們的POC調用了Joomla! 3.3.x的類,并且定義成功后,我們就可以讀取WEB服務器上的/etc/passwd。#p#
找出利用方法,直擊問題核心
我們首先要做的,就是分析該程序代碼的執行順序。同時,我們也需要使用Joomla!類的魔術方法。值得一提的時候,PHP類的析構方法__destruct(),在腳本執行完畢時會自動執行析構函數。
在這個特定案例下,我們選擇了JDatabaseDriverMysqli類的析構方法來達成我們的需求,這可以讓我們從任何存在的類里去調用方法。Destruct函數調用disconnect方法如圖:
這里采用了$this->disconnectHandlers調用那些回調函數,Disconnect函數如圖:
我們準備通過創建一個改版過的JDatabaseDriverMysqli類,它可以讓我們更改變量的默認值。特別需要指出的是,我們需要滿足幾個條件來實現序列化。一旦Hikashop被反序列化,會生成一些實例,然后析構函數會執行我們提供的任何函數或者方法。
為了實現上述的需求,我們需要做到以下幾點:
1.一定要把$this->connection的值設為“True”(否則我們不能調試到call_user_func_array()函數里面去)
2.使用某個包含如下內容的數組(以下任意一點即可)賦給$this->disconnectHandlers:
(1)包含我們目標函數名的字符串
(2)包含方法名稱和對應類的一個實例,比如這個數組(new ourClass(), “ourClassMethod”)
我們不能控制傳遞給目標函數的參數內容(它永遠是我們類的實例),這就限制了我們在以下環境里研究方法:
1.那些我們不能使用任何參數的時候
2.那些函數的第一個參數類型并沒有針對黑客進行限制的時候
3.那些因環境需要,而使用的多參數模式(事實上我們只需構造發送一個參數,因為其他的參數可能被置為默認值或者空值,并且記入服務器的錯誤日志)#p#
發現有趣的方法
使用一些grep命令,我們會看到PHPMailer類的這個方法,PHPMailer類的require_once方法如圖:
很容易是不是?傳遞PHPMailer的一個實例,把$this->PluginDir設置指向為可以進行hack的地址(這可以產生一個絕妙的LFI/RFI攻擊,可以想象一下我們把$this->PluginDir指向http://blog.sucuri.net/)。然而不幸的是,有兩個難題阻礙了我們前進的道路:
問題1– PHPMailer類在當前環境下沒有做定義
這絕對是一個讓人頭疼的問題,但我們真的什么也做不了麼?當然不是!謝天謝地,Joomla!采用了一些非常規則的類進行自動加載,這使得我們在導入PHPMailer類的過程中,自動導入JMail組件。
為了解決這個問題,我們在沒有使用過的JDatabaseDriverMysqli的變量中創建了JMail的一個實例。這樣的話,自動導入機制可以在導入JMail組件的文件的同時,加載PHPMailer的定義。
問題2– SmtpSend()方法被定義為保護模式,防止外部使用
這倒不是事兒,如果你不能直接調用SmtpSend(),可以找出另一個public方法,對SmtpSend()進行調用!然而幸運女神再次眷顧了我們,確實存在這樣一種方法!PostSend函數調用SmtpSend()如圖:
我們唯一剩下的工作,就是將$this->Mailer的值設為smtp!
這樣就完了?
當然不是,我們確實找出了一些LFI/RFI的漏洞,但離我們最初的目標還很遙遠。我們的最終目的是:發送簡單的命令,一鍵把后門植入網站根目錄!
我們可以使用RFI漏洞進行遠程文件包含,那么現在問題來了,它需要WEB容器開啟allow_url_include選項,而這個選項默認是關閉的。也許,我們需要尋求另一種方法來達成目標。#p#
Sendmail拯救世界!
你們可能注意到了該截圖,那是一個帶有PostSend()函數的方法,即$this->SendmailSend(),Sendmail函數如圖:
這里展示了一個非常有趣的方法,可以用來在目標服務器的絕對路徑下寫文件。
popen()函數使用了$sendmail變量($sendmail變量通常包含“/usr/sbin/sendmail -oi -t”或者“/usr/sbin/sendmail -oi -f’EMAIL@HERE.COM’ -t”)來執行shell命令,所以我們才可以使用Sendmail函數來發電子郵件。經過進一步分析,可以發現它使用了兩個變量,即$this->Sender和$this->Sendmail,前者可以為空。
它們使用了不同的函數:escapeshellcmd()和escapeshellarg()。在escapeshellcmd()里調用$this->Sendmail的話,以下這些特殊字符會被編碼:#&;`|*?~^()[]{}$\, \x0A以及\xFF。最后我們只能使用字母、數字以及少量如“/”和“-”這樣的字符。
這距離我們的目標還遠遠不夠!我們可以在Sendmail函數的原始命令中加入我們需要的參數。
所以,如果我們把“/usr/sbin/sendmail -OQueueDirectory=/tmp -X/tmp/smtp.php”這樣的參數加進去會如何?同樣,如果我們使用現有的poc,同時對代碼中其他所有的變量進行設置后,發送一個頭部含有以下的內容的郵件又會怎樣呢?
頭部內容:
確實是個難題吧?如果那樣做的話會產生如下后果:
1.“-OQueueDirectory=/tmp -X/tmp/smtp.php”,這部分代碼會將/tmp/smtp.php發送的郵件給保存起來。
2.我們發送的頭部內容,會被保存起來進行反序列化處理。
現在我們需要做的,就是把整個流程整理一下,最后才能達到我們的目標!
完整利用流程圖
在這時我們的方法已經很復雜了,一個統籌的流程圖在這時顯得十分有必要:
一旦黑客成功創建和序列化一個對象,將其傳遞給存在漏洞的Hikashop擴展加載,就可以竊取/etc/passwd的內容。
我們可以通過該漏洞做許多事,這里所講到的僅僅是其中一種。如果您使用的是Hikashop擴展,我希望您已經在我們上次發布該漏洞后及時更新了補丁。
水平有限,如有表達不明朗的地方請不吝賜教,可以點擊文章下方的“文章糾正”
參考來源:http://blog.sucuri.net/2014/11/deep-dive-into-the-hikashop-vulnerability.html