php是一門弱類型的語言,它不會嚴格檢驗變量類型,變量可以不顯示地聲明其類型,而是在運行期間直接賦值。
在php中比較是否相等有兩種符號:==和===。
其中==在比較時會將不同類型的變量或值轉換為相同類型再進行比較。
而===則直接比較類型是否相同,如果同類型,再比較值。
那麼php弱類型這裡的「弱」,指的不是某個類型有什麼問題,而是整個php語言中某些函數在處理賦值、字符串比較、變量比較的過程中對類型似乎並不關心,弱化了類型帶來的影響,在使用某個變量時不需要我們定義變量的類型,而是根據內容判斷這是什麼類型,從而導致了各種漏洞的發生。例如:
<?phpvar_dump("a"==0); //truevar_dump("1a"==1); //truevar_dump("a1"==1); //falsevar_dump("a1"==0); //truevar_dump("0e123456"=="0e234567"); //truevar_dump(0=="1a"); //false?>輸出結果是:
bool(true)bool(true)bool(false)bool(true)bool(true)bool(false)出現上述判斷輸出的原因是,在php中當一個字符串被當作一個數值來取值時,如果該字符串沒有包含'.','e','E',並且其數值值在整形的範圍之內時,該字符串被當作int來取值,其他所有情況下都被作為float來取值,而該字符串的開始部分決定了它的值,如果該字符串以合法的數值開始,則使用該數值,否則其值為0。
所以在上面的情況中,1a轉換為1,a1轉換為0,而"0e123456"=="0e234567"相互比較的時候,會將0e這類字符串識別為科學計數法的數字,0的無論多少次方都是零,所以相等。這就是常說的0e繞過的原理。
「MD5,即消息摘要算法(英語:MD5 Message-Digest Algorithm)。是一種被廣泛使用的密碼散列函數,將數據(如一段文字)運算變為另一固定長度值,是散列算法的基礎原理,可以產生出一個128位(16位元組)的散列值(hash value),用於確保信息傳輸完整一致。
顯然128位不足以把世界上所有消息的摘要毫不重複的計算出來,當然現在16位元組(128位)、32位元組(256位)的md5也都有,選擇位數多的方式可以在一定程度上減少硬碰撞(collision)的可能性。
<?php$flag = 'ook!';$a = $_GET['a'];if ($a != 'QNKCDZO' && md5($a) == md5('QNKCDZO')) { echo $flag;}else{echo('你的答案不對0.0');}上面這段代碼中就是上述0e開頭的所有字串都被認為是0,所以我們先看看md5('QNKCDZO')的結果是0e830400451993494058024219903391,那麼所有0e開頭的md5串都可以滿足上面的條件。常用的0e開頭md5值的字符串有:
QNKCDZO
0e830400451993494058024219903391
240610708
0e462097431906509019562988736854
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
在php中的hash函數md5、sha1等處理中若傳入一個數組的值,則會報錯返回NULL,而返回的值在類型和內容上都是相同的,所以可以用來繞過某些兩邊參數可控的場景,上面只能控制一邊的值傳入,所以數組類型不適用。
<?php$flag = "ook!";$a = $_GET['a'];$b = $_GET['b'];if ($a != $b && md5($a) === md5($b)) //這裡==也可以使用數組繞過。 echo $flag;?>上述的例子中傳入?a[]=a&b[]=b即可滿足既不相等,md5後又相等的條件,雖然報錯,但仍然輸出了正確的值。具體輸出為:
Warning: md5() expects parameter 1 to be string, array given in 1.php on line 5Warning: md5() expects parameter 1 to be string, array given in 1.php on line 5ook!php在處理傳入的json串時使用json_decode將其解碼,再進行比較時,我們不需要知道比較字串的內容,也可以利用字符串與0比較為真的特點繞過。
<?php$flag = 'ook!';$a = $_GET['a'];$b = json_decode($a);echo $b->abc;var_dump($b->abc == $flag);if ($b->abc == $flag) echo $flag;else echo "error!!";?>當傳入?a={"abc":0}時,分別輸出:0、bool(true)和00k。注意這裡的{"abc":0},0是數字,而加雙引號{"abc":"0"}之後兩邊都是字符,就不相等了。
原理都是類型轉換的問題,函數的原型為: mixed array_search ( mixed $needle , array $haystack [, bool $strict = false ] )。
其中$needle,$haystack必需,$strict可選 函數判斷$haystack中的值是存在$needle,存在則返回該值的鍵值(數組的下標,例如該值在第一位返回0,第二位返回1),第三個參數默認為false,如果設置為true則會進行嚴格過濾(帶類型的比較)。
<?php$a = array(0,1,2,3);var_dump(array_search("a",$a));var_dump(array_search("1a",$a));var_dump(array_search("2a",$a));var_dump(array_search("1a",$a,true));?>結果為:
int(0) int(1)int(2)bool(false)總結
從上面我們可以看出,所有繞過的形式都是基於弱類型的比較,或值對於不合規參數類型的錯誤處理,數組與字符串、字符串與整數等等情形,我們不能保證每個用戶都乖乖輸入我們想要的值,因此在php中限定用戶輸入的類型和值就顯得尤為重要。
原文來源:CSDN AFCC_|侵刪
中電運行是專業專注培養能源企業IT工匠和提供IT整體解決方案的服務商,也是能源網際網路安全專家。
為方便大家溝通,中電運行開通「中電運行交流群」,誠摯歡迎能源企業和相關人士,以及對網絡安全感興趣的群體加入本群,真誠交流,互相學習。想加入我們就給我們留言吧。