【root-me CTF练习】Web服务器安全-第二十一关- PHP register globals

靶机:http://challenge01.root-me.org/web-serveur/ch17/

解题思路:

本题考的是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源码。

http://challenge01.root-me.org/web-serveur/ch17/index.php.bak

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

猜你喜欢

转载自blog.csdn.net/a15803617402/article/details/83104406
今日推荐