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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?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的代码是如下:

1
2
3
4
5
6
7
8
9
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

Comments

⬆︎TOP