PHP任意文件上傳漏洞CVE-2015-2348淺析


昨晚安全新聞爆出一個“PHP任意文件上傳漏洞”,CVE編號為:CVE-2015-2348。


當時樓主正准備收拾東西回家,看到這個新聞心里一驚:失傳江湖多年的0字符截斷上傳漏洞又重現了?而且還影響這么多版本!如果漏洞屬實,看來今晚又要通宵打補丁了啊。

不過經過簡單分析后,發現漏洞的利用條件相當苛刻(很多人好奇到底有多苛刻),樓主簡單記錄自己的分析過程和大家分享一下,如有不當,請多多指正。

一、漏洞概述

漏洞報告者說php的上傳函數 move_uploaded_file的目的路徑參數可以使用空字符截斷,繞過jpg,png上傳類型的檢測,從而導致任意文件上傳。報告者給出的測試EXP:

move_uploaded_file($_FILES['x']['tmp_name'],"/tmp/test.php\x00.jpg")

按照漏洞報告者的描述 5.3 以后版本都受影響(https://bugs.php.net/bug.php?id=69207)

二、漏洞測試

為驗證漏洞有效性樓主搭建一個測試環境,版本 5.3.6,構造測試代碼如下:

上傳前台頁面upload.htm:

 上傳處理腳本upload.php

 測試上傳upload.php始終返回失敗false

於是換了一個版本5.3.29,依舊未測試成功,難道是我測試的方法不對,那就看一下源碼吧。

三、漏洞調試

move_uploaded_file的代碼實現在 ext/standard/basic_functions.c 文件,關鍵代碼:

代碼中有幾處return false的邏輯,那么測試不成功肯定是命中了其中的一個邏輯。

樓主使用最原始的打log方法來調試,確認測試代碼被上述標紅代碼過濾了,於是查看打印出來strlen(new_path) 和 new_path_len的值  —— 分別是19 和 23。

new_path 是路徑名字符串“/tmp/whoisdashuaige\x00jpg”的長度,由於strlen計算到空字符處\x00結束,因此長度19可以理解。

那么為什么new_path_len是23呢?

PHP語言中所有的變量類型都保存在一個如下的結構體中,new_path_len對應標紅的len。這里的len是一個二進制長度,不會遇到空字符結束所以長度為23。所以測試demo使用\0在這里長度不等一直返回失敗。

那測試成功的又是什么情況呢,組里另外一位同事發來消息說在5.6.6版本可測試成功,打開5.6.6漏洞代碼處一看震驚了,5.6.6代碼如下:

 

原來在高版本(受影響版本中),PHP把長度比較的安全檢查邏輯給去掉了,導致了漏洞的發生,不知道這段代碼是哪個開發者更新的,什么仇什么怨。

四、漏洞利用條件

漏洞利用需要控制第二個參數(目標路徑),比如:

 

但是,實際在開發場景中,目標路徑一般是程序自己生成的(避免同名文件覆蓋的情況),就算退一步,程序猿同學想取原來的文件名,往往也習慣用$_FILES變量取文件名。

而$_FILES變量中如果加入\0字符截斷,卻又不影響程序邏輯:

提交a.php\0jpg 和 a.php 是等價的。

測試方法如下:

 

上傳抓包修改name為a.php\0jpg(\0是nul字符),可以看到$_FILES['xx']['name']存儲的字符串是a.php,不會包含\0截斷之后的字符,因此並不影響代碼的驗證邏輯。

但是如果通過$_REQUEST方式獲取的,則可能出現擴展名期望值不一致的情況,造成“任意文件上傳”。

五、總結

1、漏洞影響版本必須在5.4.x<= 5.4.39, 5.5.x<= 5.5.23, 5.6.x <= 5.6.7,詳見CVE公告:https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-2348

2、漏洞利用條件苛刻,與實際業務書寫代碼習慣有較大的差異,因此風險較低

行為倉促,如有不當請指正。

摘自:TSRC


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM