在PHP的代碼基礎上,PHP字符串offset取值特性,可以拿來利用,給PHP應用程序帶來安全風險。
在PHP中,可以像操作數組一樣操作字符串,字符串中的字符可以用類似數組結構中的方括號包含對應的數字索引的形式來進行查找和修改,例如 $test[0]。當然 字符串中字符的排列也是從零開始的。如果需要操作的字符多余一個的話,就考慮使用函數 substr()和 substr_replace()吧。
代碼示例一:
<?php $test = "Hello World"; echo $test[0]; //輸出H echo "<br/>"; echo $test[1]; //輸出e ?>
Tips:$test[0] 方括號中的數字超出范圍將會產生空白。 非整數類型被轉換成整數,非法類型會產生一個 E_NOTICE級別錯誤, 負數在寫入時會產生一個E_NOTICE,但讀取的是空字符串。
代碼示例二:
<?php $test = "Hello World"; echo $test[0]; //輸出H echo "<br/>"; echo $test['id']; //輸出H ?>
可以看出,$test[0]等價於$test['id']
代碼片段可以看出,對於$test['id']這種形式的字符串,在offset取值時鍵值會被轉換為整形,也就是等同於$test[0]這種形式。
漏洞場景:
在某平台曾經遇到某道代碼審計的題目,大致還原代碼如下:
示例代碼:
<?php ini_set("display_errors", "On"); error_reporting(0); foreach (array('_COOKIE','_POST','_GET') as $_request) { foreach ($$_request as $_key=>$_value) { $$_key= $_value; } } //$userinfo=333333 $userinfo["username"] = $username; //==> $userinfo[0]=a 賦值以后 $userinfo=a33333 $userinfo["password"] = $password; //==> $userinfo[0]=1 賦值以后 $userinfo=133333 $_SESSION["userinfo"] = $userinfo; var_dump($_SESSION); echo "<br/>"; $userinfo=$_SESSION["userinfo"]; //輸出 array(1) { ["userinfo"]=> string(6) "133333" } if($userinfo["id"] == 1) { echo "flag{xxx}"; die(); } ?>
漏洞分析:
只有當$userinfo["id"] == 1時,才能得到flag,$userinfo由$_SESSION["userinfo"]賦值而來,$_SESSION["userinfo"]又由$userinfo賦值,只要通過變量覆蓋將$userinfo覆蓋為值1xxxx即可,具體參數流程詳見示例代碼。原題還有其他條件,只能覆蓋$_SESSION來解題。上面自己還原的代碼還可以用變量覆蓋直接解題。
<?php
//?userinfo[id]=1 ini_set("display_errors", "On"); error_reporting(0); foreach (array('_COOKIE','_POST','_GET') as $_request) { foreach ($$_request as $_key=>$_value) { $$_key= $_value; } } var_dump($_GET); //array(1) { ["userinfo"]=> array(1) { ["id"]=> string(1) "1" } } echo "<br/>"; if($userinfo["id"] == 1) { echo "flag{xxx}"; die(); } ?>
關於我:一個網絡安全愛好者,致力於分享原創高質量干貨,歡迎關注我的個人微信公眾號:Bypass--,瀏覽更多精彩文章。
參考文檔:
https://github.com/80vul/webzine/blob/master/webzine_0x06/PSTZine_0x06_0x03.txt