PHP开源程序中常见的后台绕过方法总结

说明

最近审计了几个开源的PHP源程序,发现都存在后台程序绕过的问题,而且绕过的方式均不相同,写篇总结一下。初步地将绕过方式分为了三个层次:

  1. 后台缺乏验证代码
  2. 后台验证代码不严谨
  3. 变量覆盖漏洞导致后台验证失效

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

后台缺乏验证

比如在axublog 1.0.2中后台存在一个验证管理员登录的函数chkadcookie()。但是在后台的ad/art.php中并没有chkadcookie(),因而就造成了越权访问。
这种漏洞的原理也比较简单,一般情况下是经验不足的开发者漏掉了验证函数,这种漏洞目前已经比较少了。

后台验证代码不严谨

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

axublog后台验证函数绕过

验证方式

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

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
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中的后台验证代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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()的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
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文件,其中有代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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请求如下:

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

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

总结

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