欢迎光临
我们一直在努力

zabbix高危SQL注入漏洞分析

0x01 漏洞概述

zabbix是一个开源的企业级性能监控解决方案。近日,zabbix的jsrpc的profileIdx2参数存在insert方式的SQL注入漏洞,攻击者无需授权登陆即可登陆zabbix管理系统,也可通过script等功能轻易直接获取zabbix服务器的操作系统权限。 但是无需登录注入这里有个前提,就是zabbix开启了guest权限。而在zabbix中,guest的默认密码为空。需要有这个条件的支持才可以进行无权限注入。

详情:《漏洞预警:Zabbix高危SQL注入漏洞,可获取系统权限》

0x02 影响程度

  • 攻击成本:低
  • 危害程度:高
  • 是否登陆:不需要
  • 影响版本:2.2.x,3.0.0-3.0.3

0x03 漏洞测试

在zabbix的地址后面添加:

  • 利用方式一

1-55 zabbix高危SQL注入漏洞分析

如果出现下列代码则证明漏洞存在

1-55 zabbix高危SQL注入漏洞分析

  • 利用方式二

1-55 zabbix高危SQL注入漏洞分析

如果出现下列代码则证明漏洞存在

1-55 zabbix高危SQL注入漏洞分析

0x04 实战测试

测试的一个Japan站

1-55 zabbix高危SQL注入漏洞分析

1-55 zabbix高危SQL注入漏洞分析

可获得最高权限

0x05 代码分析

zabbix 2.2.14

  • 首先从poc中的jsrpc.php文件入手,找到profileIdx2参数
case 'screen.get':
 $options = array(
 'pageFile' => !empty($data['pageFile']) ? $data['pageFile'] : null,
 'mode' => !empty($data['mode']) ? $data['mode'] : null,
 'timestamp' => !empty($data['timestamp']) ? $data['timestamp'] : time(),
 'resourcetype' => !empty($data['resourcetype']) ? $data['resourcetype'] : null,
 'screenitemid' => !empty($data['screenitemid']) ? $data['screenitemid'] : null,
 'groupid' => !empty($data['groupid']) ? $data['groupid'] : null,
 'hostid' => !empty($data['hostid']) ? $data['hostid'] : null,
 'period' => !empty($data['period']) ? $data['period'] : null,
 'stime' => !empty($data['stime']) ? $data['stime'] : null,
 'profileIdx' => !empty($data['profileIdx']) ? $data['profileIdx'] : null,
 'profileIdx2' => !empty($data['profileIdx2']) ? $data['profileIdx2'] : null,
 'updateProfile' => isset($data['updateProfile']) ? $data['updateProfile'] : null
 );
 if ($options['resourcetype'] == SCREEN_RESOURCE_HISTORY) {
 $options['itemids'] = !empty($data['itemids']) ? $data['itemids'] : null;
 $options['action'] = !empty($data['action']) ? $data['action'] : null;
 $options['filter'] = !empty($data['filter']) ? $data['filter'] : null;
 $options['filter_task'] = !empty($data['filter_task']) ? $data['filter_task'] : null;
 $options['mark_color'] = !empty($data['mark_color']) ? $data['mark_color'] : null;
 }
 elseif ($options['resourcetype'] == SCREEN_RESOURCE_CHART) {
 $options['graphid'] = !empty($data['graphid']) ? $data['graphid'] : null;
 $options['profileIdx2'] = $options['graphid'];
 }

$screenBase = CScreenBuilder::getScreen($options);
 if (!empty($screenBase)) {
 $screen = $screenBase->get();
 }

if (!empty($screen)) {
 if ($options['mode'] == SCREEN_MODE_JS) {
 $result = $screen;
 }
 else {
 if (is_object($screen)) {
 $result = $screen->toString();
 }
 }
 }
 else {
 $result = '';
 }
 break;

省略部分代码

require_once dirname(__FILE__).'/include/page_footer.php';

在看这段代码的时候各种跑偏,一度追着

$screenBase = CScreenBuilder::getScreen($options);
 if (!empty($screenBase)) {
 $screen = $screenBase->get();
 }

这几句代码死磕,看到zabbix-2.2.14/frontends/php/include/classes/screens/CScreenBuilder.php,在public static function getScreen(array $options = array())函数中没有找到可以造成漏洞的交互点,太菜了!!!

然后去请教表哥,表哥提示问题出现在flush中
根据表哥的提示,在page_footer.php中发现CProfile类的flush方法

// last page
if (!defined('ZBX_PAGE_NO_MENU') && $page['file'] != 'profile.php') {
 CProfile::update('web.paging.lastpage', $page['file'], PROFILE_TYPE_STR);
}

CProfile::flush();

// end transactions if they have not been closed already
if (isset($DB) && isset($DB['TRANSACTIONS']) && $DB['TRANSACTIONS'] != 0) {
 error(_('Transaction has not been closed. Aborting...'));
 DBend(false);
}

在profiles.inc.php中找到了flush函数

public static function flush() {
 // if not initialised, no changes were made
 if (is_null(self::$profiles)) {
 return true;
 }

if (self::$userDetails['userid'] <= 0) {
 return null;
 }

if (!empty(self::$insert) || !empty(self::$update)) {
 DBstart();
 foreach (self::$insert as $idx => $profile) {
 foreach ($profile as $idx2 => $data) {
 self::insertDB($idx, $data['value'], $data['type'], $idx2);
 }
 }

ksort(self::$update);
 foreach (self::$update as $idx => $profile) {
 ksort($profile);
 foreach ($profile as $idx2 => $data) {
 self::updateDB($idx, $data['value'], $data['type'], $idx2);
 }
 }
 DBend();
 }
 }

参数传入下面的insertDB函数,从而导致了注入的产生

private static function insertDB($idx, $value, $type, $idx2) {
 $value_type = self::getFieldByType($type);

$values = array(
 'profileid' => get_dbid('profiles', 'profileid'),
 'userid' => self::$userDetails['userid'],
 'idx' => zbx_dbstr($idx),
 $value_type => zbx_dbstr($value),
 'type' => $type,
 'idx2' => zbx_dbstr($idx2)
 );
 return DBexecute('INSERT INTO profiles ('.implode(', ', array_keys($values)).') VALUES ('.implode(', ', $values).')');
 }

0x06 漏洞修复

  • 版本升级
  • 打补丁
  • 关闭guest

0x07 后记

这里还有好多东西没有搞懂,毕竟太菜了

注:部分漏洞信息收集自网络

 

未经允许不得转载:杂术馆 » zabbix高危SQL注入漏洞分析
分享到: 更多 (0)