مسحُ ملفّاتٍ نظيف ليس موقعًا نظيفًا. فالسكربتات المحقونة تسكن المحتوى في راحة: متنُ مقال، وأداةٌ جانبية، وصفُّ إعدادات، وخيارُ قالب. وإعادةُ تنصيب التطبيق تستبدل الملفّات وتترك كلَّ واحدةٍ من تلك حيث هي بالضبط.
ابحث عنها
SELECT * FROM wp_posts
WHERE post_content LIKE '%<script%'
OR post_content LIKE '%eval(%'
OR post_content LIKE '%base64_decode%'
LIMIT 50;
SELECT option_name, LEFT(option_value, 120) FROM wp_options
WHERE option_value LIKE '%<script%' LIMIT 50;
والفكرةُ نفسها تسري على أي مخطَّط: أعمدةُ النصّ التي يراها الزوّار، مع جدول الإعدادات. فالبحثُ عن وسم سكربت في محتوًى لا ينبغي أن يحويه أبدًا يجد معظمها.
أو ابحث في النسخة كلّها بدلًا من ذلك
أسرعُ من التخمين في الجداول، ويعمل على مخطَّطٍ لا تعرفه.
mysqldump -u user -p dbname > /tmp/scan.sql
grep -n -E '<script|eval\(|base64_decode|document\.write' /tmp/scan.sql | head -40
shred -u /tmp/scan.sql
نظّفها
- انسخ قاعدة البيانات أوّلًا — فأنت على وشك تشغيل جُمَل UPDATE على محتوًى حيّ.
- أصلِح صفًّا واحدًا باليد — وتأكّد من النصّ بالضبط، ومن أن حذفه يترك محتوًى سليمًا.
- ثم الباقي بنطاقٍ ضيّق —
UPDATE wp_posts SET post_content = REPLACE(post_content, '<script src="//bad.example"></script>', '') WHERE post_content LIKE '%bad.example%'; - وافحص العدد قبل وبعد — فـREPLACE يلمس صفوفًا أكثر ممّا وجد SELECT عندك يعني أن النمط أوسع من اللازم.
ولا تشغّل أبدًا REPLACE واسعًا على كل أعمدة النصّ دفعةً واحدة. فتلك أسرعُ طريقةٍ لتحويل اختراقٍ إلى فقدان بيانات، وتصير النسخةُ التي أخذتها قبل دقيقتين النسخةَ الوحيدة من محتواك.
ثم أغلِق الباب
المحتوى يُحقَن عبر شيء: إضافةٌ قديمة، أو كلمةُ مرور إدارةٍ مسروقة، أو مجلّدُ رفعٍ قابل للكتابة. وتنظيفُ الصفوف دون العثور على ذلك يعني أنها تعود في غضون أيّام. انظر تنظيف موقعٍ مخترَق كما ينبغي.
