呵呵,昨晚和初中同学叙旧,两个人无聊找了一款网页游戏BR大逃杀玩,今天把这个网页游戏下下来简单审计了一下源码。

<?php
error_reporting(E_ERROR | E_WARNING | E_PARSE);
set_magic_quotes_runtime(0);
//ini_set('date.timezone','Asia/Shanghai');
$now = time(); 
define('IN_GAME', TRUE);
define('GAME_ROOT', substr(dirname(__FILE__), 0, 0));
define('GAMENAME', 'bra');
if(PHP_VERSION < '4.3.0') {
    exit('PHP version must >= 4.3.0!');
}
require_once GAME_ROOT.'./include/global.func.php';
require_once GAME_ROOT.'./config.inc.php';

extract(gaddslashes($_COOKIE));
extract(gaddslashes($_POST));
extract(gaddslashes($_GET));

if($attackevasive) {
    include_once GAME_ROOT.'./include/security.inc.php';
}

if($gzipcompress && function_exists('ob_gzhandler') && CURSCRIPT != 'wap') {
    ob_start('ob_gzhandler');
} else {
    $gzipcompress = 0;
    ob_start();
}

require_once GAME_ROOT.'./include/db_'.$database.'.class.php';
$db = new dbstuff;
$db->connect($dbhost, $dbuser, $dbpw, $dbname, $pconnect);
unset($dbhost, $dbuser, $dbpw, $dbname, $pconnect);
$db->select_db($dbname);
require_once GAME_ROOT.'./gamedata/system.php';
if(!$username||!$password){
    gexit($_ERROR['login_info'],__file__,__line__);
}else{
    include_once GAME_ROOT.'./gamedata/system.php';

    if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
        $onlineip = getenv('HTTP_CLIENT_IP');
    } elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
        $onlineip = getenv('HTTP_X_FORWARDED_FOR');
    } elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
        $onlineip = getenv('REMOTE_ADDR');
    } elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
        $onlineip = $_SERVER['REMOTE_ADDR'];
    }

    $password = md5($password);
    $groupid = 1;
    $credits = 0;
    $gender = 0;
    $str = "SELECT * FROM {$tablepre}users WHERE username = '$username'";
    $result = $db->query("SELECT * FROM {$tablepre}users WHERE username = '$username'");
    if(!$db->num_rows($result)) {
        $groupid = 1;
        $str = "INSERT INTO {$tablepre}users (username,`password`,groupid,ip,credits,gender) VALUES ('$username', '$password', '$groupid', '$onlineip', '$credits', '$gender')";
        $db->query("INSERT INTO {$tablepre}users (username,`password`,groupid,ip,credits,gender) VALUES ('$username', '$password', '$groupid', '$onlineip', '$credits', '$gender')");
    } else {
        $userdata = $db->fetch_array($result);
        if($userdata['groupid'] <= 0){
            gexit($_ERROR['user_ban'],__file__,__line__);
        } elseif($userdata['password'] != $password) {
            gexit($_ERROR['login_check'],__file__,__line__);
        } else {

        }
    }
    gsetcookie('user',$username);
    gsetcookie('pass',$password);
}

Header("Location: index.php");
exit();

?>

以上这些是login.php的源码,程序员从15-17行进行了addslash()操作并且用了extract()函数解压出来,这两个函数都有相关的安全风险。
addslash()函数在数据库为gbk的条件下可以用宽字节注入,extract函数的话可以用数组进行变量覆盖(日常感谢黑哥等老一辈黑阔)

看了一下下面进行sql查询的地方,因为数据库设置的是utf8格式的,所以暂时先放弃了宽字节注入的想法。

接下来我发现下面的insert语句里面需要插入一个ip,根据以往的经验来看,php获取ip一共有3种方式,其中的2种方式都是有问题的。
使用X-Forward-For和HTTP_CLIENT_IP这两种都是客户端可以伪造的。
于是看一下ip是怎么取得的,获取ip的代码是如下:

    if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
        $onlineip = getenv('HTTP_CLIENT_IP');
    } elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
        $onlineip = getenv('HTTP_X_FORWARDED_FOR');
    } elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
        $onlineip = getenv('REMOTE_ADDR');
    } elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
        $onlineip = $_SERVER['REMOTE_ADDR'];
    }

个人觉得程序猿没有注意到获取顺序,应该是$_SERVER['REMOTE_ADDR']放在判断语句的第一个,不然就不会有下面的问题了。
上面那串代码获取了$onlineip,但要注意到$onlineip是从$_SERVER这个php的超全局变量获取的。程序开头只addslash了3个超全局变量,忽略了这个,所以下面insert语句是可以注入的。
所以接下来就可以用报错注入来注入了。
F93EDEF9-CC09-479E-81F9-B5F70267FC74.png
66FF604A-1512-40CD-8858-E74C5ECA32CD.png