【读者投稿】PHP开源程序中常见的后台绕过方法总结

2017-09-12 00:00:00 spoock 信安之路

说明

最近审计了几个开源的PHP源程序,发现都存在后台程序绕过的问题,而且绕过的方式均不相同,写篇总结一下。初步地将绕过方式分为了三个层次: 1. 后台缺乏验证代码 2. 后台验证代码不严谨 3. 变量覆盖漏洞导致后台验证失效

以下就几个我审计过的PHP源程序进行说明。

后台缺乏验证

比如在axublog 1.0.2中后台存在一个验证管理员登录的函数chkadcookie()。但是在后台的ad/art.php中并没有chkadcookie(),因而就造成了越权访问。

这种漏洞的原理也比较简单,一般情况下是经验不足的开发者漏掉了验证函数,这种漏洞目前已经比较少了。

后台验证代码不严谨

这个漏洞的出现情况是最多的,出现的情况也是千奇百怪。

axublog后台验证函数绕过

验证方式

axublog中的后台验证函数是chkadcookie(),代码如下: 

function chkadcookie() {
    @$file = "../cache/txtchkad.txt";          //定义文件
    @$fp = fopen($file, "r");                  //以写入方式打开文件
    @$txtchkad = fread($fp, 4096);              //读取文件内容
    $txtchkad2 = str_replace(@$_COOKIE["chkad"], '', $txtchkad);
    if (@$_SESSION["chkad"] == '' && @$_COOKIE["chkad"] == '') {
        header("Content-type:text/html; charset=utf-8");
        echo '<div id=redmsg>请<a href="login.php">登录</a>。。。</div><script>tiao();</script>';
        exit;
    }
    if ($txtchkad == $txtchkad2) {
        header("Content-type:text/html; charset=utf-8");
        echo '<div id=redmsg>请<a href="login.php">登录</a>。。。</div><script>tiao();</script>';
        exit;
    }}// 记录当前登录的用户function loginpass($str) {
    $txtchkad = $_SERVER['HTTP_USER_AGENT'] . '_' . $_SERVER['REMOTE_ADDR'] . '_' . $date;
    $file = "../cache/txtchkad.txt";          //定义文件
    if (file_exists($file)) {
        $txt = file_get_contents($file);
        $txt = $txtchkad . "\r\n" . $txt;
    }
    file_put_contents($file, $txt);}  

分析代码发现非常有趣的问题:
1. txtchkad.txt文件中记录的是客户端的

$_SERVER['HTTP_USER_AGENT'] . '_' . $_SERVER['REMOTE_ADDR'] . '_' . $date

,其中只有$date我们是无法知道,而UA和REMOTE_ADDR都是客户端可控的。
2. 

$txtchkad2 = str_replace(@$_COOKIE["chkad"], '', $txtchkad);($txtchkad == $txtchkad2)

的验证逻辑是如果在COOKIE中出现了在txtchkad.txt中的值,那么就认为是登录的。这样的验证逻辑明显存在很大的问题。

问题很明显,既然我们知道了txtchkad.txt中的内容,同时COOKIE也是我们可控的,那么我们就可以绕过了。

绕过验证

只需要将COOKIE中的chkad设置为_就可以绕过后台的登录了。

zzcms的后台验证函数绕过

验证方式

zzcms中的后台验证代码如下:

if (isset($_SESSION["admin"]) && isset($_SESSION["pass"])) {
    $sql = "select * from zzcms_admin where admin='" . $_SESSION["admin"] . "'";
    $rs = query($sql) or showmsg('查寻管理员信息出错');
    $ok = is_array($row = fetch_array($rs));
    if ($ok) {
        if ($_SESSION["pass"] != $row['pass']) {
            showmsg('管理员密码不正确,你无权进入该页面', '/admin/login.php');
        }
    } else {
        showmsg('管理员已不存在,你无权进入该页面', '/admin/login.php');
    }} else {
    session_write_close();
    echo("<script>top.location.href = '/admin/login.php';</script>");}?>

可以发现如果SESSION中不存在adminpass就会跳转到登录代码,跳转代码是 

echo("<script>top.location.href = '/admin/login.php';</script>");

。通过前台的JS进行跳转,但是后面没有立即exit(),导致后面的代码仍然是可以执行的,所以这种验证方式也无用的。

绕过方式

绕过方式非常地简单,在浏览器段禁用JS代码就可以了。

变量覆盖漏洞导致后台验证失效

beescms的后台验证函数绕过

验证方式

检查登录的函数is_login()的代码为:

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 {
        return 0;
    }

正常情况下,如果用户无法控制SESSION中的值,上述代码是没有问题的。

但是后来分析发现,基本所有的文件都会引入includes/init.php文件,其中有代码:

session_start();$_COOKIE = fl_value($_COOKIE);$_GET = fl_value($_GET);@extract($_POST);@extract($_GET);@extract($_COOKIE);function fl_value($str) {
    if (empty($str)) {
        return;
    }
    return preg_replace('/select|insert | update | and | in | on | left | joins | delete |\%|\=|\/\*|\*|\.\.\/|\.\/| union | from | where | group | into |load_file|outfile/i', '', $str);}

上述的代码中并没有对$_POST使用fl_value()函数进行过滤,但又使用了extract()这样的函数,所以就可以通过发送POST参数覆盖掉SEESION中的值,从而绕过验证了。

绕过方式

绕过方式很简单,访问一个页面,发送POST请求如下:

index.php
POST:_SESSION[login_in]=1&_SESSION[admin]=1&_SESSION[login_time]=99999999999

此时就成功地创建了SESION变量,包括$SESSION[loginin]=1$_SESSION[admin]=1SESSION[logintime]=99999999999。 之后访问管理员页面,就可以成功地登录了。

总结

刚开始学习代码审计,发现这些问题都很有趣,于是总结了一下,当然后台绕过的方式估计还有其他的类型,也希望各位师傅们能够多多指教。