1. 程式人生 > >【root-me CTF練習】Web伺服器安全-第二十一關- PHP register globals

【root-me CTF練習】Web伺服器安全-第二十一關- PHP register globals

解題思路:

本題考的是PHP變數覆蓋漏洞。那麼首先來了解下PHP的變數覆蓋。

變數覆蓋:

變數覆蓋指的是用我們自定義的引數值去替換程式原有的變數值,一般變數覆蓋漏洞需要結合程式的其它功能來實現完整的攻擊。經常導致變數覆蓋漏洞場景有:$$,extract()函式,parse_str()函式,import_request_variables()使用不當,開啟了全域性變數註冊等。

全域性變數覆蓋:

register_globals的意思就是註冊為全域性變數,所以當On的時候,傳遞過來的值會被直接的註冊為全域性變數直接使用,而Off的時候,我們需要到特定的數組裡去得到它。

<form action='' method='get'>
<input type='text' name='username' value='alex' >
<input type='submit' name='sub' value='sub'>
</form>

<?php
echo 'username::',$username;
echo '<br>sub::',$sub;
echo '<br>GET::';
print_r($_GET);
?>

#當register_globals = On的時候,程式執行提交輸出結果為:
username::alex  
sub::sub  
array ( [username] => alex [sub] => sub )

#當register_globals = Off的時候,程式執行提交輸出結果為:
username::  
sub::  
array ( [username] => alex [sub] => sub )  

extract()變數覆蓋:

int extract ( array &$array [, int $flags = EXTR_OVERWRITE [, string $prefix = NULL ]] )

從陣列中將變數匯入到當前的符號表,此函式會將鍵名當作變數名,值作為變數的值。

<?php
$auth = '0';
extract($_GET);
if($auth==1){
echo "private!";
}else{
echo "public!";
}
?>

如果GET傳入auth=1,這時就會把原有的$auth='0' 覆蓋成$auth=1。

當然還有其他型別的變數覆蓋,以後碰到在一一講解。

根據提示,開發人員留下了備份檔案:

那麼隨手測試.bak的備份檔案字尾名下載index.php原始碼。

<?php


function auth($password, $hidden_password){
    $res=0;
    if (isset($password) && $password!=""){
        if ( $password == $hidden_password ){
            $res=1;
        }
    }
    $_SESSION["logged"]=$res;
    return $res;
}



function display($res){
    $aff= '
	  <html>
	  <head>
	  </head>
	  <body>
	    <h1>Authentication v 0.05</h1>
	    <form action="" method="POST">
	      Password&nbsp;<br/>
	      <input type="password" name="password" /><br/><br/>
	      <br/><br/>
	      <input type="submit" value="connect" /><br/><br/>
	    </form>
	    <h3>'.htmlentities($res).'</h3>
	  </body>
	  </html>';
    return $aff;
}



session_start();
if ( ! isset($_SESSION["logged"]) )
    $_SESSION["logged"]=0;

$aff="";
include("config.inc.php");

if (isset($_POST["password"]))
    $password = $_POST["password"];

if (!ini_get('register_globals')) {
    $superglobals = array($_SERVER, $_ENV,$_FILES, $_COOKIE, $_POST, $_GET);
    if (isset($_SESSION)) {
        array_unshift($superglobals, $_SESSION);
    }
    foreach ($superglobals as $superglobal) {
        extract($superglobal, 0 );
    }
}

if (( isset ($password) && $password!="" && auth($password,$hidden_password)==1) || (is_array($_SESSION) && $_SESSION["logged"]==1 ) ){
    $aff=display("well done, you can validate with the password : $hidden_password");
} else {
    $aff=display("try again");
}

echo $aff;

?>

可看到這裡進行了全域性變數註冊:如果未開啟全域性變數註冊,就用extract函式進行接受各種HTTP方法傳參進行註冊全域性變數。

接下來,看判斷密碼的條件,輸入的密碼要和$hidden_password變數的值相同才行,那麼我們傳入一個$hidden_password覆蓋原有的$hidden_password變數值即可。

可通過GET、POST、cookie等等方式傳遞。

通過之後,為當前session進行logged=1設定。當然,也可以直接傳入_SESSION[logged]=1;。

那麼再次重新整理網頁,因為已滿足這個session條件,就會顯示flag。