《php漏洞:檢查相等時的應避免的陷阱》要點:
本文介紹了php漏洞:檢查相等時的應避免的陷阱,希望對您有用。如果有疑問,可以聯(lián)系我們。
相關主題:PHP安全
PHP是一門弱類型的語言。很方便學習和應用,但在特定時候,正是因為弱類,所以會導致有程序的缺陷。
1.弱類型的比較==導致的漏洞
注:這些漏洞適用于所有版本的php
先來復習一下基本的語法:php中有如下兩種比較符號:兩個等號和三個等號(這一點和Javascript)有些類似
$a==$b
$a===$b
明確的看到,兩個等于號的等于會在比較的時候進行類型轉換的比較。
如果比較一個數(shù)字和字符串或者比較涉及到數(shù)字內(nèi)容的字符串,則字符串會被轉換為數(shù)值并且比較按照數(shù)值來進行。此規(guī)則也適用于 switch 語句。當用 === 或 !== 進行比較時則不進行類型轉換,因為此時類型和數(shù)值都要比對.
明確的寫出了 如果一個數(shù)值和一個字符串比較,那么會將字符串轉換為數(shù)值(而不是相反,將數(shù)值轉化為字符串)
然而,php是如何將一個字符串轉化為數(shù)值的呢,
當一個字符串被當作一個數(shù)值來取值,其結果和類型如下:如果該字符串沒有包含 ‘.’,’e’ 或 ‘E’ 并且其數(shù)字值在整型的范圍之內(nèi)(由 PHP_INT_MAX 所定義),該字符串將被當成 integer 來取值。其它所有情況下都被作為 float 來取值。該字符串的開始部分決定了它的值。如果該字符串以合法的數(shù)值開始,則使用該數(shù)值。否則其值為 0(零)。合法數(shù)值由可選的正負號,后面跟著一個或多個數(shù)字(可能有小數(shù)點),再跟著可選的指數(shù)部分。指數(shù)部分由 ‘e’ 或 ‘E’ 后面跟著一個或多個數(shù)字構成。
這是官方手冊上面的幾個例子
<?php $foo = 1 + "10.5"; // $foo is float (11.5) $foo = 1 + "-1.3e3"; // $foo is float (-1299) $foo = 1 + "bob-1.3e3"; // $foo is integer (1) $foo = 1 + "bob3"; // $foo is integer (1) $foo = 1 + "10 Small Pigs"; // $foo is integer (11) $foo = 4 + "10.2 Little Piggies"; // $foo is float (14.2) $foo = "10.0 pigs " + 1; // $foo is float (11) $foo = "10.0 pigs " + 1.0; // $foo is float (11) ?>
我們大概可以總結出如下的規(guī)則:當一個字符串被轉換為數(shù)值時
如果一個字符串為 “合法數(shù)字+e+合法數(shù)字”類型,將會解釋為科學計數(shù)法的浮點數(shù)
如果一個字符串為 “合法數(shù)字+ 不可解釋為合法數(shù)字的字符串”類型,將會被轉換為該合法數(shù)字的值,后面的字符串將會被丟棄
如果一個字符串為“不可解釋為合法數(shù)字的字符串+任意”類型,則被轉換為0! 為0…為0
當然,上面的那些等式對于===都是false的,原本一些應該用===的地方誤用了==,導致了可以注入的地方。
示例代碼 1:利用轉為數(shù)字后相等的漏洞
這是一個ctf的題目,非常有趣,可以看到,要求給出兩字符串,一個是純數(shù)字型,一個只能出現(xiàn)字符,使兩個的md5哈希值相等,然而這種強碰撞在密碼學上都是無法做到的。
但是我們看到,最終比較兩者的哈希的時候,使用的是等于 而不是 全等于 ,因此可以利用一下這個漏洞
再回頭看一 md5() 函數(shù):
string md5 ( string $str [, bool $raw_output = false ] )
str原始字符串。raw_output如果可選的 raw_output 被設置為 TRUE,那么 MD5 報文摘要將以16字節(jié)長度的原始二進制格式返回。
可以知道,第二個參數(shù)為true的時候,顯示16位的結果,而為false和沒有第二個參數(shù)時,為32位的16進制碼(16位的結果是把32位的作為ASCII碼進行解析)
16進制的數(shù)據(jù)中是含有e的,可以構建使得兩個數(shù)字比較的,這里有一個現(xiàn)成的例子:
md5('240610708')
//0e462097431906509019562988736854.md5('QNKCDZO')
//0e830400451993494058024219903391
可以看到,這兩個字符串一個只包含數(shù)字,一個只包含字母,雖然兩個的哈希不一樣,但是都是一個形式:0e 純數(shù)字這種格式的字符串在判斷相等的時候會被認為是科學計數(shù)法的數(shù)字,先做字符串到數(shù)字的轉換。
轉換后都成為了0的好多好多次方,都是0,相等。(大家可以自己嘗試一下)因此用===可以避免這一漏洞。
示例代碼2: 利用 類’a'==0的漏洞:
這次這個例子是傳入一個JSON的數(shù)據(jù),JSON在RESTful的網(wǎng)站中是很常用的一種數(shù)據(jù)傳輸?shù)母袷?。這個表單會把一個name為key的input的數(shù)據(jù)作為json傳到服務端
{"key":"your input"}
我們該如何破解?想”a”==0這個漏洞,之用我們使$json->key是一個數(shù)字類型的變量就可以,怎么做到呢?
php的json_decode()函數(shù)會根據(jù)json數(shù)據(jù)中的數(shù)據(jù)類型來將其轉換為php中的相應類型的數(shù)據(jù),也就是說,如果我們在json中傳一個string類型,那么該變量就是string,如果傳入的是number,則該變量為number。因此,我們?nèi)绻麄魅胍粋€數(shù)字,就可以使之相等。網(wǎng)頁中的表單可能限制了所有的輸入都是string,即使輸入數(shù)字,傳入的東西也是
{"key":"0"}
這是一個字符串0,我們需要讓他為數(shù)字類型,用burp攔截,把兩個雙引號去掉,變成這樣: {"key":0} 即可。
值得討論的一點是,在這種方法的漏洞利用中,很難在直接表單類型的POST的數(shù)據(jù)中使用,這是為什么呢,這個和HTTP協(xié)議有關。首先,我們看一下,在POST給服務器的數(shù)據(jù)中,有幾種類型,也就是HTTP header中的Content-Type:
application/x-www-form-urlencoded multipart/form-data application/json application/xml
第一個application/x-www-form-urlencoded,是一般表單形式提交的content-type第二個,是包含文件的表單。第三,四個,分別是json和xml,一般是js當中上傳的.
但是因為在直接的POST的payload當中是無法區(qū)分字符串和數(shù)字的,因為在其中并沒有引號出現(xiàn),舉一個抓包的例子
可以看到,payload是放在http包的最后面的,而且都是以沒有引號的形式傳遞的,并沒有辦法區(qū)分到底是字符串還是數(shù)字。因此,PHP將POST的數(shù)據(jù)全部保存為字符串形式,也就沒有辦法注入數(shù)字類型的數(shù)據(jù)了而JSON則不一樣,JSON本身是一個完整的字符串,經(jīng)過解析之后可能有字符串,數(shù)字,布爾等多種類型。
2. strcmp漏洞
注:這一個漏洞適用與5.3之前版本的php
我們首先看一下這個函數(shù),這個函數(shù)是用于比較字符串的函數(shù)
int strcmp ( string $str1 , string $str2 )
參數(shù) str1第一個字符串。str2第二個字符串。如果 str1 小于 str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果兩者相等,返回 0。
可知,傳入的期望類型是字符串類型的數(shù)據(jù),但是如果我們傳入非字符串類型的數(shù)據(jù)的時候,這個函數(shù)將會有怎么樣的行為呢?實際上,當這個函數(shù)接受到了不符合的類型,這個函數(shù)將發(fā)生錯誤,但是在5.3之前的php中,顯示了報錯的警告信息后,將return 0 !!!! 也就是雖然報了錯,但卻判定其相等了。
這對于使用這個函數(shù)來做選擇語句中的判斷的代碼來說簡直是一個致命的漏洞,當然,php官方在后面的版本中修復了這個漏洞,使得報錯的時候函數(shù)不返回任何值。但是我們?nèi)匀豢梢允褂眠@個漏洞對使用老版本php的網(wǎng)站進行滲透測試??匆欢问纠a:
對于這段代碼,我們能用什么辦法繞過驗證呢, 只要我們$_POST['password']是一個數(shù)組或者一個object即可,但是上一個問題的時候說到過,只能上傳字符串類型,那我們又該如何做呢。
其實php為了可以上傳一個數(shù)組,會把結尾帶一對中括號的變量,例如 xxx[]的name(就是$_POST中的key),當作一個名字為xxx的數(shù)組構造類似如下的request,即可使得上述代碼繞過驗證成功。
3 總結:
這一類型的漏洞的特點主要就是利用PHP中 的類型特性來繞過驗證。由于 == 和 === 有著明顯的區(qū)分,因此,估計短期內(nèi)PHP的作者并不會調(diào)整對于這兩個符號的策略。
而對于開發(fā)市場而言,隨著培訓機構的增多,后端程序員尤其是php后端程序員的門檻越來越低,其水平必定也是良莠不齊,這些二把刀程序員可能帶來更多的此類對于特性的不當使用導致的漏洞,因此這類漏洞仍然是非常具有利用價值的。
總結一下,對于開發(fā)人員,需要堅持幾個習慣:
認真閱讀PHP manual,不能以其他語言的經(jīng)驗來完全帶入php進行編碼
在使用一個運算符或者函數(shù)之前,詳細的查看文檔,搞清楚函數(shù)在什么樣的條件下,會有怎樣的行為。
記住保證安全的幾句箴言:任何用戶輸入都是不可信的!對于web應用來說,前端(瀏覽器端)的安全限制只能起到防止一般用戶的誤輸入行為,完全不可能對于黑帽子的行為有任何的防御作用。
因此,在防御這個漏洞的過程中,保證幾件事情:
在所有可能的地方,都使用===來代替==
對于用戶輸入做過濾和類型檢查
盡量使用新版本的php,apache
基本上就可以完美的防御這一類的漏洞。
而對于滲透測試人員,在代碼審計的過程中,對于有==,strcmp的比較也應極為敏感 。在黑盒滲透的時候也可以對于代碼進行猜測,結合信息搜集過程中的一些版本特性,利用這些漏洞來繞過驗證。
轉載請注明本頁網(wǎng)址:
http://www.snjht.com/jiaocheng/77.html