PHP弱型別在實戰中導致的漏洞總結

xfkxfk發表於2018-04-11

簡介

說到PHP弱型別大家肯定不陌生,但是對於PHP中==和===比較時存在的差異,哪一個安全哪一個不安全,肯定很多程式設計師並不清楚。

 

網路上有很多大佬們的文章都是介紹PHP弱型別原理,及其可能存在的問題理論,還有就是CTF裡面經常出現的場景,然而在具體的實戰當做卻很少有案例或者文章,本文中將我在具體的專案和程式碼審計中遇到的由PHP弱型別引發的漏洞進行一個初步總結,例如由PHP弱型別導致的密碼重置、登入繞過、SQL隱碼攻擊、命令執行、Hash碰撞等漏洞等等,後續遇到新場景繼續補充。

PHP弱型別是什麼

PHP作為最受歡迎的開源指令碼語言,也被稱為是世界上最好的語言,越來越多的應用於Web開發領域。

 

PHP屬於弱型別語言,即定義變數的時候不用宣告它是什麼型別。作為一個程式設計師,弱型別確實給程式設計師書寫程式碼帶來了很大的便利,這一便利也是PHP語言的一個特性,但是在安全領域,特性既漏洞,這些特性在程式碼裡面經常就是漏洞最容易出現的地方。

PHP比較操作符

在弄明白PHP操作符之前,需要明白PHP變數型別及它們的意義。例如,"42" 是一個字串而 42 是一個整數。FALSE 是一個布林值而 "false" 是一個字串。HTML
表單並不傳遞整數、浮點數或者布林值,它們只傳遞字串。

 

PHP的比較操作符有==(等於)鬆散比較,它不會去檢查條件式的表示式的型別;===(完全等於)嚴格比較,也就是恆等,它會檢查查表示式的值與型別是否相等,所以這裡面就會引入很多有意思的問題。例如NULL,0,”0”,array()使用==和false比較時,都是會返回true的,而使用===卻不會,如下圖:

 

 

在鬆散比較的時候,PHP會將他們的型別進行強制轉換從而統一型別,比如說字元到數字,非bool型別轉換成bool型別。一個數字和一個字串進行比較,PHP會把字串轉換成數字再進行比較。PHP轉換的規則的是:若字串以數字開頭,則取開頭數字作為轉換結果,若無則輸出0。當有一個對比引數是整數的時候,會把另外一個引數強制轉換為整數,如下圖:

 

 

PHP官方也給出了型別比較表,表格中顯示了PHP型別和比較運算子在鬆散和嚴格比較時的作用及返回值,應該是比較詳細的,如下圖:

 

使用PHP函式對變數\$x進行比較:

 

 

鬆散比較(==)情況

 

 

嚴格比較(===)情況

 

 

從上面的表格中已經很清晰的看到==和===比較時的區別了。

實戰中導致的漏洞解析

下面以實戰中遇到的真實場景為例介紹PHP弱型別導致的漏洞。

 

DedeCMS密碼重置

 

2018年01月09日,Dedecms官方更新了DedeCMS V5.7
SP2正式版,在此版本及之前版本存在任意使用者密碼重置漏洞,具體導致漏洞的程式碼如圖:

 

 

在找回密碼時,當$dopost =safequestion時,通過傳入的member_id查詢出對應id使用者的安全問題和答案資訊,當我們傳入的問題和答案不為空,並且等於系統設定的問題和答案時就進入sn()函式。

 

這裡如果使用者設定了問題和答案,我們並不知道問題和答案是什麼,就無法進入sn()函式。但是如果此使用者沒有設定問題和答案呢?此時系統預設問題是”0”,答案是空。

 

那麼我們傳入答案$safeanswer = “”時:

 

$row[‘safeanswer’] == $safeanswer;成立。

 

但是傳入問題$safequestion = “0”時:

 

empty(\$safequestion)為真,此時$safequestion = ””,而$row[safequestion] = “0”

 

此時$row[safequestion] == $safequestion;不成立。

 

 

所以現在要讓問題相等,才能繞過if判斷,此時如果熟悉PHP的話,會想到PHP的弱型別問題,如下圖:

 

 

利用弱型別的特性,==鬆散比較,"0.0"、"0."、"0e123"在empty()函式是不為空,並且鬆散比較"0"時為真,成功進入if條件,進入sn()函式重置密碼。此漏洞在滲透測試和眾測時應該已經被刷很多遍了吧。詳細漏洞分析見:https://mp.weixin.qq.com/s/MTES86qMVDquKrZq2oolVA

 

ZPanel密碼重置

 

Sentora / ZPanel 由於設計缺陷,導致存在密碼重置漏洞,具體漏洞程式碼如下:

 

 

生成一個隨機的驗證密碼Token,然後更新資料庫,傳送重置密碼連結。

 

 

然後點選重置密碼連結後,驗證token有效性,重置密碼。

 

但是在重置密碼完成後,系統又設定了ac_resethash_tx為空,那麼我們就可以以空的token繼續重置密碼了!!!

 

具體漏洞細節:https://blogs.securiteam.com/index.php/archives/3386

 

HDwikiSQL隱碼攻擊

 

具體漏洞程式碼如圖:

 

 

從程式碼中看到,首先從GET裡獲得doctype($doctype =
$this->get[2];),然後進入一個switch語句。如果進入case 2和case
3保持\$doctype的值不變,但是進入default將\$doctype改為1,最後看到這句$count=$this->db->fetch_total('focus',"type=$doctype");,直接將\$doctype帶入SQL語句,所以只要這個switch語句不影響\$doctype的值也就是必須進入case
2和case 3分支,就導致SQL隱碼攻擊漏洞。

 

如果要進行SQL隱碼攻擊那麼\$doctype必須是字串,但是\$doctype必須進入case 2和case
3分支,case 2和case
3分支又是整型數字,所以就是很經典的弱型別問題進行鬆散比較的點了。

 

我們只需要將\$doctype的值,也就是GET獲取的引數第一位設定為2或者3就好了,後面跟上sql語句就成功繞過進行sql注入了,如下圖:

 

 

如上圖成功繞過進行sql注入。

 

某產品命令執行

 

在偶然一次滲透測試專案中,登入到某產品中,發現如下程式碼(圖為虛擬碼):

(圖片丟了...)

 

從程式碼中看到\$file進入到命令執行,但是\$file中可控的變數是\$config,而且這裡判斷只有\$config==2時才能進入命令執行流程,所以利用弱型別的型別強制轉換就可繞過判斷進入命令執行。

 

 

WordPress Cookie偽造

 

在WordPress 3.8.2的官方補丁中有這樣一個補丁

 

 

很明顯,就改變鬆散比較和嚴格比較。

 

在WordPress中\$hmac來源於cookies,是我們可控的一個輸入引數,結構如下:

 

 

\$hash是以下程式碼生成一個md5值,當\$hmac ==
\$hash 時,登入成功。由於是==鬆散比較,所以存在如下幾種情況都可以登入成功:

//第一種情況,完全相等。

\$hmac = ‘1f253e501c301bf5bf293c40d7d92ded’;

\$hash = ‘1f253e501c301bf5bf293c40d7d92ded’;

//第二種情況,第一位為數字,第二位為字母

\$hmac = 1;

\$hash = ‘1f253e501c301bf5bf293c40d7d92ded’;

//第三種情況。第一位為字母

\$hmac = 0;

\$hash = ‘af253e501c301bf5bf293c40d7d92ded’;

//第四種情況,第一位為0,第二位為e,後面所有位為數字

\$hmac = “0”;

\$hash = ‘0e1234567890123456...32’;

 

由於\$hmac最後獲取的是一個字串,所以很顯然第四種情況是可以成立的。所以最後這個漏洞的利用方式還可以是:讓\$hmac =‘0’,通過生成\$hash,獲得一個,第一位為0,第二位為e,後面所有位為數字的\$hash。

 

變相資訊洩露

 

在PHP中進行比較運算時,如果遇到了0e\d+這種字串,就會將這種字串解析為科學計數法,例如0e10,‘e’會識別為次方,0的10次方為0,如下圖所示,兩個不同字串但是在==下他們的md5值相等:

 

 

那麼我們來擴充套件一下:

先註冊密碼為240610708的使用者A。

然後用密碼QNKCDZO嘗試登入使用者A。

倘若成功登入,則證明此網站採用了不完備的加密體制md5一次加密。

先註冊密碼為0e33455555的使用者A。

然後用密碼0e66788888嘗試登入使用者A。

倘若成功登入,則證明此網站採用了明文進行儲存密碼!

 

這樣既可採集目標資訊了,還有其他擴充套件大家自己開腦洞。

 

其他

 

除了在PHP的弱型別中存在強制型別轉換外,MySQL中也同樣存在類似的特性,在mysql裡面,當欄位型別為整型,而where語句中的值不為整型的時候,會被轉換成整型才放入查詢。也就是說,如果where
code='xxx',xxx不為整型的話,則會先將xxx轉換成整數,才放入查詢,也就是說,如果我們傳入的字串為0aaa,則會轉換成0,再執行。詳見P牛的部落格:

 

https://www.leavesongs.com/PENETRATION/findpwd-funny-logic-vul.html

參考連結

http://php.net/manual/zh/types.comparisons.php

防護方案

為了避免意想不到的執行效果,根基實際場景應該使用嚴格比較。

相關文章