1. 程式人生 > >PHP程式碼審計05之正則使用不當

PHP程式碼審計05之正則使用不當

#前言 根據紅日安全寫的文章,學習PHP程式碼審計的第五節內容,題目均來自**PHP SECURITY CALENDAR 2017**,講完題目會用一道CTF的題目和例項來加深鞏固。這是之前寫的,有興趣可以去看看: [PHP程式碼審計01之in_array()函式缺陷](https://www.cnblogs.com/lxfweb/p/13729406.html) [PHP程式碼審計02之filter_var()函式缺陷](https://www.cnblogs.com/lxfweb/p/13757525.html) [PHP程式碼審計03之例項化任意物件漏洞](https://www.cnblogs.com/lxfweb/p/13822440.html) [PHP程式碼審計04之strpos函式使用不當](https://www.cnblogs.com/lxfweb/p/13898553.html) #漏洞分析 下面看題目,程式碼如下: ![](https://img2020.cnblogs.com/blog/1996712/202012/1996712-20201228160937231-25522013.png) 題目漏洞是正則使用不嚴謹導致任意檔案刪除的漏洞,現在來具體分析,引起漏洞的地方在上面程式碼的21行,這裡用到了preg_replace()函式,我們開啟PHP手冊來看看對這個函式的定義如下: ![](https://img2020.cnblogs.com/blog/1996712/202012/1996712-20201228162734726-1728777475.png) 瞭解了函式的用法,看上面程式碼,**[^a-z.-_]** 表示匹配除了 a 字元到 z 字元和. 字元到 _ 字元之間的所有字元,但是沒有考慮到目錄路徑字元。這就直接可以任意刪除檔案,例如構造如下引數: `action=delete&data=../../config.php` 將刪除config.php檔案。 #CTF練習 通過上面的講解,來用一道CTF題目來練習一下,也是關於正則的問題,先看程式碼: ``` //index.php = preg_match('/^[[:graph:]]{12,}$/', $password))   {        echo 'Wrong Format';        exit;   }    while (TRUE)   {        $reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';        if (6 > preg_match_all($reg, $password, $arr))            break;        $c = 0;        $ps = array('punct', 'digit', 'upper', 'lower');        foreach ($ps as $pt)       {            if (preg_match("/[[:$pt:]]+/", $password))            $c += 1;       }        if ($c < 3) break;        if ("42" == $password) echo $flag;        else echo 'Wrong password';        exit;   } } highlight_file(__FILE__); ?> //flag.php ``` 這道題目考察了是否熟悉PHP正則表達的字元類,大體是下面這個表格: | alnum | 字母和數字 | | ------------- | ------ | | alpha | 字母 | | ascii | 0 - 127的ascii字元 | | blank | 空格和水平製表符 | | cntrl | 控制字元 | | digit | 十進位制數(same as \d) | | graph | 列印字元, 不包括空格 | | lower | 小寫字母 | | print | 列印字元,包含空格 | | punct | 列印字元, 不包括字母和數字 | | space | 空白字元 (比\s多垂直製表符) | | upper | 大寫字母 | | word | 單詞字元(same as \w) | | xdigit | 十六進位制數字 | 想要更加詳細的瞭解,建議翻閱PHP手冊,瞭解了字元類,下面來分析程式碼,上面一共三處正則表達,第一處如下: `if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password))` 它表示的含義是匹配到可列印字元12往上包含12,^表示必須某類字元開頭,$表示必須某類字元結尾。 第二處正則如下: ``` $reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/'; if (6 > preg_match_all($reg, $password, $arr)) break; ``` 它表示的含義是,把連續的字元,數字,大寫,小寫作為一段,最少分成六段,比如Test+0He 會分為T est + 0 H e六段。 下面看第三處正則: ``` $ps = array('punct', 'digit', 'upper', 'lower'); foreach ($ps as $pt) { if (preg_match("/[[:$pt:]]+/", $password)) $c += 1; } if ($c < 3) break; if ("42" == $password) echo $flag; ``` 這裡的含義是輸入的字元必須包含字元,數字,大寫,小寫其中的三種往上。最後與42進行弱型別比較,都符合就輸出flag,現在都解讀清楚了,讓咱們構造payload結果如下: ![](https://img2020.cnblogs.com/blog/1996712/202012/1996712-20201229160015554-1041551907.png) #例項分析 通過例題和CTF題目的講解,是不是感覺棒棒的,現在咱們來分析例項吧,例項是LvyeCMS3.1,是基於ThinkPHP3.2.3框架。這個例項存在的漏洞也是函式使用不規範被繞過,導致任意檔案刪除。下面來具體分析: 先檢視入口檔案index.php ![](https://img2020.cnblogs.com/blog/1996712/202012/1996712-20201229172049949-152775478.png) 可以看到公共目錄,應用目錄等一些資訊。接下來再看看目錄結構: ![](https://img2020.cnblogs.com/blog/1996712/202012/1996712-20201229172548660-1222378931.png) 而漏洞在`Application/Template/Controller/StyleController.class.php`檔案中,具體如下: ![](https://img2020.cnblogs.com/blog/1996712/202012/1996712-20201229172950641-543274393.png) 看程式碼第117行,這裡是獲取目錄路徑,引數也是我們可以控制的,再向後看,用到了str_replace()函式,它是個字串替換函式,具體說明如下: ![](https://img2020.cnblogs.com/blog/1996712/202012/1996712-20201229173427362-702119022.png) 再這裡起到的作用就是將'..\\', '../', './', '.\\'替換為空。但是這裡是可以繞過的,如果我們輸入.....///呢,會發生什麼?是不是正好構造成了../,舉個小例子會更清楚,如下: ![](https://img2020.cnblogs.com/blog/1996712/202012/1996712-20201229174750873-1552218961.png) 構造出../我們就可以穿越目錄了,現在訪問install.php檔案會提示已安裝,如下圖: ![](https://img2020.cnblogs.com/blog/1996712/202012/1996712-20201229174955034-756372498.png) 然後嘗試刪除lvyecms/Application/Install/目錄下的 install.lock 檔案,構造payload如下: http://www.xxx.com/index.php?g=Template&m=Style&a=delete&dir=.....///Application/Install/&file=install.lock ![](https://img2020.cnblogs.com/blog/1996712/202012/1996712-20201229175524255-407732001.png) 現在訪問install.php,發現確實刪除了,如下圖: ![](https://img2020.cnblogs.com/blog/1996712/202012/1996712-20201229175854454-968611439.png) #小結 通過這篇文章的學習與講解,是不是對PHP的正則瞭解的更多了呢,下一篇文章會對parse_str函式缺陷進行學習和講解。一起加