漏洞簡介
PHP 發布公告,舊版本的?php_array_merge_recursive?函數中存在UAF風險,被利用可能導致用來繞過禁用函數。
受影響的版本
PHP 7.2 - 7.4.9
安全專家建議用戶盡快升級到安全版本,以解決風險。
php include漏洞、漏洞原理
一、array_merge_recursive 函數實現
在?array_merge_recursive?函數的實現中,通過遍歷源數組鍵值,如果鍵值不存在,則將對應的值直接插入目標數組;如果鍵值存在,則查詢相應的目標數組。在目標數組不存在此鍵值時,將鍵值與相應的值插入目標數組;如果存在相同的鍵值,則會嘗試將相應的值加入到目標數組中。具體處理如下圖,在目標值為?NULL?時,將其轉變為數組類型并在數組中加入?NULL,在源數組中的值為對象類型時將其轉換為數組類型,嘗試為?src_entry?添加引用后將?src_zval?添加到數組中;如果源數組中的值類型為數組則遞歸調用?php_array_merge_recursive?函數。
二、原理分析
在嘗試為源數組中的值添加引用計數的時候錯誤地調用了?Z_TRY_ADDREF_P(src_entry),?src_entry?此時為對源數組中的值的引用,此時引用計數被添加到了引用而不是源數組中的值。
如果在?array_merge_recursive?函數中傳入可變的字符串(通過直接賦值獲得的字符串不可變,在嘗試添加引用計數時會失敗),此時?src_zval?即可變字符串的引用計數并沒有增加,在數組被銷毀時,因為可變字符串的引用計數提前變為 0 導致 UAF。
沒裝php有漏洞、三、利用分析
注: 以下調試直接在 php 調試而不是在服務器加載 php 調試,但是差別不大。
1、在字符串被釋放后,創建一個新的對象占位,進行類型混淆,此時字符串的?len?被新創建對象的?ce?覆蓋。ce 是一個地址,所以后續不會影響字符串的寫入。
占位前后對比圖如下:
字符串對象被釋放后,創建對象前:
創建對象后:
php漏洞怎么修復,2、讀取新創建對象的?handlers?方便之后泄露內存信息,handers?的值即為上圖的 0x0000000008dfe500,在后面可以達到任意內存讀取后可以用來泄露 php 基地址。讀取新創建對象中包含堆地址的區域,獲取被釋放的字符串地址,例如可以讀取 0x7ffffb080540 中的堆地址,減去 0xc8 即為字符串對象中的字符串地址 hex(0x00007ffffb0805b0 - 0xc8) = 0x7ffffb0804e8 即為字符串對象的 val 屬性的地址。
3、將新創建對象的一個屬性的值指向的類型改寫為引用,引用的地址為一個偽造的引用字符串對象。可以將新創建對象的第一個屬性即?properties_table?數組中的第一個元素的類型改為引用,地址改為偽造的引用字符串對象的地址。地址0x7ffffb0804f8 保存的即為新創建對象的第一個屬性的地址,地址0x7ffffb080500 中存儲的 0xa 代表引用類型。
其指向的地址 0x00007ffffb080548 保存的為偽造引用對象的地址,偽造的對象的第三個八字節需置為 6 (引用對象的類型)。引用字符串對象的內存布局如下圖。可以看到,引用中保存類型為 0x6 代表字符串類型,但是地址為 0x0,之后可以通過寫入任意地址來達到內存讀取。
4、通過修改偽造的字符串的起始地址來達到任意內存讀取,利用之前泄露的?handlers?地址來獲取?elf?基址,之后遍歷內存獲取?zif_system?函數的地址。
5、偽造一個閉包對象,從一個真實存在的閉包對象拷貝其存儲的值,修改函數類型為內置函數類型,has_dimension?屬性地址為?zif_system,修改后如下圖。
6、修改對象的一個屬性地址為偽造的閉包對象的地址,調用對象的屬性函數即可完成禁用函數的繞過。
php漏洞源碼、漏洞驗證
一、在7.4.5 版本中進行攻擊嘗試
在目標服務器上傳利用腳本,執行命令。
(視頻地址:https://v.qq.com/x/page/c31651dla6g.html)
二、7.4.10 版本修復分析
修改?Z_TRY_ADDREF_P(src_entry) 為 Z_TRY_ADDREF_P(src_zval)。
php漏洞是什么原因。參考
https://bugs.php.net/bug.php?id=79930
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态