0
回答
代码审计之伪全局机制使用不当导致的后果
利用AWS快速构建适用于生产的无服务器应用程序,免费试用12个月>>>   

正文

一:漏洞起因

首先我们先来看一段简单的伪全局机制代码

<?php
foreach($_REQUEST as $key => $value)
{
        $key=$value;


这段代码就是把$_REQUEST中的变量遍历循环,然后名字为key的变量,而这段代码没有做任何过滤,导致可以覆盖$_GET,$_POST,$_COOKIE,$_SESSION各种各样的全局变量
由于不少系统都是通过$_SESSION的值来判断是否登录的了,所以我们修改$_SESSION直接进入后台,比如下面这段代码

<?php
foreach($_REQUEST as $key => $value)
{
        $key=$value;
}
if($_SESSION['name']=='admin' && $_SESSION['id']=1)
{
        echo "welcome to admin";
}
else
{
        die("Please login");
}
?>

 


也就是从session中取出数据,并进行对应的判断如果true的话,就登录失败,false的话就提示登录,正常情况下是没有问题,因为session是不可控的,但是这里刚好伪全局机制,并且没做好过滤,导致可以直接覆盖全局SESSION来伪造登录




实现伪全局机制的,除了$$,还有extract函数和parse_str函数这些
而如果没有对名字进行限制的话,可以覆盖任意全局变量,会造成严重的后果
之前在审计一套系统的时候,发现他的实现伪全局机制没有多名字做过滤,导致可以覆盖任意全局变量,造成了特别严重的后果

if (!get_magic_quotes_gpc())
{
    if (isset($_REQUEST))
    {
        $_REQUEST  = addsl($_REQUEST);
    }
    $_COOKIE   = addsl($_COOKIE);
        $_POST = addsl($_POST);
        $_GET = addsl($_GET);
}
if (isset($_REQUEST)){$_REQUEST  = fl_value($_REQUEST);}
    $_COOKIE   = fl_value($_COOKIE);
    $_GET = fl_value($_GET);
@extract($_POST);
@extract($_GET);
@extract($_COOKIE);



就和上面的例子一样,由于未对变量名进行限制,导致可以覆盖各种全局变量,造成了各种各样了漏洞,比如上面的例子,很多web系统都是通过session来判断是否登录的了,由于遇到这种情况,直接覆盖了session就可以了,同时有一些全局变量本来是不可控的,比如session这种,由于它是不可控的,程序对他的过滤就比较少,对输入进行的过滤不足可能会导致sql注入,xss这些漏洞

二:全局变量覆盖导致的各种漏洞

2.1、验证码绕过
很多程序会把正确的验证码放在session里面,然后把post传输过来验证码和session里面的验证码比对,如果一样,就继续执行程序,由于session在这种情况下可以覆盖,所以修改成和post一样的就可以了,虽然这个基本没什么危害。。
比如这里

elseif($action=='add'){
        //是否开启留言本
        $is_use=$mysql->get_row("select is_book from ".DB_PRE."book_info where id=1");
        if(!$is_use){die("<script type=\"text/javascript\">alert('".$language['book_msg1']."');history.go(-1);</script>");}
        $book_code=$_POST['book_code'];
        if($book_code!=$_SESSION['code']){die("<script type=\"text/javascript\">alert('{$language['member_msg2']}');history.go(-1);</script>");}
        $book_name=fl_html($_POST['book_name']);
        $book_title=fl_html($_POST['book_title']);


直接把$_POST的值和$_SESSION做比较,不一样,就是验证码不正确,退出,不过$_SESSION可控,直接修改就可以了
  if($book_code!=$_SESSION['code']){die("<script type=\"text/javascript\">alert('{$language['member_msg2']}');history.go(-1);</script>");}



2.2、越权漏洞
前面说过了,很多web系统都是通过session来判断用户权限的,所以此处可以直接覆盖$_SESSION来造成这种越权,比如这系统的一处越权进后台
由于这里可以直接伪造session,所以可以直接伪造进后台

function is_login(){
        if($_SESSION['login_in']==1&&$_SESSION['admin']){
                if(time()-$_SESSION['login_time']>3600){
                        login_out();
                }else{
                        $_SESSION['login_time']=time();
                        @session_regenerate_id();
                }
                return 1;
        }else{
                $_SESSION['admin']='';
                $_SESSION['admin_purview']='';
                $_SESSION['admin_id']='';
                $_SESSION['admin_time']='';
                $_SESSION['login_in']='';
                $_SESSION['login_time']='';
                $_SESSION['admin_ip']='';
                return 0;
        }
}


判断了$_SESSION['login_in']是否等于1并且存在$_SESSION['admin'],并且当前时间没有比$_SESSION['login_time']多出一个小时以上

time()得到是当前时间的unix时间时间戳,所以直接把$_SESSION[login_time]伪造的大一点就可以了
覆盖好$_SESSION 直接访问后台地址,就绕过密码验证,进入后台了

2.3、覆盖原本不可控的全局变量注入恶意数据
对不可控的变量,一般系统对过滤的比较少,不过利用这个全局变量覆盖漏洞覆盖原本不可控的变量的,由于系统对这些变量过滤的少,造成了很大的危害
xss

[/size][/color]
[size=2][color=#000000]elseif($action=='add'){
[/color][/size][size=2][color=#000000]        //是否开启留言本
        $is_use=$mysql->get_row("select is_book from ".DB_PRE."book_info where id=1");
        if(!$is_use){die("<script type=\"text/javascript\">alert('".$language['book_msg1']."');history.go(-1);</script>");}
        $book_code=$_POST['book_code'];
        if($book_code!=$_SESSION['code']){die("<script type=\"text/javascript\">alert('{$language['member_msg2']}');history.go(-1);</script>");}
        $book_name=fl_html($_POST['book_name']);
        $book_title=fl_html($_POST['book_title']);
        $mail=fl_html($_POST['mail']);
        $book_type=intval($_POST['book_type']);
        $book_content=fl_html($_POST['book_content']);
        $pr_id=intval($_POST['pr_id']);
        if(empty($book_title)){die("<script type=\"text/javascript\">alert('".$language['book_msg2']."');history.go(-1);</script>");}
        if(empty($book_content)){die("<script type=\"text/javascript\">alert('".$language['book_msg3']."');history.go(-1);</script>");}
        $book_name=empty($book_name)?(empty($_SESSION['member_user'])?'游客':$_SESSION['member_user']):cn_substr($book_name,50);
        $book_title=$book_title;
        $book_content=$book_content;
        $addtime=time();
        //是否开启审核
        $is_verify=$mysql->get_row("select book_verify from ".DB_PRE."book_info where id=1");
        $verify=($is_verify)?0:1;
        $sql="insert into ".DB_PRE."book (book_name,book_title,book_content,mail,book_type,pr_id,addtime,verify,lang) values ('{$book_name}','{$book_title}','{$book_content}','{$mail}',{$book_type},{$pr_id},'{$addtime}',{$verify},'{$lang}')";
        $mysql->query($sql);

 

      $book_name=fl_html($_POST['book_name']);
      $book_name=empty($book_name)?(empty($_SESSION['member_user'])?'游客'_SESSION['member_user']):cn_substr($book_name,50);
$book_name从$_POST中提取,由于$_POST我们可控,直接让他为空,他的值就是$_SESSION['member_user'],而系统没有对$_SESSION的数据进行过滤,只在全局文件开头做了addslashes,所以我们可以直接插入xss代码,出库的时候这系统也没有进行过滤,所以造成了存储型xss

sql注入攻击
同样是因为覆盖原本不可控的数据造成的,造成了这处系统存在多处注入,本来这套系统过滤的还不错,偏偏因为这个全局变量覆盖,造成了各种各样的漏洞
比如这一处

elseif($action=='info'){
        $url=$language['member_msg28'];
        $tpl->assign('position',get_dy_position($url));//位置
        if(empty($_SESSION['member_user'])||empty($_SESSION['member_id'])||empty($_SESSION['member_login'])){die('<script type="text/javascript">location.href=\'?action=login&lang='.$lang.'\';</script>');}
        $sql="select*from ".DB_PRE."member where id=".$_SESSION['member_id'];
        $rel=$GLOBALS['mysql']->fetch_asc($sql);

 

由于可以伪造$_SESSION,所以这就变成了一处很明显的注入了

三:总结
原本这套系统的安全性不错,过滤的很好,但是偏偏因为在做伪全局变量这里出现全局变量覆盖漏洞,导致出现了各种各样的漏洞,一套系统如果出现了在做伪全局机制的时候没有做好,导致全局变量覆盖,会出现各种各样的漏洞,以上是我以前在审计某套系统的时候发现的,如果出现这样的全局变量覆盖,根据具体的代码,会出现各种各样的漏洞,现在很多系统的伪全局机制代码都会验证变量名是不是_开头的,如果是的话,就不覆盖,防止这些$_GET,$_POST,$_COOKIE,$_SERVER,$_SESSSION,$_FILE,$_SESSION被覆盖了。
比如这一段

<?php
foreach(array("_GET","_POST","_COOKIE") as $_R)
{
        foreach ($_R as $key => $value)
        {
                if($key[0]!="_") $key=$value;
        }
}
echo $a;
echo "<br>";
echo $_a;
?>


这样就覆盖不了_开头的了

<无标签>
举报
i春秋学院
发帖于9个月前 0回/102阅
顶部