PHP字串offset取值特性

bypass發表於2017-11-28

  在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(); } ?>

 

參考文件:

https://github.com/80vul/webzine/blob/master/webzine_0x06/PSTZine_0x06_0x03.txt


相關文章