【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 <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。