この記事は主に、PHP の文字オフセット機能によって引き起こされるバイパス脆弱性に関する関連情報を紹介します。この記事では、脆弱性の発生状況を詳細に紹介するだけでなく、より重要なことに、確実な参考情報と修復方法も紹介します。すべての人にとっての価値を学び、それがすべての人に役立つことを願っています。
phpの文字オフセット機能
phpの文字列には、配列のような値を取ることもできる非常に興味深い機能があります。
$test = "hello world"; echo $test[0];
最終結果はhです。
しかし、上記の機能は時々予期せぬ効果をもたらします。以下のコードを見てください
$mystr = "hello world"; echo $mystr["pass"];
上記のコードの出力結果はなぜでしょうか?実際、他の多くの言語と同様に、PHP の文字列は配列と同じように添字を使用して値を取得できます。 $mystr["pass"] のパスは暗黙的に 0 に変換されるため、$mystr[0] の出力結果は最初の文字 h になります。
同様に、次のコードを試してみると:
$mystr = "hello world"; echo $mystr["1pass"];
出力結果は e です。1pass は暗黙的に 1 に変換されるため、$mystr[1] の出力結果は 2 番目の文字 e になります。
文字の特性に起因する脆弱性
phpspy2006 でのログイン判定に使用したコードは次のとおりです。
$admin['check'] = "1"; $admin['pass'] = "angel"; ...... if($admin['check'] == "1") { .... }
上記の機能を使用すると、このような検証ロジックは簡単にバイパスできます。 $admin は最初は配列型として定義されていないため、文字列を指定して phpsyp.php?admin=1abc を送信すると、PHP は文字列 1xxx の最初のビットを取得し、if 条件の判断を正常にバイパスします。
上記のコードはコード スニペットで、次のコードは完全なロジック コードです。これは php4fun の質問 5 からのもので、非常に興味深いものです。
<?php # GOAL: overwrite password for admin (id=1) # Try to login as admin # $yourInfo=array( //this is your user data in the db # 'id' => 8, # 'name' => 'jimbo18714', # 'pass' => 'MAYBECHANGED', # 'level' => 1 # ); require 'db.inc.php'; function mres($str) { return mysql_real_escape_string($str); } $userInfo = @unserialize($_GET['userInfo']); $query = 'SELECT * FROM users WHERE id = \'' . mres($userInfo['id']) . '\' AND pass = \'' . mres($userInfo['pass']) . '\';'; $result = mysql_query($query); if (!$result || mysql_num_rows($result) < 1) { die('Invalid password!'); } $row = mysql_fetch_assoc($result); foreach ($row as $key => $value) { $userInfo[$key] = $value; } $oldPass = @$_GET['oldPass']; $newPass = @$_GET['newPass']; if ($oldPass == $userInfo['pass']) { $userInfo['pass'] = $newPass; $query = 'UPDATE users SET pass = \'' . mres($newPass) . '\' WHERE id = \'' . mres($userInfo['id']) . '\';'; mysql_query($query); echo 'Password Changed.'; } else { echo 'Invalid old password entered.'; }
この質問はネット上では最終的な答えしか出ず、原理は説明されていないか、詳しく説明されていません。実はその原理は、上で述べたPHPの特性にあります。
質問の要件は非常に簡単で、管理者のパスワードを変更するというものです。管理者の ID は 1 です。次の質問について考える必要があります:
更新時に ID を 1 に変更する方法
$userInfo['pass'] = $newPass; このコード行はなぜ表示されるのですか? if 判定ステートメントは
にそのようなコードがあります。これら 2 つの問題を解決した後、最終的な解決策も得られます。 ID 8 のユーザーのパスワードを 8 に変更し、次に userInfo 文字列 '8' を渡してクエリ保護を突破し、最後に $userInfo['pass'] = $newPass を使用して ID を 1 に変更します。
最終的なペイロードは次のとおりです。
最初の送信、index.php?userInfo=a:2:{s:2:"id";i:8;s:4:"pass";s:12 :" MAYBECHANGED";}&oldPass=MAYBECHANGED&newPass=8、目的は ID 8 のユーザーのパスワードを 8 に変更することです
2 回目の送信、index.php?userInfo=s:1:"8";&oldPass=8&newPass =1 , このようにして、シリアル化された $userInfo は文字列 '8' ($userInfo = '8') を取得するため、データベース クエリの検証に合格できます。後続の if 検証も、このコード行 $userInfo['pass'] = $newPass; を通過できます。$newpass の値が 1 であるため、上記のコードは $userInfo['pass'] = 1; になります。 $userInfo 文字列型のため、最終結果は $userInfo='1' となり、最終的に ID 1 のユーザーのパスワードを更新できます。
修正方法
この種の脆弱性の修復方法も非常に簡単で、事前にデータ型を定義し、使用する際に、使用されるデータ型が予想されるものと一致しているかどうかを確認するのが最善です。そうしないと、前述のバイパスの問題が発生します。同時に、入力を制御し、入力データをチェックし、不用意に使用しないようにする必要があります。
関連する推奨事項:
mysql のページネーション時の過剰なオフセットを含む SQL 最適化の例の共有
の style.width と offsetWidth の違いの詳細な説明js
以上がPHPのオフセット機能によって引き起こされる脆弱性を回避するための解決策の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。