PHP弱類型總結
1. 什么是弱類型
強類型語言是一種強制類型定義的語言,即一旦某一個變量被定義類型,如果不經強制轉換,那么它永遠就是該數據類型。代表有Java、.net、Python、C++等語言。
弱類型語言是一種弱類型定義的語言,某一個變量被定義類型,該變量可以根據環境變化自動進行轉換,不需要經過現行強制轉換。代表有VB,PHP,JavaScript等語言。
簡單舉一個例子:
1 </p><p style="margin: 0px 0px 10px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;clear: both;min-height: 1em;white-space: normal;">2 var A<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p><p style="margin: 0px 0px 10px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;clear: both;min-height: 1em;white-space: normal;">3 var B<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p><p style="margin: 0px 0px 10px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;clear: both;min-height: 1em;white-space: normal;">4 A=5<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p><p style="margin: 0px 0px 10px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;clear: both;min-height: 1em;white-space: normal;">5 B="5"<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p><p style="margin: 0px 0px 10px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;clear: both;min-height: 1em;white-space: normal;">6 sumA=A+B<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p><p style="margin: 0px 0px 10px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;clear: both;min-height: 1em;white-space: normal;">7 sumB=A-B<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p><p style="margin: 0px 0px 10px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;clear: both;min-height: 1em;white-space: normal;">

sumA=55,系統默認+字符連接符,將A轉化為字符串類型;而sumB=0;系統認為-是算數運算符,從而將B轉化為int類型,所以sum為5-5=0;
2. PHP中“==”與“===”
php當中有兩種比較符號==與===。
1 2 $a==$b; 3 $a===$b; 4 ?>
在進行===符號比較時,會先判斷兩種字符串類型是否相同,再比較值是否相同。
在進行==符號比較時,會將字符串類型轉換成相同,再比較值是否相同。
1
2 var_dump("admin"==0);//true
3 var_dump("1admin"==1);//true
4 var_dump("admin1"==1)//true
5 var_dump("admin1"==0)//true
6 var_dump("0e123456"=="0e456789");//true
7 ?>
在進行"admin"==0 比較的時候,會將admin轉化成數值,強制轉化,由于admin是字符串,轉化的結果是0自然和0相等。
當一個字符串被當作數值來取值,其結果和類型如下:如果該字符串沒有包含'.','e','E'并且其數值在整型的范圍之內該字符串被當作int來取值,其他所有情況都被作為float來取值,該字符串的開始部分決定了它的值,如果該字符串以合法的數值開始,則使用該數值,否則其值為0。因此"1admin"==1的結果為true,"admin1"==1的結果為false。
在進行"0e123456"=="0e456789"相互比較的時候,會將0e這類字符串識別為科學技術法的數字,0的無論多少次方都是零,所以相等。
3. md5繞過(hash比較缺陷)
以BugKu中的前女友題為例:
1
2 if(isset($_GET['v1']&&isset($_GET['v2'])&&isset($_GET['v3'])){
3 $v1=$_GET['v1'];
4 $v2=$_GET['v2'];
5 $v3=$_GET['v3'];
6 if($v1!=$v2&&md5($v1)==md5($v2)){
7 if(!strcmp($v3,$flag)){
8 echo $flag;
9 }
10 }
11 }
12 ?>
這道題的關鍵是第6行,$v1弱不等于$v2并且$v1的md5值弱等于$v2的md5值
這里構造的思路也很簡單,就是想辦法使得md5($v1)與md5($v2)的值是以0e開頭的字符串,在進行==符號比較的時候,PHP會0e這類字符串識別為科學技術法的數字,0的無論多少次方都是零,因此可以達到md5繞過的效果。
常見的字符串的md5值以0e開頭的有QNKCDZO、s878926199a、s155964671a、s214587387a、s214587387a。
那么這題的WriteUp也就出來了
http://114.67.246.176:11589/?v1=QNKCDZO&v2=s878926199a&v3[]=1
4. switch繞過
以BugKu中的前女友題為例:
1
2 $a="3ctf";
3 switch($a){
4 case 1;
5 echo"fail1";
6 break;
7 case 2;
8 echo"fail2";
9 break;
10 case 3;
11 echo'flag{xxxxxx}';//結果輸出success;
12 break;
13 case 4;
14 echo"fail4";
15 break;
16 default;
17 echo"failall";
18 break;
19 }
20 ?>
同樣是弱類型的利用,當在switch中進行判斷時,將$a強制轉換成整型,也就是3,正好與case 3匹配上了,輸出flag{xxxxx}。
5. Json繞過
if (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,如果相等,則輸出flag的值。這里$key我們不知道,但是程序使用了==,我們就可以使用0="admin"這種形式進行繞過,因此最終的payload:message={"key":0}
6. strcmp函數繞過
strcmp(str1,str2)函數的作用是比較字符串。
如果 str1 小于 str2 返回 < 0;如果 str1 大于 str2 返回 > 0;如果兩者相等,返回 0。
1
2 $password="***************"
3 if(isset($_POST['password'])){
4 if(strcmp($_POST['password'],$password)==0){
5 echo"Right!!!login succsess";n
6 exit();
7 }else{
8 echo"Wrong password..";
9 }
10 ?>
這里程序的邏輯是,通過strcmp()函數比較POST方法傳遞的password的值與$password,如果strcmp()函數的返回值弱等于0,那么登錄成功。
這里構造的思路是false==0,當strcmp()函數當中的str1與str2不為字符串時,strcmp()函數的返回值為布爾類型的false,那么false==0的結果是true,就可以達到繞過的效果,因此這里的payload:password[]=xxx(任意)。
7. “array_search"與is_array"繞過
is_array()函數會判斷傳入的數組是否是一個數組。如果是,返回true,反之false。
array_search()函數會在數組中搜索某個鍵值,并返回對應的鍵名。如果找到返回鍵名,反之false。這邊要注意的是array_search()函數搜索鍵值的時候是使用==進行比較。
1
2 if(!is_array($_GET['test'])){
3 exit();
4 }
5 $test=$_GET['test'];
6 for($i=0;$i
7 if($test[$i]==="admin"){
8 echo"error";
9 exit();
10 }
11 $test[$i]=intval($test[$i]);
12 }
13 if(array_saerch("admin",$test)===o){
14 echo"flag";
15 }else{
16 echo"false";
17 }
18 ?>
這里程序的邏輯是,首先判斷GET方法傳遞的test是否為數組,然后通過for循環遍歷數組當中每個值并判斷是否強等于字符串admin,并且將值轉換為整型。最后使用array_search函數在$test數組搜尋是否有鍵值弱等于字符串admin,如果有的話返回其鍵名,最后判斷鍵名強等于0才輸出flag。
因此構造思路是"admin"==0,也就是說傳遞的數組第一個鍵值必須是0(無論字符串還是整型,因為存在intval函數強制轉換),那么payload:test[]=0就可以繞過。
8. 總結
PHP是最好的語言,而且使用很方便,但是特性是弱類型,以及內置函數對于傳入參數的松散處理會導致存在許多安全問題,所以要特別注意。