آسیب پذیری بحرانی wp2shell در هسته WordPress
آسیب پذیری wp2shell در هسته WordPress بدون نیاز به ورود، زنجیره SQL Injection و REST API را به اجرای کد از راه دور روی سرور تبدیل می کند.
پژوهشگران Searchlight Cyber در ۱۸ ژوئیه ۲۰۲۶ جزئیات یک آسیب پذیری خطرناک در هسته WordPress را منتشر کردند که wp2shell نام گرفته است. این نقص به مهاجم ناشناس اجازه می دهد بدون داشتن حساب کاربری، نصب افزونه مخرب یا دسترسی قبلی، یک درخواست HTTP را به اجرای کد از راه دور یا Remote Code Execution روی سرور تبدیل کند. اهمیت رخداد در این است که سطح حمله به افزونه یا قالب خاصی محدود نیست و نصب استاندارد WordPress نیز می تواند در معرض خطر باشد.
نسخه اولیه هشدار و به روز رسانی های امنیتی در ۱۷ ژوئیه منتشر شدند، اما جزئیات فنی، شناسه آسیب پذیری، دامنه نسخه های متاثر و وجود نمونه عملی بهره برداری در ۱۸ ژوئیه روشن تر شد. آسیب پذیری اصلی با شناسه CVE-2026-63030 ثبت شده است. ارزیابی GitHub آن را بحرانی توصیف کرده، هرچند امتیاز اولیه CVSS برابر با ۷.۵ گزارش شده است. تفاوت میان برچسب بحرانی و امتیاز عددی به این معنا نیست که خطر ناچیز است؛ امکان اجرای کد بدون احراز هویت روی یک نصب پیش فرض، از نظر عملی یک سناریوی نفوذ کامل محسوب می شود.
پژوهش اولیه Searchlight Cyber تایید می کند که حمله پیش شرط خاصی ندارد و یک کاربر ناشناس می تواند نصب استاندارد WordPress را هدف قرار دهد. تحلیل های مستقل Rapid7 و Aikido نیز وجود زنجیره آسیب پذیری و نسخه های اصلاح شده را تایید کرده اند.
سازوکار فنی حمله wp2shell
مرحله اول: سردرگمی مسیر در REST API
نقطه ورود حمله به مسیر دسته ای REST API با آدرس /wp-json/batch/v1 مربوط است. Batch Route به مشتری اجازه می دهد چند عملیات API را در قالب یک درخواست مدیریت کند. نقص موجود در پردازش این مسیر می تواند باعث شود WordPress وضعیت، زمینه یا محدودیت امنیتی درخواست را به شکل نادرست تفسیر کند.
این بخش از زنجیره با عنوان سردرگمی مسیر یا Route Confusion شناخته می شود. مهاجم از تفاوت میان مسیری که لایه مسیریابی بررسی می کند و عملیاتی که در نهایت اجرا می شود، بهره می برد. چنین اختلافی می تواند کنترل های احراز هویت و اعتبارسنجی را بی اثر کند.
مرحله دوم: تزریق SQL
پس از عبور از مرحله نخست، ورودی کنترل شده مهاجم به یک عملیات پایگاه داده می رسد که در برابر تزریق SQL یا SQL Injection آسیب پذیر است. در این وضعیت، داده ورودی به جای آنکه صرفا یک مقدار عادی تلقی شود، می تواند ساختار فرمان پایگاه داده را تغییر دهد.
نسخه های WordPress 6.8.0 تا 6.8.5 فقط در برابر بخش SQL Injection این نقص آسیب پذیر گزارش شده اند. این شاخه با WordPress 6.8.6 اصلاح شده است. وجود SQL Injection به تنهایی نیز می تواند محرمانگی و یکپارچگی داده ها را تهدید کند، اما تمام نسخه های این شاخه لزوما در برابر زنجیره کامل wp2shell و اجرای کد قرار ندارند.
مرحله سوم: تبدیل تزریق به اجرای کد
در نسخه های جدیدتر، مهاجم می تواند Route Confusion و SQL Injection را زنجیره کند و از دستکاری داده یا وضعیت داخلی به اجرای کد PHP روی سرور برسد. اجرای کد در بستر فرایند وب می تواند به ایجاد حساب مدیر، نصب در پشتی، تغییر فایل ها، سرقت اطلاعات پایگاه داده یا حرکت به سمت دیگر منابع سرور منجر شود.
نسخه های متاثر از زنجیره کامل عبارتند از:
- WordPress 6.9.0 تا 6.9.4؛ اصلاح شده در نسخه 6.9.5
- WordPress 7.0.0 تا 7.0.1؛ اصلاح شده در نسخه 7.0.2
- WordPress 7.1 Beta؛ اصلاح شده در 7.1 Beta 2
نسخه های پیش از 6.8 در برابر این دو نقص مشخص آسیب پذیر گزارش نشده اند، اما قدیمی ماندن روی آنها راهکار امنیتی قابل قبولی نیست؛ زیرا ممکن است آسیب پذیری های شناخته شده دیگری داشته باشند.
دامنه خطر و پیامدهای واقعی
یک سایت آسیب پذیر صرفا با خطر تغییر صفحه اصلی مواجه نیست. WordPress معمولا به پایگاه داده حاوی حساب ها، ایمیل کاربران، داده های فروشگاه، توکن ها و تنظیمات حساس متصل است. فایل wp-config.php نیز اطلاعات اتصال به پایگاه داده و کلیدهای رمزنگاری را در اختیار برنامه قرار می دهد. در نتیجه، اجرای کد می تواند دامنه نفوذ را از یک برنامه وب به حساب میزبانی و منابع مجاور گسترش دهد.
در محیط Shared Hosting، تنظیمات جداسازی ضعیف ممکن است ریسک دسترسی جانبی به سایت های دیگر همان حساب را افزایش دهد. در سرور اختصاصی یا VPS نیز اجرای WordPress با مجوزهای بیش از حد می تواند مهاجم را به فایل های پشتیبان، وظایف زمان بندی شده و اسرار برنامه های دیگر نزدیک کند.
انتشار عمومی نمونه عملی بهره برداری، فاصله میان افشای آسیب پذیری و آغاز اسکن گسترده اینترنت را کاهش می دهد. هنوز نباید بدون سند ادعا کرد که یک عملیات جهانی تاییدشده در جریان است، اما وجود کد عمومی، سطح حمله وسیع و عدم نیاز به احراز هویت، اولویت اصلاح را به سطح اضطراری می رساند.
اقدامات فوری برای مدیران WordPress
نخست نسخه فعال را از پیشخوان، ابزار WP-CLI یا سامانه مدیریت مرکزی بررسی کنید. به فعال بودن Auto Update اعتماد مطلق نداشته باشید؛ نسخه نصب شده باید به صورت مستقیم تایید شود.
شاخه 7.0 باید حداقل به 7.0.2، شاخه 6.9 به 6.9.5 و شاخه 6.8 به 6.8.6 ارتقا پیدا کند. برای سامانه های عملیاتی، ابتدا یک نسخه پشتیبان قابل بازیابی تهیه کنید، سپس به روز رسانی را اجرا و عملکرد قالب، افزونه ها، REST API و فرایندهای پرداخت را آزمایش کنید.
اگر نصب فوری Patch ممکن نیست، دسترسی ناشناس به مسیرهای /wp-json/batch/v1 و ?rest_route=/batch/v1 را موقتا در WAF یا Reverse Proxy محدود کنید. این اقدام ممکن است برخی یکپارچه سازی های قانونی REST API را مختل کند و جایگزین Patch نیست.
تیم دفاعی باید گزارش های وب مربوط به درخواست های غیرعادی این مسیر، خطاهای SQL، ایجاد حساب مدیر، تغییر فایل های PHP، افزونه های ناشناس و فرایندهای جدید سرور را بررسی کند. مقایسه Hash فایل های هسته با بسته رسمی WordPress و بررسی پوشه های wp-content/uploads و wp-content/mu-plugins نیز ضروری است.
در صورت مشاهده نشانه نفوذ، صرفا به روز رسانی کافی نیست. سایت باید از شبکه عمومی جدا شود، Snapshot و شواهد ثبت شوند، رمزهای پایگاه داده و پنل میزبانی تغییر کنند، کلیدهای امنیتی WordPress بازتولید شوند و نشست های فعال کاربران خاتمه پیدا کنند.
بهترین روش های کاهش ریسک
کمینه سازی مجوزهای کاربر پایگاه داده، جلوگیری از اجرای PHP در پوشه Upload، محدود کردن دسترسی مدیریتی، استفاده از File Integrity Monitoring و نگهداری نسخه پشتیبان خارج از سرور، دامنه خسارت را کاهش می دهد. WAF یک لایه دفاعی مفید است، اما نباید به عنوان جایگزین اصلاح هسته در نظر گرفته شود.
موجودی دقیق سایت ها نیز اهمیت دارد. سازمانی که نمی داند چند نصب WordPress، چه نسخه هایی و تحت مالکیت چه تیم هایی دارد، نمی تواند Patch Management موثری اجرا کند. در محیط های بزرگ، نسخه WordPress باید در Asset Inventory و سامانه Vulnerability Management ثبت شود.
جلوگیری از اجرای فایل PHP مخرب در مسیرهای غیرمجاز وردپرس
علاوه بر Patch کردن WordPress و محدود کردن Route آسیب پذیر، بهتر است اجرای مستقیم فایل های PHP در مسیرهایی که اصولا نباید محل اجرای اسکریپت باشند نیز محدود شود.
این اقدام اهمیت زیادی دارد؛ زیرا مهاجم پس از به دست آوردن امکان Upload یا ایجاد فایل ممکن است یک Web Shell یا Backdoor با پسوند .php در مسیرهایی مانند wp-content/uploads قرار دهد و سپس آن را مستقیما از طریق وب اجرا کند.
برای Apache می توان Ruleهای امنیتی زیر را در فایل .htaccess و خارج از بخش خودکار WordPress قرار داد:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/wp-content/uploads/.*\.php$ [NC]
RewriteRule ^ - [F,L]
RewriteCond %{REQUEST_METHOD} POST [NC]
RewriteCond %{REQUEST_URI} ^/wp-content/(plugins|themes)/.*\.php$ [NC]
RewriteRule ^ - [F,L]
RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
RewriteRule ^wp-includes/js/tinymce/langs/.+\.php$ - [F,L]
RewriteRule ^wp-includes/theme-compat/ - [F,L]
</IfModule>
مهم ترین بخش این تنظیمات، جلوگیری کامل از اجرای فایل PHP داخل مسیر زیر است:
wp-content/uploads
پوشه Uploads باید محل نگهداری فایل هایی مانند تصویر، ویدیو، PDF و سایر Mediaها باشد و در حالت عادی نباید فایل PHP از آن اجرا شود. در نتیجه اگر مهاجم بتواند یک فایل مخرب مانند:
wp-content/uploads/shell.php
را روی سرور قرار دهد، درخواست مستقیم به آن با پاسخ 403 Forbidden مسدود خواهد شد.
محدود کردن درخواست های POST مستقیم به فایل های PHP داخل Plugin و Theme نیز می تواند سطح حمله را کاهش دهد و مانع استفاده مستقیم از برخی فایل های PHP به عنوان Endpoint شود.
Ruleهای مربوط به wp-includes نیز دسترسی مستقیم به بخش هایی از فایل های داخلی WordPress را محدود می کنند که معمولا باید از طریق خود WordPress اجرا شوند، نه مستقیما توسط کاربر اینترنت.
این تنظیمات یک لایه Defense in Depth محسوب می شوند. یعنی حتی اگر مهاجم در مرحله دیگری موفق به ایجاد یا Upload فایل مخرب شود، اجرای آن از طریق وب دشوارتر یا غیرممکن خواهد شد.
با این حال این روش جایگزین Patch امنیتی نیست. ترتیب صحیح اقدامات دفاعی به شکل زیر است:
Security Patch → محدود کردن Route آسیب پذیر → جلوگیری از اجرای PHP در مسیرهای غیرمجاز → File Integrity Monitoring → بررسی Logها و نشانه های نفوذ
Ruleهای امنیتی سفارشی نیز بهتر است خارج از محدوده زیر قرار داده شوند:
# BEGIN WordPress
# END WordPress
زیرا WordPress ممکن است محتوای این محدوده را هنگام تغییر Permalink یا تنظیمات دیگر بازنویسی کند.
چگونه دسترسی ناشناس به /wp-json/batch/v1 را مسدود کنیم؟
WordPress به صورت داخلی Route با نام /batch/v1 دارد و این Endpoint درخواست های POST دسته ای REST API را پردازش می کند.
برای یک اقدام موقت دفاعی می توان دسترسی کاربران ناشناس به این Route را مسدود کرد، بدون اینکه کل WordPress REST API غیرفعال شود.
بهترین روش برای این کار استفاده از یک MU Plugin کوچک است.
فایل زیر را ایجاد کنید:
wp-content/mu-plugins/abdal-block-anonymous-batch-rest.php
اگر پوشه mu-plugins وجود ندارد، ابتدا آن را ایجاد کنید.
<?php
/*
-------------------------------------------------------------------
Programmer : Ebrahim Shafiei (EbraSha)
Email : [email protected]
-------------------------------------------------------------------
*/
add_filter(
'rest_pre_dispatch',
function ( $result, $server, $request ) {
if ( null !== $result ) {
return $result;
}
$route = untrailingslashit( $request->get_route() );
if (
'/batch/v1' === $route &&
0 === get_current_user_id()
) {
return new WP_Error(
'rest_batch_anonymous_blocked',
'Anonymous access to this REST route is disabled.',
array(
'status' => 403,
)
);
}
return $result;
},
10,
3
);
Hook رسمی rest_pre_dispatch قبل از Dispatch شدن درخواست REST اجرا می شود و اجازه می دهد درخواست قبل از رسیدن به Endpoint متوقف شود.
این روش هر دو شکل رایج دسترسی REST API را پوشش می دهد:
/wp-json/batch/v1
و:
/?rest_route=/batch/v1
زیرا WordPress در هر دو حالت Route نهایی را به REST Server منتقل می کند. استفاده از پارامتر rest_route نیز روش رسمی WordPress برای سایت هایی است که Pretty Permalinks ندارند.
این کد فقط کاربران ناشناس را مسدود می کند و درخواست هایی که WordPress آنها را به یک User معتبر نسبت داده باشد همچنان قابل پردازش هستند.
این محدودیت فقط یک راهحل موقت برای کاهش خطر است و جایگزین نصب Patch امنیتی یا بهروزرسانی اصلی نمیشود. همچنین اگر سایت شما یا یکی از سرویسهای متصل به آن از درخواستهای گروهی بدون ورود به حساب کاربری استفاده میکند، قبل از فعال کردن این محدودیت باید بررسی کنید که آن سرویس همچنان درست کار میکند.
کدام دسترسی های کاربر پایگاه داده WordPress را باید محدود کرد؟
بهتر است برای هر نصب WordPress یک Database و یک Database User اختصاصی ایجاد شود و دسترسی آن User فقط به Database مربوط به همان سایت محدود باشد.
مرحله اول ایجاد Database User اختصاصی برای WordPress
در phpMyAdmin ابتدا وارد بخش:
User accounts → Add user account
شوید و یک User جدید برای سایت WordPress ایجاد کنید.
در این مرحله موارد اصلی را مشخص کنید:
- User name: یک نام اختصاصی برای کاربر WordPress
- Host name: در بیشتر سرورها
localhost - Password: یک رمز عبور قوی و تصادفی
- Authentication plugin: تنظیم پیش فرض و سازگار با MariaDB/MySQL سرور
در این صفحه هیچ کدام از Global Privileges را فعال نکنید و گزینه Check all نیز نباید انتخاب شود.
همچنین در بخش Database for user account فعلا گزینه های زیر را فعال نکنید:
Create database with same name and grant all privileges
Grant all privileges on wildcard name
دلیل این کار این است که Database User مربوط به WordPress نباید در سطح Global به کل MariaDB/MySQL یا Databaseهای دیگر سرور دسترسی داشته باشد.

در این مرحله فقط User ایجاد می شود. در مرحله بعد دسترسی این User را به صورت Database-specific فقط روی Database مربوط به همان سایت WordPress تعریف می کنیم.
مرحله دوم: ورود به تنظیمات دسترسی Database User

پس از ایجاد کاربر، وارد بخش:
User accounts
شوید.
در لیست کاربران، Database User اختصاصی WordPress را پیدا کنید. در ستون Global privileges بهتر است مقدار:
USAGE
نمایش داده شود. این یعنی کاربر هنوز هیچ Global Privilege روی کل MariaDB/MySQL ندارد.
همچنین مقدار ستون Grant باید:
No
باشد.
سپس در مقابل همان User روی گزینه:
Edit privileges
کلیک کنید و بر روی دکمه DataBase کلیک کنید

در مرحله بعد دسترسی این User را فقط به Database مربوط به همان سایت WordPress اختصاص می دهیم.
مرحله سوم: انتخاب Database و اعطای دسترسی اختصاصی
در صفحه Edit privileges وارد تب:
Database
شوید.
در بخش:
Add privileges on the following database(s)
Database مربوط به همان سایت WordPress را انتخاب کنید و سپس روی:
Go
کلیک کنید.

در صفحه بعد، بخش Database-specific privileges نمایش داده می شود. در اینجا گزینه:
Check all
را فعال کنید تا تمام Privilegeهای مورد نیاز فقط روی همین Database به User اختصاص داده شوند.

این دسترسی ها شامل مواردی مانند:
SELECTINSERTUPDATEDELETECREATEALTERINDEXDROPCREATE TEMPORARY TABLESSHOW VIEWCREATE ROUTINEALTER ROUTINEEXECUTECREATE VIEWEVENTTRIGGERLOCK TABLESREFERENCES
است.
در پایان روی:
Go
کلیک کنید تا دسترسی ها ذخیره شوند.
نکته مهم این است که این Privilegeها فقط به Database انتخاب شده اختصاص داده می شوند و User همچنان هیچ Global Privilege روی سایر Databaseها یا کل MariaDB/MySQL Server ندارد.
دیدگاه های مربوط به این مقاله (برای ارسال دیدگاه در سایت حتما باید عضو باشید و پروفایل کاربری شما تکمیل شده باشد)
تعداد 4 دیدگاه ثبت شده
سلام کدام دسترسی های کاربر پایگاه داده باید محدود شود که سایت دچار مشکل نشود؟
با سلام به مقاله اضافه شد .
سلام ممکنه افزونه و کد لازم برای بستن دسترسی ناشناس به مسیرهای اعلامی فوق را در ادامه یا مقاله ای جدید ارسال کنید؟
با سلام به مقاله اضافه شد .