phpcms/33578.html">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。我們需要思考以下幾個問題:
$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的用戶的密碼了。
修復方式
這種漏洞的修復方式也很簡單,事先定義好數據類型同時在使用時最好檢查一下所使用的數據類型是否和預期的一致。否則就會出現上述的繞過的問題。同時要控制好輸入,對輸入的數據要進行檢查不要隨意地使用。
參考
https://github.com/80vul/webzine/blob/master/webzine_0x06/PSTZine_0x06_0x03.txt
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對VeVb武林網的支持。
新聞熱點
疑難解答
圖片精選