php弱類型問題總結

e安全 發佈 2020-03-09T07:31:56+00:00

No.1 聲明由於傳播、利用此文所提供的信息而造成的任何直接或者間接的後果及損失,均由使用者本人負責,雷神眾測以及文章作者不為此承擔任何責任。雷神眾測擁有對此文章的修改和解釋權。如欲轉載或傳播此文章,必須保證此文章的完整性,包括版權聲明等全部內容。

No.1 聲明


由於傳播、利用此文所提供的信息而造成的任何直接或者間接的後果及損失,均由使用者本人負責,雷神眾測以及文章作者不為此承擔任何責任。

雷神眾測擁有對此文章的修改和解釋權。如欲轉載或傳播此文章,必須保證此文章的完整性,包括版權聲明等全部內容。未經雷神眾測允許,不得任意修改或者增減此文章內容,不得以任何方式將其用於商業目的。

No.2 弱類型介紹

php是特別方便的一個語言,在申明一個變量的時候,並不需要指明它保存的數據類型,但是由於其自身弱類型語言的特性以及內置函數對於傳入參數的鬆散處理,會帶來很多的安全問題,這裡將進行簡要介紹。弱類型語言對變量的數據類型沒有限制,可以將變量賦值成其他類型變量,同時變量可以轉換成任意其他類型的數據。

No.3 弱類型會產生的問題

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

==比較兩個變量的值,不比較數據類型。

===比較兩個變量的值和類型。

類型轉換問題

類型轉換是無法避免的問題。例如需要將GET或者是POST的參數轉換為int類型,或者是兩個變量不匹配的時候,PHP會自動地進行變量轉換。但是PHP是一個弱類型的語言,導致在進行類型轉換的時候會存在很多意想不到的問題。

var_dump("abc" == 0); //bool(true)var_dump("1ab" == 1); //bool(true)var_dump("ab1" == 1); //bool(false)var_dump("ab0" == 0); //bool(true)

1.int轉string:

$var = 5;方式1:$item = (string)$var;方式2:$item = strval($var);

2.string轉int:intval()函數

var_dump(intval('2')) //2var_dump(intval('3abcd')) //3var_dump(intval('abcd')) //0

在intval()轉換的時候,會將從字符串的開始進行轉換知道遇到一個非數字的字符。即使出現無法轉換的字符串,intval()不會報錯而是返回0。

3.Hash比較

"0e132456789"=="0e7124511451155" //true"0e123456abc"=="0e1dddada" //false"0e1abc"=="0" //true

在進行比較運算時,如果遇到了0e\d+這種字符串,就會將這種字符串解析為科學計數法。所以上面例子中2個數的值都是0因而就相等了。如果不滿足0e\d+這種模式就不會相等。

4.十六進位轉換

"0x1e240"=="123456" //true"0x1e240"==123456 //true"0x1e240"=="1e240" //false

當其中的一個字符串是0x開頭的時候,PHP會將此字符串解析成為十進位然後再進行比較,0x1240解析成為十進位就是123456,所以與int類型和string類型的123456比較都是相等。

5.函數鬆散性

  • switch

如果switch是數字類型的case的判斷時,switch會將其中的參數轉換為int類型。

$abc = "1ab";switch ($abc) {case 1:echo "this is 1."; //輸出break;case 2:echo "this is 2.";break;case 3:echo "this is 3.";break;}

$abc = "abc";switch ($abc) {case 0:echo "this is 1."; //輸出break;case 1:echo "this is 2.";break;case 2:echo "this is 3.";break;}

這裡再說一下switch函數沒有break的情況,它會一直向下執行。

$abc = "abc";switch ($abc) {case 0:echo "this is 1."; //輸出case 1:echo "this is 2."; //輸出case 2:echo "this is 3."; //輸出}

  • md5

0e開頭的全部相等(繞過==判斷),兩個字符串轉換成MD5值時都是0e開頭,0e 純數字這種格式的字符串在判斷相等的時候會被認為是科學計數法的數字,先做字符串到數字的轉換。

var_dump(md5('240610708') == md5('QNKCDZO')); //bool(true)

純數字類:

2406107080e4620974319065090195629887368543142824220e9909955048216994945203569537345715794060e9723798328542952241180257482219032511470e17451050382393294236135320938411102421610e43587455848862589132486119810313208305260e91209595898548334699541406083215862642930e62274367115599573763966271849823027562690e25056688849747379872442679446224274355920e06769695232866973247549847234326535316020e87748752234154475802881061088532938674410e47100120130360254392114457026032954212010e70387033300223268123961885622034658147130e25863164565099966452170553712235248547800e50741906248988782708781573519539083362900e80762449895919041588124824527140116270630e48580568703443990593836270177547756350650e99821208994664096759945036116847905553610e64344221466099443013449246451254324535310e51231869908588163086189052609755796798200e87762201173022180346174018491555853935790e66435735538230580599276533702363765525010e16588670699748218787021557801571241299770e50000736104474780468212206087671975461970e91518857607246910145731567550276564861570e451569119711843337267091732412

大寫字母類:

QLTHNDT0e405967825401955372549139051580QNKCDZO0e830400451993494058024219903391EEIZDOI0e782601363539291779881938479162TUFEPMC0e839407194569345277863905212547UTIPEZQ0e382098788231234954670291303879UYXFLOI0e552539585246568817348686838809IHKFRNS0e256160682445802696926137988570PJNPDWY0e291529052894702774557631701704ABJIHVY0e755264355178451322893275696586DQWRASX0e742373665639232907775599582643DYAXWCA0e424759758842488633464374063001GEGHBXL0e248776895502908863709684713578GGHMVOE0e362766013028313274586933780773GZECLQZ0e537612333747236407713628225676NWWKITQ0e763082070976038347657360817689NOOPCJF0e818888003657176127862245791911MAUXXQC0e478478466848439040434801845361MMHUWUV0e701732711630150438129209816536

md5()中的需要是一個string類型的參數。但是當你傳遞一個array時,md5()`不會報錯,只是會無法正確地求出array的md5值,返回false,這樣就會導致任意2個array的md5值都會相等。(繞過===判斷)

$array1=array(1,2,3);$array2=array(4,5,6);var_dump(md5($array1)===md5($array2)) //true

  • sha1

sha1函數和md5函數一樣不能判斷數組的值。

$array1=[1,2,3];$array2=[4,5,6];var_dump(sha1($array1)===sha1($array2)); //true

  • strcmp

strcmp()函數在PHP官方手冊中的描述是int strcmp ( string $str1 , string $str2 ) ,需要給strcmp()傳遞2個string類型的參數。如果str1小於str2,返回-1,相等返回0,否則返回1。strcmp函數比較字符串的本質是將兩個變量轉換為ascii,然後進行減法運算,然後根據運算結果來決定返回值。

$array=[1,2,3];var_dump(strcmp($array,'123')); //null,如果是==比較的話,null就等於false

  • josn(這個不符合鬆散性)

json_decode()對 JSON 格式的字符串進行解碼

<?phpif (isset($_POST['message'])) {$message = json_decode($_POST['message']);$key ="*********";if ($message->key == $key) {echo "flag";}else {echo "fail";}}else{echo "~~~~";}?>

輸入一個json類型的字符串,json_decode函數解密成一個數組,判斷數組中key的值是否等於 $key的值,但是$key的值我們不知道,但是可以利用0和字符串==比較相等繞過。

6.最終payload為:message={"key":0}

  • in_array/array_search

在PHP手冊中,in_array()函數的解釋是bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] ) ,如果strict參數沒有提供,那麼in_array就會使用鬆散比較來判斷$needle是否在$haystack中。當strince的值為true時,in_array()會比較needls的類型和haystack中的類型是否相同。

$array=[0,1,2,'3'];var_dump(in_array('abc', $array)); //truevar_dump(in_array('1bc', $array)); //true

可以看到上面的情況返回的都是true,因為'abc'會轉換為0,'1bc'轉換為1。

  • is_numeric

is_numeric() 函數用於檢測變量是否為數字或數字字符串。在這裡我們的payload需要是一個大於1336的數字後面加上非數字即可(%00也可以),如1337+,他不是數字或數字字符串,但是與數字1336進行比較時,又會把前面的1337當成數字來運算。

<?phperror_reporting(0);$flag = "flag{test}";$temp = $_GET['password'];is_numeric($temp)?die("no numeric"):NULL;if($temp>1336){echo $flag;}?>

  • intval

Intval()函數最大的值取決於作業系統。32 位系統最大帶符號的 integer 範圍是 -2147483648 到 2147483647。64 位系統上,最大帶符號的 integer 值是 9223372036854775807。一個數值超出限制的話依然會返回最大值

echo intval('9223372036854775807000'); //輸出2147483647

No.4 總結

弱類型確實提升了程式設計師書寫代碼的效率,但是也帶來了嚴重的安全問題。在使用PHP的比較時,注意合理利用鬆散比較與嚴格比較的區別和規範傳入的參數類型,防止漏洞的出現。

安全服務部華北大區致力於天津、山西、內蒙以及河北四地安全服務業務支撐,主要提供滲透測試、紅藍對抗、溯源取證、安全諮詢等領域的安全服務業務。擁有專業級安全技術、應急響應以及豐富的攻防演練和紅藍對抗經驗,致力於打造一個規範、安全、高效、誠信、專業的安全服務團隊。

本文轉載自雷神眾測

關鍵字: