您的位置:首页 > 编程语言 > PHP开发

PHP审计之WeEngine审计

2021-10-09 22:36 1931 查看

PHP审计之WeEngine审计

前言

审计该CMS加深一下对于MVC架构的php审计流程

梳理路由

打开代码看到index.php文件

if($_W['os'] == 'mobile' && (!empty($_GPC['i']) || !empty($_SERVER['QUERY_STRING']))) {
header('Location: ./app/index.php?' . $_SERVER['QUERY_STRING']);
} else {
header('Location: ./web/index.php?' . $_SERVER['QUERY_STRING']);
}

web端会跳转到

/web/index.php
,来看到
web/index.php

if (($_W['setting']['copyright']['status'] == 1) && empty($_W['isfounder']) && $controller != 'cloud' && $controller != 'utility' && $controller != 'account') {
$_W['siteclose'] = true;
if ($controller == 'account' && $action == 'welcome') {
template('account/welcome');
exit;
}
if ($controller == 'user' && $action == 'login') {
if (checksubmit()) {
require _forward($controller, $action);
}
template('user/login');
exit;
}
isetcookie('__session', '', -10000);
message('站点已关闭,关闭原因:' . $_W['setting']['copyright']['reason'], url('account/welcome'), 'info');
}

这里

$controller
$action
接收是从
bootstrap.inc.php

$controller = $_GPC['c'];
$action = $_GPC['a'];
$do = $_GPC['do'];

上面接收

$controller
$action
account
welcome

调用

template('account/welcome');

function template($filename, $flag = TEMPLATE_DISPLAY) {
global $_W;
$source = IA_ROOT . "/web/themes/{$_W['template']}/{$filename}.html";
$compile = IA_ROOT . "/data/tpl/web/{$_W['template']}/{$filename}.tpl.php";
if(!is_file($source)) {
$source = IA_ROOT . "/web/themes/default/{$filename}.html";
$compile = IA_ROOT . "/data/tpl/web/default/{$filename}.tpl.php";
}
...

这段代码实际上就是加载一个模板渲染。

继续往下看

$controllers = array();
$handle = opendir(IA_ROOT . '/web/source/');
if(!empty($handle)) {
while($dir = readdir($handle)) {
if($dir != '.' && $dir != '..') {
$controllers[] = $dir;
}
}
}
if(!in_array($controller, $controllers)) {
$controller = 'account';
}
$init = IA_ROOT . "/web/source/{$controller}/__init.php";
if(is_file($init)) {
require $init;
}

$actions = array();
$handle = opendir(IA_ROOT . '/web/source/' . $controller);
if(!empty($handle)) {
while($dir = readdir($handle)) {
if($dir != '.' && $dir != '..' && strexists($dir, '.ctrl.php')) {
$dir = str_replace('.ctrl.php', '', $dir);
$actions[] = $dir;
}
}
}
if(empty($actions)) {
header('location: ?refresh');
}
if(!in_array($action, $actions)) {
$action = $acl[$controller]['default'];
}
if(!in_array($action, $actions)) {
$action = $actions[0];
}

遍历读取

/web/source/
,所有内容。

遍历读取

/web/source/' . $controller
,并且把内容中的
.ctrl.php
去掉。

if(is_array($acl[$controller]['direct']) && in_array($action, $acl[$controller]['direct'])) {
require _forward($controller, $action);
exit;

判断是否为数组并且判断

$acl[$controller]['direct']
,并且查看
$action
是否在
$acl
截取对应
$controller
direct

逻辑其实就是

$acl
中定义了大量的数组,如

'account' => array(
'default' => 'welcome',
'direct' => array(
'welcome',
'auth'
)

$controller=account

direct=array('welcome','auth')

direct这个数组对应的是account下面的路由

访问welcome的路由的访问策略即

/web/index.php?c=account&a=welcome

漏洞审计

定位到漏洞位置

web/source/site/category.ctrl.php

定位到176行

if (!empty($navs)) {
foreach ($navs as $row) {
file_delete($row['icon']);
}
pdo_query("DELETE FROM ".tablename('site_nav')." WHERE id IN (".implode(',', array_keys($navs)).")");
}

file_delete($row['icon']);
,这里的
$row['icon']
是通过遍历
$navs

$navs
是通过一下这个sql语句查询得来的

$navs = pdo_fetchall("SELECT icon, id FROM ".tablename('site_nav')." WHERE id IN (SELECT nid FROM ".tablename('site_category')." WHERE id = {$id} OR parentid = '$id')", array(), 'id');

找看数据库中的这两个字段是否可控

site_nav数据库表中对应的数据是

$nav
变量内容,发现
$nav['icon']
变量是从
$_GPC['iconfile']
来的,即参数可控。这里的
$nav['icon']
变量,其实就是我们文章开头分析的传入
file_delete
函数的参数

if(!empty($nav_exist)) {
pdo_update('site_nav', $nav, array('id' => $category['nid'], 'uniacid' => $_W['uniacid']));
} else {
pdo_insert('site_nav', $nav);

这里需要先把文件名插入到数据库中,然后调用该功能将文件上传,代码会从数据库从查找该文件名,然后删除对应文件。

参考

https://github.com/hongriSec/PHP-Audit-Labs/tree/master/Part1/Day6/files

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: