0x00 前言
翻譯自 這篇部落格
在本文中,我們將尋求策略來檢測和分析隱藏在OPcache檔案中的惡意軟體。如果你沒有看過我們之前關於隱藏PHP7 OPcache檔案中的 二進位的webshell文章 中,我們建議在繼續之前先閱讀。
0x01 OPcache
OPcache是PHP7.0新的內建緩衝引擎。它編譯PHP指令碼,並設定在儲存空間中的儲存產生的位元組碼。
在php.ini中也可以指定的緩衝的目標檔案夾:
opcache.file_cache=/tmp/opcache
Persisent secondary file-based cache for OPCahe
在上面的檔案夾中,OPCache儲存php指令碼和相應的編譯之後的php指令碼在同一個檔案夾結構目錄之下。例如 /var/www/index.php 編譯之後會被儲存在 /tmp/opcache/[system_id]/var/www/index.php.bin
上面的system_id是有php的版本號碼,zend的擴充id和各種資料類型的大小,md5之後得到的。在Ubuntu的最新版本(16.04)中,有當前的zend版本和php(7.0.4-7)產生的system_id是81d80d78c6ef96b89afaadc7ffc5d7ea。這個散列是最有可能用於確保安裝時的二進位相容性。該目錄由OPcache緩衝它的第一個檔案時建立。
如我們將在後面看到,每個OPcache檔案將有一個system_id被儲存在前序欄位中。
有趣的是OPcache所有產生的檔案夾/檔案(/tmp/opcache下的一切)都會有寫的許可權作為這個使用者正在啟動並執行服務。
下面是opchache檔案夾中的許可權:
#!shell$ ls /tmp/opcache/drwx------ 4 www-data www-data 4096 Apr 26 09:16 81d80d78c6ef96b89afaadc7ffc5d7ea
正如你可以在上面看到,通過OPcache產生的檔案夾是由www-data使用者寫入並且有寫的許可權。如果我們在OPcache目錄有寫入權限,我們可以通過重寫與編譯的webshell緩衝的檔案執行任意代碼。
0x02 攻擊案例
首先,我們必須獲得快取檔案夾(/tmp/opcache/[SYSTEM_ID])的位置,並有針對性的PHP檔案的位置(/var/WWW/...)
為了簡便起見,我們假設該網站留下了的phpinfo()檔案,從中我們可以得到的快取檔案夾位置,檔案的原始碼的位置,和所有必要的欄位來計算SYSTEM_ID。(我們已經建立了一個工具,計算從一個網站的phpinfo的系統ID()。你可以找到它在我們的 GitHub庫 )。
值得注意的是,目標網站也必須容易檔案上傳。
假設使用了預設的php.ini設定:
opcache.validate_timestamp = 0 ; PHP 7's default is 1opcache.file_cache_only = 1 ; PHP 7's default is 0opcache.file_cache = /tmp/opcache
這裡的攻擊是如何工作的:我們發現了一個網站,可以任意檔案上傳到/var/www下。我們的目標是代替/tmp/opcache/[system_id]/var/www/index.php.bin用我們自己的含有後門的檔案。
1.建立一個名為index.php的本地的包含的webshell惡意PHP檔案:
#!php
2.在php.ini檔案中的設定opcache.file_cache設定為您選擇的地方。
3.運行一個web服務,使用PHP -S 127.0.0.1:8080,然後發送了index.php檔案的請求,觸發緩衝引擎。一個簡單的wge t127.0.0.1:8080 將會完成這個工作。
4.再到在步驟1中指定的快取檔案夾;你會發現一個名為index.php.bin檔案。這是我們的webshell的編譯版本。
5.由於本地SYSTEM_ID將有可能和目標的不同,我們要開啟index.php.bin,修改system_id。正如前面提到的,system_id可以通過暴力破解或phpinfo()函數的伺服器資訊進行計算而得到。要更換system_id所在的檔案簽名的右面:
6.使用檔案上傳漏洞,我們上傳一個檔案/tmp/opcache/[system_id]/var/www/index.php.bin。
7.重新整理網站的index.php檔案將運行我們的webshell。
0x03 繼續深入
php.ini中設定至少有兩個配置將建立替代行為。
Disabling file_cache_onlyEnabling validate_timestamp
Bypassing memory cache (file_cache_only = 0)
如果記憶體快取檔案緩衝優先檔案快取,覆蓋OPcache檔案將不執行
我們的webshell。如果網站伺服器重新啟動,這種限制可以被繞過。由於記憶體緩衝將被清空,OPcache將使用檔案快取,填補了記憶體快取,從而執行我們的webshell。
從這個行為看來,不需要重新啟動來執行webshell仍然是可能的。
在像WordPress的架構,也有一些過時檔案仍然公開訪問(例如: functions.php )。
由於這些檔案已被棄用,他們不會被裝載在記憶體或在檔案系統中沒有一個緩衝版本。我們上傳惡意負載(functions.php.bin),並請求相關的網頁(/wp-includes/registration-functions.php)後,OPcache將運行我們的二進位的webshell。
Bypassing timestamp validation (validate_timestamps = 1)
如果啟用了時間戳記驗證,OPcache將檢查請求的PHP源檔案的時間戳記,並將其與快取檔案的時間戳記前序欄位對比。如果它們不匹配,則快取檔案被丟棄,並建立一個新的。為了成功地繞過這個限制,攻擊者必須知道目標源檔案的時間戳記。
話雖這麼說,在像WordPress的架構,對源檔案的時間戳記是作為他們在提取zip或tar時的。
這個有趣的是,一些檔案2012年以來沒有被修改(functions.php和registration.php的檔案)。因此,這些跨越多個版本的WordPress時間戳記將會相同。知道時間戳記,攻擊者就可以相應地修改他的有效載荷,並成功地代替快取,與validate_timestamps設定。時間戳記位於從檔案的開頭34位元組:
0x04 結論
總之,這種新的攻擊向量是針對具體的硬化環境的額外開採技術。它不是影響PHP應用的通用漏洞。隨著PHP7.0的發行如Ubuntu16.04的到來,此攻擊更需要加強審核您的代碼避免檔案上傳漏洞和警惕潛在危險的伺服器配置。