この記事で共有した内容は、php の弱い型変換に関するもので、非常に参考になる内容です。困っている友人のお役に立てれば幸いです。
最近の CTF コンテストで PHP の弱い型に関する問題が何度も出題されましたので、PHP の弱い型に関する知識とそれを回避する方法をまとめたいと思います
php には 2 つの比較記号 == と ===
1 <?php 2 $a = $b ; 3 $a===$b ; 4 ?>
=== があります。比較するとき、まず 2 つの文字列の型が一致するかどうかを判断します。が等しい場合、比較
== 比較する場合、文字列型は最初に同じ型に変換されてから比較されます。
如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换成数值并且比较按照数值来进行
ここでは、 value は文字列と比較されます。比較する場合、文字列は数値に変換されます。
1 <?php 2 var_dump("admin"==0); //true 3 var_dump("1admin"==1); //true 4 var_dump("admin1"==1) //false 5 var_dump("admin1"==0) //true 6 var_dump("0e123456"=="0e4456789"); //true 7 ?> //上述代码可自行测试
1 上記のコードを確認してください。「admin」==0 比較すると、admin は数値に変換されます。値、強制変換、admin は文字列であるため、変換の結果は、0 は当然 0
2 "1admin"==1 と等しくなります。比較すると、1admin は数値に変換され、結果は次のようになります。 1 ですが、「admin1」==1 はエラーに相当します。つまり、「admin1」は 0 に変換されます。なぜですか? ? 3 "0e123456"=="0e456789" 0eなどの文字列は科学技術法で数値として認識されます。0は何度上げてもゼロなので等しいです
上記の質問については、PHP マニュアルを確認しました。
文字列を数値として扱う場合、結果と型は次のようになります。 '.'、'e'、'E'を含まず、その数値が整数の範囲内である
文字列はintとして扱われ、値が取得されます。それ以外の場合はfloatとして扱われます。文字列の開始部分によって、文字列が有効な数値で始まる場合はその値が使用され、それ以外の場合は値が 0 になります。
1 <?php 2 $test=1 + "10.5"; // $test=11.5(float) 3 $test=1+"-1.3e3"; //$test=-1299(float) 4 $test=1+"bob-1.3e3";//$test=1(int) 5 $test=1+"2admin";//$test=3(int) 6 $test=1+"admin2";//$test=1(int) 7 ?>
これは、「admin1」==1 =>False
md5 バイパス (ハッシュ比較の欠陥)
の理由を説明しています。1 <?php 2 if (isset($_GET['Username']) && isset($_GET['password'])) { 3 $logined = true; 4 $Username = $_GET['Username']; 5 $password = $_GET['password']; 6 7 if (!ctype_alpha($Username)) {$logined = false;} 8 if (!is_numeric($password) ) {$logined = false;} 9 if (md5($Username) != md5($password)) {$logined = false;} 10 if ($logined){ 11 echo "successful"; 12 }else{ 13 echo "login failed!"; 14 } 15 } 16 ?>
質問の主な考え方は、文字列と数値型を入力することであり、それらの md5 値が等しい場合、次のステートメントを正常に実行できます。
上で述べた 0e で始まる md5 文字列 私は以前そこにいたことがありますが、0e は比較するときに科学表記として扱われるため、0e の後に何が来ても 0 の累乗は 0 です。 md5('240610708') == md5('QNKCDZO')正常にバイパスされました!
QNKCDZO 0e830400451993494058024219903391 s878926199a 0e545993274517709034328855841020 s155964671a 0e342768416822451524974117254469 s214587387a 0e848240448830537924465865611904 s214587387a 0e848240448830537924465865611904 s878926199a 0e545993274517709034328855841020 s1091221200a 0e940624217856561557816327384675 s1885207154a 0e509367213418206700842008763514
json bypass
<?php 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 の値と等しいかどうかを判断しますが、$key の値はわかりません。ただし、形式 0=="admin" を使用してバイパスできます。 it
Final payload message={"key":0}
array_search is_array bypass
1 <?php 2 if(!is_array($_GET['test'])){exit();} 3 $test=$_GET['test']; 4 for($i=0;$i<count($test);$i++){ 5 if($test[$i]==="admin"){ 6 echo "error"; 7 exit(); 8 } 9 $test[$i]=intval($test[$i]); 10 } 11 if(array_search("admin",$test)===0){ 12 echo "flag"; 13 } 14 else{ 15 echo "false"; 16 } 17 ?>
上記は私が書いたものです、最初に受信した配列が配列であるかどうかを判断し、次に配列内の各値をループし、配列内の各値が admin と等しくないことを確認し、各値を int 型に変換してから、受信した配列に admin が含まれているかどうかを判断します。したがって、戻りフラグ
payload test[]=0 はバイパスできます
以下は、公式マニュアルの array_search
mixed array_search ( mixed $needle , array $haystack [, bool $strict = false ] )
$needle の紹介です。$haystack が必要です。$ strict はオプションです 関数判定$ ヘイスタックの値が $needle に存在します 存在する場合は、その値のキー値が返されます 3 番目のパラメータのデフォルトは false です true に設定すると、厳密なフィルタリングが実行されます
1 <?php 2 $a=array(0,1); 3 var_dump(array_search("admin",$a)); // int(0) => 返回键值0 4 var_dump(array_seach("1admin",$a)); // int(1) ==>返回键值1 5 ?>
array_search 関数は == に似ています。つまり、$ a=="admin" はもちろん $a=0 です。もちろん、3 番目のパラメータが true の場合、
strcmp をバイパスすることはできません。 Bypass php -v <5.3
1 <?php 2 $password="***************" 3 if(isset($_POST['password'])){ 4 5 if (strcmp($_POST['password'], $password) == 0) { 6 echo "Right!!!login success";n 7 exit(); 8 } else { 9 echo "Wrong password.."; 10 } 11 ?>
strcmp は 2 つの文字列を比較します。str1
$password の値がわかりません。質問には strcmp が判断する必要があります。受け入れられる値は、$password と等しい必要があります。strcmp によって渡される予期される型は文字列型です。何が起こるでしょうか。配列を渡すとどうなるでしょうか?
パスワード[]=xxxを渡しますが、関数の関係で回避できます 互換性のない型を受け取った場合はエラーになりますが、それでも正しいと判断されます等しい
ペイロード: パスワード[]=xxx
スイッチバイパス
1 <?php 2 $a="4admin"; 3 switch ($a) { 4 case 1: 5 echo "fail1"; 6 break; 7 case 2: 8 echo "fail2"; 9 break; 10 case 3: 11 echo "fail3"; 12 break; 13 case 4: 14 echo "sucess"; //结果输出success; 15 break; 16 default: 17 echo "failall"; 18 break; 19 } 20 ?>
この原理は前の原理と同じです同様です、詳細は説明しません
これらの PHP の弱い型は氷山の一角です。上記でコード監査の重要性が確認されました。
関連する推奨事項:
php キュー処理: PHP メッセージ キューの実装原理 (画像とテキスト)
以上がPHPでの弱い型変換の実装の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。