這篇文章主要為大家介紹了關於由php中字符offset特徵造成的繞過漏洞的相關資料,文中不僅詳細介紹了該漏洞的形成,更重要的是介紹了修復方式,對大家具有一定的參考學習價值,需要的朋友們下面來一起看看吧。
php中的字元offset特性
#php中的字串存在一個非常有趣的特性,php中的字串也可以像數組一樣進行取值。
$test = "hello world"; echo $test[0];
最後的結果就是h。
但是上述的這種特性有時會有意想不到的效果,看下面這段程式碼
$mystr = "hello world"; echo $mystr["pass"];
上述的程式碼的輸出結果是h.這是為什麼呢?其實很簡單,跟很多其他的語言一樣,字串在php中也像陣列一樣可以使用下標取值。 $mystr["pass"]
中pass會被進行隱性型別轉換為0,這樣$mystr[0]
的輸出結果就是首字母h.
同樣地,如果嘗試如下的程式碼:
$mystr = "hello world"; echo $mystr["1pass"];
輸出結果就是e.因為1pass會被隱性型別轉換為1,$mystr[1]
的輸出結果就是第二個字母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的字元特性。
題目要求很簡單就是修改admin的密碼,admin的id為1。我們需要思考以下幾個問題:
如何在更新的時候將id修改為1
$userInfo['pass '] = $newPass;
這行程式碼有什麼作用,為什麼會在if判斷語句中存在這種的程式碼
想通了這兩個問題,那麼最終的解決方法也有了。將id為8的使用者的密碼修改為8,然後傳入一個userInfo的字串'8',突破查詢防護,最後利用$userInfo['pass'] = $newPass
將id修改為1。
最終的payload就是;
第一次提交, index.php?userInfo=a:2:{s:2:"id"; i:8;s:4:"pass";s:12:"MAYBECHANGED";}&oldPass=MAYBECHANGED&newPass=8
,目的是將id為8的使用者的密碼修改為8
#第二次提交,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的用戶的密碼了。
修復方式
這種漏洞的修復方式也很簡單,事先定義好資料型別同時在使用時最好檢查一下所使用的資料類型是否和預期的一致。否則就會出現上述的繞過的問題。同時要控制好輸入,對輸入的資料要檢查不要隨意使用。
以上是因php中offset字元繞過漏洞結果詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!